I need to resize my image proportionately without changing aspect ratio.I have the code to resize with fixed hight and width but I need to resize image proportionately with max height(say 600 pixels). How can I modify the code to suit my requirement?
public static void Main()
{
var image = Image.FromFile(#"c:\logo.png");
var newImage = ScaleImage(image, 300, 400);
newImage.Save(#"c:\test.png", ImageFormat.Png);
}
public static Image ScaleImage(Image image, int maxWidth, int maxHeight)
{
var ratioX = (double)maxWidth / image.Width;
var ratioY = (double)maxHeight / image.Height;
var ratio = Math.Min(ratioX, ratioY);
var newWidth = (int)(image.Width * ratio);
var newHeight = (int)(image.Height * ratio);
var newImage = new Bitmap(newWidth, newHeight);
Graphics.FromImage(newImage).DrawImage(image, 0, 0, newWidth, newHeight);
return newImage;
}
Please provide your valuable thoughts.
This almost feels to easy and I feel I'm missing something. Anyway, won't that do the trick?
public static Image ScaleImage(Image image, int maxHeight)
{
var ratio = (double)maxHeight / image.Height;
var newWidth = (int)(image.Width * ratio);
var newHeight = (int)(image.Height * ratio);
var newImage = new Bitmap(newWidth, newHeight);
using (var g = Graphics.FromImage(newImage))
{
g.DrawImage(image, 0, 0, newWidth, newHeight);
}
return newImage;
}
Use the following function
public Bitmap ProportionallyResizeBitmapByHeight(Bitmap imgToResize, int height)
{
int sourceWidth = imgToResize.Width;
int sourceHeight = imgToResize.Height;
float scale = 0;
scale = (height / (float)sourceHeight);
int destWidth = (int)(sourceWidth * scale);
int destHeight = (int)(sourceHeight * scale);
Bitmap result = new Bitmap(destWidth, destHeight);
result.SetResolution(imgToResize.HorizontalResolution, imgToResize.VerticalResolution);
Graphics g = Graphics.FromImage(result);
g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
g.Dispose();
return result;
}
Well, thinking through the process:
if you have an image that 800 x 600 in size and want to resize it to newWidth x 400 height (plus whatever the respective newWidth will be), you get the ratio by dividing the newHeight (maxHeight in your case) with 600 and multiply 800 with this ratio, right?
So, in this case you need to change maxWidth and maxHeight to optional parameters (say 800 by 600) to give yourself some dynamism and get the following:
public static Image ScaleImage(Image image, int maxWidth = 800, int maxHeight = 600)
{
int newWidth;
int newHeight;
double ratio = image.Height / image.Width;
if(maxHeight != 600) {
newWidth = image.Width * ratio;
newHeight = maxHeight;
}
Bitmap newImage = new Bitmap(newWidth, newHeight);
Graphics.FromImage(newImage).DrawImage(image, 0, 0, newWidth, newHeight);
return newImage;
}
I hope this helps. I didn't test it, but I've rewritten my VB code, so allegedly it should be okay...
There's also a ResizeStream method here: http://forums.asp.net/t/1576697.aspx/1 that you might find useful.
If you want to keep image quality, you can use the CompositingQuality and SmoothingMode, etc. variables.
100% Worked
private static BitmapFrame CreateResizedImage(ImageSource source, int Max_width, int Max_height, int margin)
{
float scaleHeight = (float)Max_width / (float)source.Height;
float scaleWidth = (float)Max_height / (float)source.Width;
float scale = Math.Min(scaleHeight, scaleWidth);
int width = (int)(source.Width * scale);
int height = (int)(source.Height * scale);
var rect = new Rect(margin, margin, width - margin * 2, height - margin * 2);
var group = new DrawingGroup();
RenderOptions.SetBitmapScalingMode(group, BitmapScalingMode.HighQuality);
group.Children.Add(new ImageDrawing(source, rect));
var drawingVisual = new DrawingVisual();
using (var drawingContext = drawingVisual.RenderOpen())
drawingContext.DrawDrawing(group);
var resizedImage = new RenderTargetBitmap(
width, height, // Resized dimensions
96, 96, // Default DPI values
PixelFormats.Default); // Default pixel format
resizedImage.Render(drawingVisual);
return BitmapFrame.Create(resizedImage);
}
//--------Main------------//
BitmapImage imageSource = (BitmapImage)ImagePreview.Source;
var NewImage= CreateResizedImage(imageSource , 300, 300, 0);
Related
I try to resize a binary image to a smaller file if needed, however all images are getting more byte after resize, while size is getting smaller, so result is very ugly images...have no idea why its get bigger.
here is the code I use any help would be appreciated.
using (var srcImage = System.Drawing.Image.FromStream(myMemStream))
{
double height = srcImage.Height;
double width = srcImage.Width;
newWidth = (int)(srcImage.Width);
double aspect = scale / width;
newHeight = Convert.ToInt32(aspect * height);
newWidth = Convert.ToInt32(aspect * width);
using (var newImage = new Bitmap(newWidth, newHeight))
using (var graphics = Graphics.FromImage(newImage))
{
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.DrawImage(srcImage, new Rectangle(0, 0, newWidth, newHeight));
System.IO.MemoryStream ms = new System.IO.MemoryStream();
newImage.Save(ms, format);
ms.Position = 0;
_bytes = ms.ToArray(); //Returns a new byte array.
newImage.Dispose();
}
}
**** update *****
double height = srcImage.Height;
double width = srcImage.Width;
newWidth = (int)(srcImage.Width);
double aspect = scale / width;
newHeight = Convert.ToInt32(aspect * height);
newWidth = Convert.ToInt32(aspect * width);
Image scaledImage = ScaleDownTo(srcImage, newHeight, newWidth);
newWidth = scaledImage.Width;
newHeight = scaledImage.Height;
System.IO.MemoryStream ms = new System.IO.MemoryStream();
scaledImage.Save(ms, format);
ms.Position = 0;
_bytes = ms.ToArray();
scaledImage.Dispose();
What I actually do is resize the image for example to a static max width, from any to 300px, so I calculate the current image width, take the aspect in double and resize this image to this size.
Any help on this is really appriciated
Well, here is a short function for scaling down images.
public static Image ScaleDownTo(Image image, int height, int width) {
if (image != null) {
if (image.Width > width || image.Height > height) {
float factor = Math.Max(((float)width) / image.Width, ((float)height) / image.Height);
if (factor > 0) {
RectangleF imgRect = new RectangleF(0, 0, image.Width * factor, image.Height * factor);
imgRect.X = ((float)width - imgRect.Width) / 2f;
imgRect.Y = ((float)height - imgRect.Height) / 2f;
Bitmap cellImage = new Bitmap(width, height);
using (Graphics cellImageGraphics = Graphics.FromImage(cellImage)) {
cellImageGraphics.Clear(Color.Transparent);
cellImageGraphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
cellImageGraphics.DrawImage(image, imgRect);
}
return cellImage;
}
}
return image;
}
return null;
}
Just use it to get the new downscaled image.
I am facing an interesting issue when re-sizing images of average dimension 1200x700. I am using following method to do the same. I see original image size is 210KB and output image size is 255KB.
public static Image ResizeImage(Image image, Size size, bool preserveAspectRatio = true)
{
int newWidth;
int newHeight;
if (preserveAspectRatio)
{
int originalWidth = imageFile.Width;
int originalHeight = imageFile.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;
}
Image newImage = new Bitmap(newWidth, newHeight);
using (Graphics graphicsHandle = Graphics.FromImage(newImage))
{
graphicsHandle.CompositingQuality = CompositingQuality.HighQuality;
graphicsHandle.SmoothingMode = SmoothingMode.HighQuality;
graphicsHandle.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphicsHandle.DrawImage(imageFile, 0, 0, newWidth, newHeight);
}
return newImage;
}
To call above method I'm using following code:
WebClient wc = new WebClient();
try
{
using (var image = Image.FromStream(new MemoryStream(wc.DownloadData(remoteFileLocation))))
{
Image resized = ResizeImage(image, new Size(660, 660));
resized.Save(saveFileLocation);
}
}
catch(Exception)
{
//todo
}
I tried different InterpolationMode and CompositingQuality but result is always same. Is there anything I'm missing to reduce image dimension and size? I mean, I'm expecting if dimension is decreased image size should also decrease.
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
I have to display image in photo gallery # width=200 height=180, but while uploading images I have to resize it , but the problem is every image have different resolution. How can I resize the images with different resolution so that images remain intact.
Here is my code :
private void ResizeImage()
{
System.Drawing.Image ImageToUpload = System.Drawing.Image.FromStream(FileUpload1.PostedFile.InputStream);
byte[] image = null;
int h = ImageToUpload.Height;
int w = ImageToUpload.Width;
int r = int.Parse(ImageToUpload.VerticalResolution.ToString());
int NewWidth = 200;//constant
int NewHeight = 180;//constant
byte[] imagesize = FileUpload1.FileBytes;
System.Drawing.Bitmap BitMapImage = new System.Drawing.Bitmap(ImageToUpload, NewWidth, NewHeight);//this line gives horrible output
MemoryStream Memory = new MemoryStream();
BitMapImage.Save(Memory, System.Drawing.Imaging.ImageFormat.Jpeg);
Memory.Position = 0;
image = new byte[Memory.Length + 1];
Memory.Read(image, 0, image.Length);
}
if resolution is 96 and if I set maxwidth=200 then its height would be 150 then only the image looks small and accurate. Can't we resize image in desired way so that it looks exact?
The function will resize the image maintaining aspect ratio.
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;
}
Usage
Image BitMapImage = Resize(ImageToUpload, NewWidth, NewHeight);
Here i keep height fixed to 180 to maintain aspect ratio. It will resize the image and save to disk. The return value is the percentage value which i use in 'background-size' css.
public float ResizePhoto(string filepath, string filename)
{
var path = Path.Combine(filepath, filename);
var newPath = Path.Combine(filepath, "sml_" + filename);
Image orgImage = Image.FromFile(path);
float fixedHt = 180f;
int destHeight, destWidth;
float reqScale;
if(orgImage.Height > fixedHt)
{
destHeight = (int)fixedHt;
destWidth = (int)(fixedHt / orgImage.Height * orgImage.Width);
reqScale = destWidth / destHeight * 100;
}
else
{
destHeight = orgImage.Height;
destWidth = orgImage.Width;
reqScale = fixedHt / destHeight * 100;
}
Bitmap bmp = new Bitmap(destWidth, destHeight);
bmp.SetResolution(orgImage.HorizontalResolution,orgImage.VerticalResolution);
Graphics grPhoto = Graphics.FromImage(bmp);
grPhoto.DrawImage(orgImage,
new Rectangle(0, 0, destWidth, destHeight),
new Rectangle(0, 0, orgImage.Width, orgImage.Height),
GraphicsUnit.Pixel);
bmp.Save(newPath);
return reqScale;
}
How would you resize a JPEG image, to a fixed width whilst keeping aspect ratio? In a simple way, whilst preserving quality.
This will scale in the vertical axis only:
public static Image ResizeImageFixedWidth(Image imgToResize, int width)
{
int sourceWidth = imgToResize.Width;
int sourceHeight = imgToResize.Height;
float nPercent = ((float)width / (float)sourceWidth);
int destWidth = (int)(sourceWidth * nPercent);
int destHeight = (int)(sourceHeight * nPercent);
Bitmap b = new Bitmap(destWidth, destHeight);
Graphics g = Graphics.FromImage((Image)b);
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
g.Dispose();
return (Image)b;
}
If you are reducing the width by 25 percent to a fixed value, you must reduce the height by 25 percent.
If you are increasing the width by 25 percent to a fixed value, you must increasing the height by 25 percent.
It's really straight forward.
Assuming there is a (double width) variable:
Image imgOriginal = Bitmap.FromFile(path);
double height = (imgOriginal.Height * width) / imgOriginal.Width;
Image imgnew = new Bitmap((int)width, (int)height, PixelFormat.Format32bppArgb);
Graphics g = Graphics.FromImage(imgnew);
g.DrawImage(imgOriginal, new Point[]{new Point(0,0), new Point(width, 0), new Point(0, height)}, new Rectangle(0,0,imgOriginal.Width, imgOriginal.Height), GraphicsUnit.Pixel);
In the end you´ll have a new image with widthxheight, then, you´ll need to flush the graphics e save the imgnew.
I think there are plenty of samples of this if you search for them. Here's the one I commonly use...
public static Stream ResizeGdi(Stream stream, System.Drawing.Size size)
{
Image image = Image.FromStream(stream);
int width = image.Width;
int height = image.Height;
int sourceX = 0, sourceY = 0, destX = 0, destY = 0;
float percent = 0, percentWidth = 0, percentHeight = 0;
percentWidth = ((float)size.Width / (float)width);
percentHeight = ((float)size.Height / (float)height);
int destW = 0;
int destH = 0;
if (percentHeight < percentWidth)
{
percent = percentHeight;
}
else
{
percent = percentWidth;
}
destW = (int)(width * percent);
destH = (int)(height * percent);
MemoryStream mStream = new MemoryStream();
if (destW == 0
&& destH == 0)
{
image.Save(mStream, System.Drawing.Imaging.ImageFormat.Jpeg);
return mStream;
}
using (Bitmap bitmap = new Bitmap(destW, destH, System.Drawing.Imaging.PixelFormat.Format48bppRgb))
{
using (System.Drawing.Graphics graphics = System.Drawing.Graphics.FromImage(bitmap))
{
//graphics.Clear(Color.Red);
graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
graphics.DrawImage(image,
new Rectangle(destX, destY, destW, destH),
new Rectangle(sourceX, sourceY, width, height),
GraphicsUnit.Pixel);
}
bitmap.Save(mStream, System.Drawing.Imaging.ImageFormat.Jpeg);
}
mStream.Position = 0;
return mStream as Stream;
}
Example of the calling code...
Stream stream = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.None);
resizedStream = ImageUtility.ResizeGdi(stream, new System.Drawing.Size(resizeWidth, resizeHeight));
A quick search on code project has found the following article. It allows for resizing of images which accepts a boolean to restrain the new image to keep the originals aspect ratio. I'm unsure of what the quality is like as no screenshots were provided. See the article here