I have an image (attached).
I want the image to be stretched out to cover the yellow area.
I am using c#, magick.net
What will be the best approach?
I propose the following approach:
read input image saving original size
remove the transparent* area using trim
stretch the (now smaller) image to the original size
*If the yellow area in your sample image is actually transparent you can leave fuzz = 0 in the following code, otherwise you'll have to adjust the value to be sure to remove all the unwanted area.
string srcImageFullPath = "c:\input.png";
int fuzz = 0;
string destImageFullPath = "c:\output.png";
// Read image from file
using (MagickImage image = new MagickImage(srcImageFullPath))
{
//save height/width of the original image
int height = image.Page.Height;
int width = image.Page.Width;
//set fuzz percentage
image.ColorFuzz = new ImageMagick.Percentage(fuzz);
//trim borders
image.Trim();
//resize image to original size
MagickGeometry size = new MagickGeometry(width, height);
size.IgnoreAspectRatio = true;
image.Resize(size);
// Save the result
image.Write(destImageFullPath);
}
In the following picture you can see the original image on the left, and the image after resizing on the right:
Notes
Trim removes any border that has the same color of the pixels in the corner of you image (see here for the details)
Since the yellow border in your sample image is not made of a single color you can use Fuzz to remove "similar" colors (more info here). As said before if your border is transparent just leave fuzz = 0
Related
I have an image loaded into a Bitmap in C# with a gradient background from a document i scanned in.
An example of it could be like the picture below:
My goal in C# is now to remove the background so that I have a solid white background. Now I myself can't seem to find a way to do this. Is there a way to achieve this in a way?
Thanks in advance.
Here is a version using LockBits.
The premise is if it's not black then change it to white.
It will be magnitudes faster the GetPixel and SetPixel
It works with the raw data in memory using pointers
iterates through every pixel
Checks the color and changes it to white if needed
Saves the image
Note : obviously this will destroy any antialiasing and smoothing, it will fail for certain image types, and other assorted issues.
using (var bmp = new Bitmap(#"D:\Test.png"))
{
var data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppPArgb);
var white = Color.White.ToArgb();
var black = Color.Black.ToArgb();
try
{
var length = (int*)data.Scan0 + bmp.Height * bmp.Width;
for (var p = (int*)data.Scan0; p < length; p++)
if (*p != black) *p = white;
}
finally
{
// unlock the bitmap
bmp.UnlockBits(data);
bmp.Save(#"D:\Output.Bmp", ImageFormat.Bmp);
}
}
Output
If you know the gradient colors (e.g. only part of RGB color responsible for red changes) or at least the color of text (e.g. if it is always black) then you can iterate through all of image's pixels and then:
Use GetPixel() to get pixel color.
Check if it is text (black).
If it is, then move to the next pixel.
If it isn't, then change color to white with SetPixel().
For gradient it should be enough. For more complex backgrounds it would need a more complex algorithm.
I want to draw a rectangle inside an image (imageToCrop), which is in a Canvas, and print that cropped rectangle beside the image.
Then I need to save it to a new file.
I draw a System.Windows.Shapes.Rectangle on my image and this work.
Here is my code to crop the rectangle and print it to another image (croppedImage) :
croppedImage.Width = selectionBox.Width;
croppedImage.Height = selectionBox.Height;
CroppedBitmap cb = new CroppedBitmap((BitmapSource)imageToCrop.Source, new Int32Rect(Convert.ToInt32(Canvas.GetLeft(selectionBox)), Convert.ToInt32(Canvas.GetTop(selectionBox)), Convert.ToInt32(selectionBox.Width), Convert.ToInt32(selectionBox.Height)));
croppedImage.Source = cb;
The problem is that I get in the other image a new image witch have the good sizes, Height and Width of the drawn rectangle, but it's an unyform color, not related to the drawn rectangle...
I don't understand why ?
Here's what I have:
var rand = new Random();
var files = Directory.GetFiles("C:/Projects/MOMENTUM/MOMENTUM/pics/", "*.jpg");
Image bgimage = new Bitmap(files[rand.Next(files.Length)]);
BackgroundImage = bgimage;
Rectangle UsedScreen = Screen.FromControl(this).Bounds;
if (UsedScreen.Height / UsedScreen.Width > bgimage.Height / bgimage.Width)
{
//SET IMAGE HEIGHT TO SCREEN HEIGHT
}
else
{
//SET IMAGE WIDTH TO SCREEN WIDTH
}
As you see, I first choose a random image from a specific folder and then set this as background image.
I want this application to run in full screen. However, if i set the bgimage ImageLayout property to Zoom, there will be this ugly borders and if I set it to stretch, it will look awful.
I want to achieve the following:
I get the current used screensize via screen bounds, and then adjust the image to fit the screen without being distorted.
Part of the image will be cut away but the main aim is, that the entire screen is always filled out by the image (See the comments in if). I don't know how to do this because if I try
bgimage.Height = UsedScreen.Height
I cant overwrite the image height.
Any ideas?
I am using this code to draw a scrollable panel on win form. The ImageBox is 512x512 and image I am using is 1024x768 (added as resource):
imageBox1.Image = Properties.Resources.test;
Unfortunately, it seems like image is scaled for some reasons - I cannot scroll to it's border. If I use 512x512 image, it doesn't fit the ImageBox, it seems cropped. Any ideas what is going on here?
using System;
using System.Drawing;
using System.Windows.Forms;
class ImageBox : Panel {
public ImageBox() {
this.AutoScroll = true;
this.DoubleBuffered = true;
}
private Image mImage;
public Image Image {
get { return mImage; }
set {
mImage = value;
if (mImage != null) this.AutoScrollMinSize = mImage.Size;
else this.AutoScrollMinSize = new Size(0, 0);
this.Invalidate();
}
}
protected override void OnPaint(PaintEventArgs e) {
e.Graphics.TranslateTransform(this.AutoScrollPosition.X, this.AutoScrollPosition.Y);
if (mImage != null) e.Graphics.DrawImage(mImage, 0, 0);
base.OnPaint(e);
}
}
It is an issue with the resolution of the image, it is less than the resolution of your display. Pretty unusual.
There is more than one workaround for this. #TaW's approach works but favors the monitor resolution. You'll get a sharper image but it will not be close to the image size as originally recorded. The other approach is to keep the physical size, like DrawImage() does, and adjust the scrollbars accordingly. Change the Image property setter to:
set {
mImage = value;
if (value == null) this.AutoScrollMinSize = new Size(0, 0);
else {
var size = value.Size;
using (var gr = this.CreateGraphics()) {
size.Width = (int)(size.Width * gr.DpiX / value.HorizontalResolution);
size.Height = (int)(size.Height * gr.DpiY / value.VerticalResolution);
}
this.AutoScrollMinSize = size;
}
this.Invalidate();
}
Picking the "right" approach is not so obvious, you probably ought to consider adding another property so you can change it as needed.
DrawImage has many variants and it is well worth checking them all out carefully. You have chosen the wrong one for your purpose. Look at the doc at MSDN:
Graphics.DrawImage Method (Image, Int32, Int32)
...
Draws the specified image, using its original physical size,
at the location specified by a coordinate pair.
At first glance this sounds good. 'Physical size' - isn't that pixels? But read on at MSDN:
Remarks
An Image stores a value for pixel width and a value for horizontal resolution
(dots per inch). The physical width, measured in inches, of an image is
the pixel width divided by the horizontal resolution. For example,
an image with a pixel width of 216 and a horizontal resolution of 72 dots
per inch has a physical width of 3 inches. Similar remarks apply to pixel
height and physical height.
The DrawImage method draws an image using its physical size, so the image will
have its correct size in inches regardless of the resolution (dots per inch)
of the display device. For example, suppose an image has a pixel width of 216
and a horizontal resolution of 72 dots per inch. If you call DrawImage to
draw that image on a device that has a resolution of 96 dots per inch,
the pixel width of the rendered image will be (216/72)*96 = 288.
Ouch, that's not about pixels after all! It is about displays and the resolution the image has embedded in it..This is good if you want to get the image e.g. printed right on all printers.
But you want the pixels of the image to match the pixels of the display. You could adapt the resolution of the image to your screen; but that wouldn't work for a different screen. So this DrawImage call will not work for you..
So you should, quite simply, use the number of pixels your image has and feed them into the right DrawImage call:
e.Graphics.DrawImage(mImage, 0, 0, mImage.Width, mImage.Height);
Now it will not distort the image but put one image pixel onto one screen pixel..
Edit: Note: I had misquoted MSDN in my OP; now the right (but wrong for your purpose) method call is quoted in the first part..
I'm trying to print image from Silverlight application. I have pretty good quality scans (TIFF) with resolution 1696x2200
When I print - I get PrintableArea from PrintDocument and it's 816x1056
What I do - I resize bitmap to Printable area (to fit document to page) and result I get is blurry image. I understand this is scaling problem (most likely), but how do I scale properly so it looks good? When I display document inside Image and just set image size - it looks good.
For resizing I'm using WriteableBitmapEx extensions and tried both types of resize (Nearest neighbor and bilinear)
Code:
var printDocument = new PrintDocument();
printDocument.PrintPage += (s, ea) =>
{
var printableArea = ea.PrintableArea;
var bitmap = this.currentPreviewPage.FullBitmap.Resize((int)printableArea.Width, (int)printableArea.Height, WriteableBitmapExtensions.Interpolation.Bilinear);
var image = new Image { Source = bitmap };
var canvas = new Canvas { Width = bitmap.PixelWidth, Height = bitmap.PixelHeight };
canvas.Children.Add(image);
ea.PageVisual = canvas;
ea.HasMorePages = false;
};
printDocument.PrintBitmap("Silverlight Bitmap Print");
How document looks on screen (inside Image)
And this is printed:
Rather than using the WriteableBitmapEx extensions, when declaring your Image element, try setting the Stretch property so that it stretches based on your maximum specified dimensions:
var image = new Image { Source = bitmap, Stretch = Stretch.UniformToFill };
Blilinear filter tends to blur images.You may want to try WriteableBitmapExtensions.Interpolation.NearestNeighbor instead to see if you get better results
In my case it was enough to set UseLayoutRounding="True".