I am trying to rescale an image on the fly with c#.net. Everything appeared to be working correctly, but upon closer inspection, the colors do not look right.
The code appears to be pretty straight forward and it rescales fine, but why does the original image appear a pinker color than the scaled picture?
using (Bitmap origBitmap = new Bitmap("my_picture.jpg"))
{
using (Bitmap outputImage = new Bitmap(1024, 768, origBitmap.PixelFormat))
{
outputImage.SetResolution(origBitmap.HorizontalResolution, origBitmap.VerticalResolution);
using (Graphics g = Graphics.FromImage(outputImage))
{
g.Clear(Color.Black);
g.CompositingMode = CompositingMode.SourceCopy;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(
origBitmap,
new Rectangle(0, 0, 1024, 768),
new Rectangle(0, 0, origBitmap.Width, origBitmap.Height),
GraphicsUnit.Pixel
);
context.Response.ContentType = "image/jpeg";
outputImage.Save(context.Response.OutputStream, ImageFormat.Jpeg);
}
}
}
Attached you can see the difference in the colors. Hoping I am missing something simple?
picture_scaling_issues.jpg
Looks like I answered my own question!
using (Bitmap origBitmap = (Bitmap) Bitmap.FromFile("my_file.jpg", true))
{ … }
The "true" parameter is for "useEmbeddedColorManagement". Setting that to true fixes the problem...
Related
I am currently writing a .NET Core App to run cross-platform. Part of this is App is Drawing a Text and overlay onto a Bitmap.
So I added System.Drawing.Common and finally ended up with a working Code(On Windows) like this:
public static Bitmap WriteText(Bitmap bmp, string txt)
{
RectangleF rectf = new RectangleF(0, 0, bmp.Width, bmp.Height);
// Create graphic object that will draw onto the bitmap
using (Graphics g = Graphics.FromImage(bmp))
{
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
StringFormat format = new StringFormat()
{
Alignment = StringAlignment.Center,
LineAlignment = StringAlignment.Center
};
// dampening
using (Brush brush = new SolidBrush(Color.FromArgb(69, Color.Black)))
g.FillRectangle(brush, rectf);
var fSize = 26;
var fFam = Fonts.GetDefaultFontName();
// Draw the path
GraphicsPath p = new GraphicsPath();
p.AddString(txt, fFam, (int)FontStyle.Regular, g.DpiX * fSize / 72.2f, rectf, format);
g.DrawPath(new Pen(Color.FromArgb(180, Color.Black), 8), p);
// Draw the text
g.DrawString(txt, new Font(fFam, fSize), Brushes.White, rectf, format);
// Flush all graphics changes to the bitmap
g.Flush();
}
// Now save or use the bitmap
return bmp;
}
On Windows Outputs are generated correctly or as expected like this for Example:
But when run on my Ubuntu/linux server, the GraphicsPath/Shadow would generate like this:
My first thought was an Error in the DPI-calculation since my Server doesn't have an X-Server installed but apparently the GraphicsPath is drawn correct; just the position is wrong?
*Editnote: Also the "Formatting" apparently works on the usual DrawString... so thats extra weird
Maybe I've missed something but this looks like a platform-specific bug to me?
I'd appreciate any help & opinions at this point... Thanks
I have a PNG image of resolution 6000x4000, on which I have to draw upon. So I load the image into a pictureBox with of size 1280x800. After drawing on it, I need to save the PNG image in its original resolution of 6000x4000. So I reload it into a new bitmap of size 6000x4000 using
btm = new Bitmap(6000, 4000);
image = Graphics.FromImage(btm);
g.DrawImage(btm, Point.Empty);
And save it using
btm.Save(filePath, System.Drawing.Imaging.ImageFormat.Png);
Now I end up with the a white background png image of resolution 6000x4000 but with the edited image of 1280x800 on it like this Saved Image
How do I resize the image back to its original (6000x4000) size. Thank you.
Also please find my codebelow
private void drawImage(string imgLocation)
{
Bitmap b = new Bitmap(imgLocation);
////test
pictureBox1.Height = 800;
pictureBox1.Width = 1280;
g = pictureBox1.CreateGraphics();
btm = new Bitmap(6000, 4000);
image = Graphics.FromImage(btm);
image.CompositingMode = CompositingMode.SourceCopy;
image.CompositingQuality = CompositingQuality.HighQuality;
image.InterpolationMode = InterpolationMode.HighQualityBicubic;
image.SmoothingMode = SmoothingMode.HighQuality;
image.PixelOffsetMode = PixelOffsetMode.HighQuality;
image.Clear(Color.White);
image.DrawImage(b, new Rectangle(0, 0, pictureBox1.Width, pictureBox1.Height));
//image.DrawImage(btm, new Rectangle(0, 0, pictureBox1.Width, pictureBox1.Height));
g.SmoothingMode = SmoothingMode.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
//g.DrawImage(btm, Point.Empty);
g.DrawImage(btm, new Rectangle(0, 0, 6000,4000) );
}
What about this? g.DrawImage(btm, new Rectangle(0,0,6000,4000));
Below is a method that may help you with images upscaling/downscaling.
Note though that big upscaling ratio will cause serious image distortions in any case.
You may also try to play with other then graphics.CompositingMode properties like graphics.CompositingQuality
You will need following usings:
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
The method works fine in my app.
public static Image ImageResize(Image img, int width, int height)
{
var tgtRect = new Rectangle(0, 0, width, height);
var tgtImg = new Bitmap(width, height);
tgtImg.SetResolution(img.HorizontalResolution, img.VerticalResolution);
using (var graphics = Graphics.FromImage(tgtImg))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(img, tgtRect, 0, 0, img.Width, img.Height, GraphicsUnit.Pixel, wrapMode);
}
return tgtImg;
}
}
I'm trying to resize an image. I thought it was a simple task...
Here's my code (note, the two Save calls are just for debugging to illustrate the problem):
var newSize = new Size { Width = 450, Height = 250 };
using (var img = (Bitmap)Image.FromFile(sourceImageFilename))
{
var outputImage = new Bitmap(newSize.Width, newSize.Height);
// Save input image for debugging (screenshot below)
img.Save(#"M:\Coding\Photos\Temp\input.jpg");
using (Graphics gr = Graphics.FromImage(img))
{
gr.SmoothingMode = SmoothingMode.HighQuality;
gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
gr.PixelOffsetMode = PixelOffsetMode.HighQuality;
gr.DrawImage(outputImage, new Rectangle(0, 0, newSize.Width, newSize.Height));
}
// Save output image for debugging (screenshot below)
outputImage.Save(#"M:\Coding\Photos\Temp\output.jpg");
}
This appears to be the exact same code a ton of people are using (and exists on SO in many answers). However, here's what the two images that are being written to disk look like:
The original image is 5344x3006 and newSize (and the black output image) are 450x250.
All my other code is working fine (reading pixels from the input image with SetPixel, etc.), it's just this resize that's broken. Doing the resize with the Bitmap constructor is fine (but a bad quality resize).
You need to get the graphics from the OutputImage.
public static Bitmap Scale(this Bitmap inputImage, Size newSize)
{
var outputImage = new Bitmap(newSize.Width, newSize.Height);
inputImage.Save(#"M:\Coding\Photos\Temp\input.jpg");
using (Graphics gr = Graphics.FromImage(outputImage))
{
gr.SmoothingMode = SmoothingMode.HighQuality;
gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
gr.PixelOffsetMode = PixelOffsetMode.HighQuality;
gr.DrawImage(inputImage, new Rectangle(0, 0, newSize.Width, newSize.Height));
}
outputImage.Save(#"M:\Coding\Photos\Temp\output.jpg");
return outputImage;
}
I cannot seem to programmatically create a colored bitmap to display in a PictureBox. The bitmap saves normally as a file, but is faded at the edges when displayed in a PictureBox. Here is simplified code used to create and display the Bitmap (in actual code, the bitmap generation is completely separate from the form, so forcing the bitmap size to match the picturebox size isn't possible):
Bitmap Bmp = new Bitmap(4, 4, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
using (Graphics gfx = Graphics.FromImage(Bmp))
using (SolidBrush brush = new SolidBrush(Color.BlueViolet))
{
gfx.FillRectangle(brush, 0, 0, 4, 4);
}
Then set the Image value on a PictureBox to the generated Bitmap:
pictureBox1.Image = Bmp;
Here is the resulting bitmap displayed in a 300x300 picturebox:
How do I set the Image on the PictureBox so that it displays the colored bitmap properly (full solid)?
EDIT: I am restricted to generating smaller source bitmaps, so upscaling into a PictureBox is unavoidable. The problem appears when the generated source bitmap is 4px or 100px square, so I believe these are relevant cases.
EDIT: The PictureBox scaling should be set to stretch or zoom for the issue to manifest. In this example case the 4x4 source bitmap is stretched to 300x300.
EDIT: The basic problem is PictureBox's inability to upscale small bitmaps into large controls. This is confusing because the Bitmap upscales nicely into a PictureBox.Background image. Unless you have a magic bullet that will fix the image upscaling problem, I think it might be best to go for clear and simple workarounds in your answer.
You are generating a 4x4 bitmap and it's being stretched. Specify the size to match the picture box instead:
int width = pictureBox1.Width;
int height = pictureBox1.Height;
var Bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
using (Graphics gfx = Graphics.FromImage(Bmp))
using (var brush = new SolidBrush(Color.BlueViolet))
{
gfx.FillRectangle(brush, 0, 0, width, height);
}
pictureBox1.Image = Bmp;
You will need to turn anti-aliasing off. Also, since you are using one color for the whole picturebox, why not make the bitmap 1x1? If you need it 4x4, change the int the top of the example from 1 to 4.
int hw = 1;
Bitmap Bmp = new Bitmap(hw, hw,
System.Drawing.Imaging.PixelFormat.Format24bppRgb);
using (Graphics gfx = Graphics.FromImage(Bmp))
{
// Turn off anti-aliasing and draw an exact copy
gfx.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
gfx.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
using (SolidBrush brush = new SolidBrush(Color.BlueViolet))
{
gfx.FillRectangle(brush, 0, 0, hw, hw);
}
}
pictureBox1.Image = Bmp;
UPDATE
Since you are still having the same issue by setting the picturebox to the image, you will have to get the graphics object from the picturebox and draw directly on it.
The code is very similar.
using (Graphics gfx = Graphics.FromImage(pictureBox1.Image))
{
// Turn off anti-aliasing and draw an exact copy
gfx.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
gfx.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
using (SolidBrush brush = new SolidBrush(Color.BlueViolet))
{
gfx.FillRectangle(brush, 0, 0,
pictureBox11.Width - 1,
pictureBox11.Height - 1);
}
}
// Force the picturebox to redraw with the new image.
// You could also use pictureBox11.Refresh() to do the redraw.
pictureBox11.Invalidate();
I tried to test your code and the image were properly displayed.
But when i used this code:
Rectangle srcRect = New Rectangle(0, 0, Bmp.Width, Bmp.Height);
Rectangle dstRect = New Rectangle(0, 0, PictureBox1.Width, PictureBox1.Height);
g = PictureBox1.CreateGraphics;
g.DrawImage(Bmp, dstRect, srcRect, GraphicsUnit.Pixel);
g.Dispose();
I did get exactly your result. In order to fix it:
Rectangle srcRect = New Rectangle(0, 0, Bmp.Width - 1, Bmp.Height - 1);
Rectangle dstRect = New Rectangle(0, 0, PictureBox1.Width, PictureBox1.Height);
g = PictureBox1.CreateGraphics;
g.DrawImage(Bmp, dstRect, srcRect, GraphicsUnit.Pixel);
g.Dispose();
Edit:
So you have the bitmap and you want to stretch it. And the bitmap has ane solid color. Do this insted:
Color pixelColor = Bmp.GetPixel(0, 0);
PictureBox1.BackColor = pixelColor;
valter
I'm trying to draw images to return as base 64 strings over a web service in .net 4.5. I can get as far as loading a custom background, but then I need to draw text onto that background. The problem is, once I go from Image->Graphics object->Image, I end up with a blank png. If I return the original srcImage (the blank template) over the service, everything works, but my label is blank so I know it must be a problem with my graphics object somewhere.
My code is:
var labelSize = new Size(400, 459);
using (var srcImage = Image.FromFile(HostingEnvironment.MapPath("~/images/labels/" + labelImageFilename))) {
PixelFormat format = srcImage.PixelFormat;
using (Bitmap newImage = new Bitmap(labelSize.Width, labelSize.Height, format))
using (Graphics g = Graphics.FromImage(newImage)) {
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
Rectangle srcRect = new Rectangle(0, 0, srcImage.Width, srcImage.Height);
Rectangle destRect = new Rectangle(0,0, labelSize.Width, labelSize.Height);
g.DrawImage(srcImage, destRect, srcRect, GraphicsUnit.Pixel);
// draw other shapes etc
g.FillRegion(Brushes.Blue,new Region(new Rectangle(0,0,200,200)));
g.Clear(Color.Red);
g.Flush();
return new Bitmap(srcImage, labelSize.Width, labelSize.Height); // this works fine, but my image is just the standard background I'm using
return new Bitmap(labelSize.Width, labelSize.Height, g); // returns a blank image
}
}
Nothing is drawn, neither the template background (srcImage), not the red or blue rectangles.
I think it looks like your graphics object is drawing on newImage, but you are returning srcImage. If you want to return the result of your drawing, I think you need to return newImage.
Try something like:
return new Bitmap(newImage, labelSize.Width, labelSize.Height);