low visual quality of shrinked image using Graphics.FromImage.DrawImage - c#

Following this question Resize image proportionally with MaxHeight and MaxWidth constraints
I implemented the solution as follows:
public static class ImageResizer
{
public static Image ResizeImage(String origFileLocation, int maxWidth, int maxHeight)
{
Image img = Image.FromFile(origFileLocation);
if (img.Height < maxHeight && img.Width < maxWidth) return img;
using (img)
{
Double xRatio = (double)maxWidth / img.Width;
Double yRatio = (double)maxHeight / img.Height;
Double ratio = Math.Max(xRatio, yRatio);
int nnx = (int)Math.Floor(img.Width * ratio);
int nny = (int)Math.Floor(img.Height * ratio);
Bitmap cpy = new Bitmap(nnx, nny, PixelFormat.Format32bppArgb);
using (Graphics gr = Graphics.FromImage(cpy))
{
gr.Clear(Color.Transparent);
// This is said to give best quality when resizing images
gr.SmoothingMode = SmoothingMode.HighQuality;
gr.PixelOffsetMode = PixelOffsetMode.HighQuality;
gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
gr.DrawImage(img,
new Rectangle(0, 0, nnx, nny),
new Rectangle(0, 0, img.Width, img.Height),
GraphicsUnit.Pixel);
}
return cpy;
}
}
}
And then saving image this way:
resized.Save(resizedFilePath, System.Drawing.Imaging.ImageFormat.Gif);
However, trying it, shrinking image, the result is very grained as you can see in this photo
I would assume that shrinking image should result with no noticeable effects. Any ideas about it?

Yes. As #Ivan Stoev suggested. The problem is not with the resizing, rather in the saving method which appears to compress the image by default for some reason.
I used
resized.Save(resizedFilePath, System.Drawing.Imaging.ImageFormat.Png);
for saving and now everything seems fine. Thank you.

resized.Save(resizedFilePath, System.Drawing.Imaging.ImageFormat.Png);
size large not optimation

Related

Graphics.DrawImage not changing size of image

I have a function which takes in an image and resizes it to fit a canvas while maintaining its aspect ratio. This code is only a minorly modified version of the code from this answer: c# Image resizing to different size while preserving aspect ratio
For this example, my canvas height is 642, my canvas width is 823.
When I run the below function, the line
graphic.DrawImage(image, posX, posY, newWidth, newHeight);
seemingly does nothing to the image size. Going in:
Image.Height == 800,
Image.Width == 1280.
newHeight = 514,
newWidth == 823
AFTER running graphic.DrawImage
Image.Height == 800,
Image.Width == 1280.
As you can see, Image's height and width are unchanged.
Does anyone see a gapingly obvious error that would cause this to happen? Thank you!
private Bitmap resizeImage(Bitmap workingImage,
int canvasWidth, int canvasHeight)
{
Image image = (Bitmap)workingImage.Clone();
System.Drawing.Image thumbnail =
new Bitmap(canvasWidth, canvasHeight);
double ratioX = (double)canvasWidth / (double)workingImage.Width;
double ratioY = (double)canvasHeight / (double)workingImage.Height;
double ratio = ratioX < ratioY ? ratioX : ratioY;
int newHeight = Convert.ToInt32((double)workingImage.Height * ratio);
int newWidth = Convert.ToInt32((double)workingImage.Width * ratio);
int posX = Convert.ToInt32((canvasWidth - ((double)workingImage.Width * ratio)) / 2);
int posY = Convert.ToInt32((canvasHeight - ((double)workingImage.Height * ratio)) / 2);
using (Graphics graphic = Graphics.FromImage(thumbnail))
{
graphic.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
graphic.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
graphic.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
graphic.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
graphic.Clear(SystemColors.Control);
graphic.DrawImage(image, posX, posY, newWidth, newHeight); //<--- HERE
}
System.Drawing.Imaging.ImageCodecInfo[] info =
System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders();
System.Drawing.Imaging.EncoderParameters encoderParameters;
encoderParameters = new System.Drawing.Imaging.EncoderParameters(1);
encoderParameters.Param[0] = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality,
100L);
return workingImage;
}
Size of your image is defined here
Image image = (Bitmap)workingImage.Clone();
This
graphic.DrawImage(image, posX, posY, newWidth, newHeight);
only draws the image with specified arguments, but it does not mean that the image size gets changed. In other words, drawing an image simply does not change its size, it just takes the image and draws it on a canvas as you wish.
Image Resizing functanality pupose see the below link
http://www.codeproject.com/Articles/30524/An-Easy-to-Use-Image-Resizing-and-Cropping-Control?msg=5203911#xx5203911xx
This link content may help you

Re size image not working C# [duplicate]

This question already has answers here:
Resize image proportionally with MaxHeight and MaxWidth constraints
(3 answers)
Closed 9 years ago.
Am re sizing an image with the following code
using (Image thumbnail = new Bitmap(100, 50))
{
using (Bitmap source = new Bitmap(imageFile))
{
using (Graphics g = Graphics.FromImage(thumbnail))
{
g.CompositingQuality = CompositingQuality.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.SmoothingMode = SmoothingMode.HighQuality;
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(source, 0, 0, 100, 50);
}
}
using (MemoryStream ms = new MemoryStream())
{
thumbnail.Save(ms, ImageFormat.Png);
thumbnail.Save(dest, ImageFormat.Png);
}
}
but it is not giving an image of any quality. pixelation is making the image wired.
i have also tried the code
image re size in stack
but am getting a black screen as the result instead of jpg am using png is the only difference.
any suggestion for improving the image quality. i have to re size the transparent image to a size 100by50.
Thanks in advance.
Try this, Assuming you can use it
public static Image Resize(Image originalImage, int w, int h)
{
//Original Image attributes
int originalWidth = originalImage.Width;
int originalHeight = originalImage.Height;
// Figure out the ratio
double ratioX = (double)w / (double)originalWidth;
double ratioY = (double)h / (double)originalHeight;
// use whichever multiplier is smaller
double ratio = ratioX < ratioY ? ratioX : ratioY;
// now we can get the new height and width
int newHeight = Convert.ToInt32(originalHeight * ratio);
int newWidth = Convert.ToInt32(originalWidth * ratio);
Image thumbnail = new Bitmap(newWidth, newHeight);
Graphics graphic = Graphics.FromImage(thumbnail);
graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphic.SmoothingMode = SmoothingMode.HighQuality;
graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphic.CompositingQuality = CompositingQuality.HighQuality;
graphic.Clear(Color.Transparent);
graphic.DrawImage(originalImage, 0, 0, newWidth, newHeight);
return thumbnail;
}

Control the image file size after re-size and add watermark

I am Resizing a Image and add watermark to image. And Return the image. Here is my code.
Image resizedImage = ResizeImage(original6, new Size(500, 375));
Re size function:
public static System.Drawing.Image ResizeImage(System.Drawing.Image image, Size size)
{
int newWidth;
int newHeight;
if (true)
{
int originalWidth = image.Width;
int originalHeight = image.Height;
float percentWidth = (float)size.Width / (float)originalWidth;
float percentHeight = (float)size.Height / (float)originalHeight;
float percent = percentHeight < percentWidth ? percentHeight : percentWidth;
newWidth = (int)(originalWidth * percent);
newHeight = (int)(originalHeight * percent);
}
else
{
newWidth = size.Width;
newHeight = size.Height;
}
System.Drawing.Image newImage = new Bitmap(newWidth, newHeight);
using (Graphics graphicsHandle = Graphics.FromImage(newImage))
{
graphicsHandle.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphicsHandle.DrawImage(image, 0, 0, newWidth, newHeight);
}
System.Drawing.Bitmap bitmapimage = new System.Drawing.Bitmap(newImage, size.Width, size.Height);// create bitmap with same size of Actual image
System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bitmapimage);
SolidBrush brush = new SolidBrush(Color.FromArgb(113, 255, 255, 255));
//Adding watermark text on image
g.DrawString("My watermark", new Font("Arial", 16, FontStyle.Bold), brush, 5, 100);
return bitmapimage;
}
I am retrieve the new re sized image with watermark and going to save as new image file.
resized6.Save(Server.MapPath(sSavePath + ownerRef + "Pic6v2" + ".jpg"));
This is working fine. However I can't control the file size.
When my original JPG is only 45kb but when my new re-sized image is 500kb. How can I reduce the file size.?
info: original resolution (400x300 px) and new image (500x375px)
I don't remember this off the top of my head, but file size generally has to do with JPEG quality settings. You also need to make sure it's saved as an actual jpg, not a bitmap, which I don't see that you're doing..
See also: C# Simple Image Resize : File Size Not Shrinking
JPEG Quality settings:
http://msdn.microsoft.com/en-us/library/bb882583.aspx
You may be able to change the quality of the JPEG to get a smaller file size. See
http://msdn.microsoft.com/en-us/library/bb882583.aspx
also
Quality of a saved JPG in C#

Image loss while shrinking certain images with Graphics.DrawImage() [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How can I get better results when shrinking an image
I am trying to generate a thumbnail of size 200 x 200px using the code below. It works fine for certain images but does not for others. When it does not work, the thumbnail is generated with that size but only partial image is seen and the other part is gray (like you have used a gray brush and smeared on top of the thumbnail). I haven't been able to see a trend when it fails. For example, it fails for a JPEG image with 400px x 400px size. If I try to generate the thumbnail with size 150px x 150px, there is no image loss.
If this helps here is one image that causes problems - http://s11.postimage.org/sse5zhpqr/Drawing_8.jpg
Appreciate your time.
public Bitmap GenerateThumbnail(Bitmap sourceBitmap, int thumbnailWidth, int thumbnailHeight)
{
Bitmap thumbnailBitmap = null;
decimal ratio;
int newWidth = 0;
int newHeight = 0;
// If the image is smaller than the requested thumbnail size just return it
if (sourceBitmap.Width < thumbnailWidth &&
sourceBitmap.Height < thumbnailHeight)
{
newWidth = sourceBitmap.Width;
newHeight = sourceBitmap.Height;
}
else if (sourceBitmap.Width > sourceBitmap.Height)
{
ratio = (decimal)thumbnailWidth / sourceBitmap.Width;
newWidth = thumbnailWidth;
decimal tempDecimalHeight = sourceBitmap.Height * ratio;
newHeight = (int)tempDecimalHeight;
}
else
{
ratio = (decimal)thumbnailHeight / sourceBitmap.Height;
newHeight = thumbnailHeight;
decimal tempDecimalHeight = sourceBitmap.Width * ratio;
newWidth = (int)tempDecimalHeight;
}
thumbnailBitmap = new Bitmap(newWidth, newHeight);
Graphics g = Graphics.FromImage(thumbnailBitmap);
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
g.FillRectangle(Brushes.White, 0, 0, newWidth, newHeight);
g.DrawImage(sourceBitmap, 0, 0, newWidth, newHeight);
g.Dispose();
return thumbnailBitmap;
}
Update:
I did some more analysis and it seems that the issue is while saving the thumbnail to the SQL Server database in a varbinary column. I am using a MemoryStream to do that as below. If I save it to the disk it appears just fine. Here is my thumbnail from the database - http://s12.postimage.org/a7j50vr8d/Generated_Thumbnail.jpg
using (MemoryStream thumbnailStream = new MemoryStream())
{
thumbnailBitmap.Save(thumbnailStream, System.Drawing.Imaging.ImageFormat.Jpeg);
return thumbnailStream.ToArray();
}
Update - This problem is resolved. The issue was NHibernate mapping that I was using for the varbinary column. I had to specify the type as "BinaryBlob" to make sure there is no silent truncation of data > 8KB.
I appreciate, this should probably be a comment and not an answer, but for the extra formatting I'm posting as an answer.
Here's the code I've used to shrink an image and I've never had this issue:
private byte[] ResizeImage(System.Drawing.Image image, double scaleFactor)
{
//a holder for the result
int newWidth = (int)(image.Width * scaleFactor);
int newHeight = (int)(image.Height * scaleFactor);
Bitmap result = new Bitmap(newWidth, newHeight);
//use a graphics object to draw the resized image into the bitmap
using (Graphics graphics = Graphics.FromImage(result))
{
//set the resize quality modes to high quality
graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
//draw the image into the target bitmap
graphics.DrawImage(image, 0, 0, result.Width, result.Height);
}
//return the resulting bitmap
ImageConverter converter = new ImageConverter();
return (byte[])converter.ConvertTo(result, typeof(byte[]));
}
Granted, I return a byte[] and not a Bitmap, as I then save it to a database.
The only differences I can really see is that instantiate my result Bitmap with a height and width, I have no call to the FillRectangle method, and I do not set the PixelOffsetMode. I also start off with an Image instead of a Bitmap
Hope this helps you somehow though.

How to proportional resize image of any type in .NET?

Is possible to resize image proportionally in a way independent of the image type (bmp, jpg, png, etc)?
I have this code and know that something is missing (but don't know what):
public bool ResizeImage(string fileName, string imgFileName,
ImageFormat format, int width, int height)
{
try
{
using (Image img = Image.FromFile(fileName))
{
Image thumbNail = new Bitmap(width, height, img.PixelFormat);
Graphics g = Graphics.FromImage(thumbNail);
g.CompositingQuality = CompositingQuality.HighQuality;
g.SmoothingMode = SmoothingMode.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
Rectangle rect = new Rectangle(0, 0, width, height);
g.DrawImage(img, rect);
thumbNail.Save(imgFileName, format);
}
return true;
}
catch (Exception)
{
return false;
}
}
If not possible, how can I resize proportional a jpeg image?
I know that using this method, but don't know where to put this (!).
First and foremost, you're not grabbing the CURRENT height and width of the image. In order to resize proportionately you'll need to grab the current height/width of the image and resize based on that.
From there, find the greatest attribute and resize proportionately based on that.
For instance, let's say the current image is 800 x 600 and you wanna resize proportionately within a 400 x 400 space. Grab the greatest proportion (800) and find it's ratio to the new size. 800 -> 400 = .5 Now take that ratio and multiply by the second dimension (600 * .5 = 300).
Your new size is 400 x 300.
Here's a PHP example (sorry....you'll get it though)
$thumb_width = 400;
$thumb_height = 400;
$orig_w=imagesx($src_img);
$orig_h=imagesy($src_img);
if ($orig_w>$orig_h){//find the greater proportion
$ratio=$thumb_width/$orig_w;
$thumb_height=$orig_h*$ratio;
}else{
$ratio=$thumb_height/$orig_h;
$thumb_width=$orig_w*$ratio;
}
I think your code is fine, but taking in the width and the height as parameters is where you're going wrong in my opinion. Why should the caller of this method have to decide how big they want the width and the height? I would suggest changing it to a percentage:
public bool ResizeImage(string fileName, string imgFileName,
ImageFormat format, int percent)
{
try
{
using (Image img = Image.FromFile(fileName))
{
int width = img.Width * (percent * .01);
int height = img.Height * (percent * .01);
Image thumbNail = new Bitmap(width, height, img.PixelFormat);
Graphics g = Graphics.FromImage(thumbNail);
g.CompositingQuality = CompositingQuality.HighQuality;
g.SmoothingMode = SmoothingMode.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
Rectangle rect = new Rectangle(0, 0, width, height);
g.DrawImage(img, rect);
thumbNail.Save(imgFileName, format);
}
return true;
}
catch (Exception)
{
return false;
}
}

Categories

Resources