Resizing image get damage in pixel - c#

My requirement is to resize an image if it is bigger than 800 X 600 pixels. I have to resize it to 800 X 600 resolution as per aspect ratio.
I am using below code to re-size it:
public string ResizeUserImage(string fullFileName, int maxHeight, int maxWidth, string newFileName)
{
string savepath = System.Web.HttpContext.Current.Server.MapPath("//InitiativeImage//");
try
{
using (Image originalImage = Image.FromFile(fullFileName))
{
int height = originalImage.Height;
int width = originalImage.Width;
int newHeight = maxHeight;
int newWidth = maxWidth;
if (height > maxHeight || width > maxWidth)
{
if (height > maxHeight)
{
newHeight = maxHeight;
float temp = ((float)width / (float)height) * (float)maxHeight;
newWidth = Convert.ToInt32(temp);
height = newHeight;
width = newWidth;
}
if (width > maxWidth)
{
newWidth = maxWidth;
float temp = ((float)height / (float)width) * (float)maxWidth;
newHeight = Convert.ToInt32(temp);
}
Image.GetThumbnailImageAbort abort = new Image.GetThumbnailImageAbort(ThumbnailCallback);
using (Image resizedImage = originalImage.GetThumbnailImage(newWidth, newHeight, abort, System.IntPtr.Zero))
{
//When image is compress then store the image
var guid = Guid.NewGuid().ToString();
string latestFileName = guid + Path.GetExtension(newFileName);
resizedImage.Save(savepath + #"\" + latestFileName);
string finalPath = AppSettings.Domain + "InitiativeImage/" + latestFileName;
return finalPath;
}
}
else if (fullFileName != newFileName)
{
//var guid = Guid.NewGuid().ToString();
//newFileName = guid + Path.GetExtension(newFileName);
//// no resizing necessary, but need to create new file
//originalImage.Save(savepath + #"\" + newFileName);
//string finalPath = AppSettings.Domain + "UserImage/" + newFileName;
return newFileName;
}
return fullFileName;
}
}
catch (Exception)
{
throw;
}
}
It works perfect but resizing image gets damaged in pixel.
See below original image which I am uploading to the server:
After re-sizing it, it is damages like below image:
Hope you got my question. The resized image get damage in pixel. Please let me know where I am wrong or where is the issue.

Pls try out below function.
public void FixedSize(string oldImageFile, int Width, int Height,string finalpath)
{
Bitmap imgPhoto = new Bitmap(oldImageFile);
int sourceWidth = imgPhoto.Width;
int sourceHeight = imgPhoto.Height;
int sourceX = 0;
int sourceY = 0;
int destX = 0;
int destY = 0;
float nPercent = 0;
float nPercentW = 0;
float nPercentH = 0;
nPercentW = ((float)Width / (float)sourceWidth);
nPercentH = ((float)Height / (float)sourceHeight);
if (nPercentH < nPercentW)
{
nPercent = nPercentH;
destX = System.Convert.ToInt16((Width -
(sourceWidth * nPercent)) / 2);
}
else
{
nPercent = nPercentW;
destY = System.Convert.ToInt16((Height -
(sourceHeight * nPercent)) / 2);
}
int destWidth = (int)(sourceWidth * nPercent);
int destHeight = (int)(sourceHeight * nPercent);
Bitmap bmPhoto = new Bitmap(destWidth, destHeight,
PixelFormat.Format24bppRgb);
bmPhoto.SetResolution(imgPhoto.HorizontalResolution,
imgPhoto.VerticalResolution);
Graphics grPhoto = Graphics.FromImage(bmPhoto);
grPhoto.Clear(Color.White);
grPhoto.InterpolationMode =
InterpolationMode.HighQualityBicubic;
grPhoto.DrawImage(imgPhoto,
new Rectangle(0, 0, destWidth, destHeight),
new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight),
GraphicsUnit.Pixel);
grPhoto.Dispose();
bmPhoto.Save(finalpath);
}

From the documentation on Image.GetThumbnailImage method:
The GetThumbnailImage method works well when the requested thumbnail image has a size of about 120 x 120 pixels. If you request a large thumbnail image (for example, 300 x 300) from an Image that has an embedded thumbnail, there could be a noticeable loss of quality in the thumbnail image. It might be better to scale the main image (instead of scaling the embedded thumbnail) by calling the DrawImage method.
But your objective size is around 800x600 pixels, which is way above the indented use.
Thus, I recommend you to take a look at this answer about image resizing.

Related

Resize Image But Wrong Border Color (Black 'Auto')

public Image resizeImage(int newWidth, int newHeight, string stPhotoPath)
{
Image imgPhoto = Image.FromFile(stPhotoPath);
int sourceWidth = imgPhoto.Width;
int sourceHeight = imgPhoto.Height;
if (sourceWidth < sourceHeight)
{
int buff = newWidth;
newWidth = newHeight;
newHeight = buff;
}
int sourceX = 0, sourceY = 0, destX = 0, destY = 0;
float nPercent = 0, nPercentW = 0, nPercentH = 0;
nPercentW = ((float)newWidth / (float)sourceWidth);
nPercentH = ((float)newHeight / (float)sourceHeight);
if (nPercentH < nPercentW)
{
nPercent = nPercentH;
destX = System.Convert.ToInt16((newWidth -
(sourceWidth * nPercent)) / 2);
}
else
{
nPercent = nPercentW;
destY = System.Convert.ToInt16((newHeight -
(sourceHeight * nPercent)) / 2);
}
int destWidth = (int)(sourceWidth * nPercent);
int destHeight = (int)(sourceHeight * nPercent);
Bitmap bmPhoto = new Bitmap(newWidth, newHeight,
PixelFormat.Format24bppRgb);
bmPhoto.SetResolution(imgPhoto.HorizontalResolution,
imgPhoto.VerticalResolution);
Graphics grPhoto = Graphics.FromImage(bmPhoto);
grPhoto.Clear(Color.Black);
grPhoto.InterpolationMode =
System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
grPhoto.DrawImage(imgPhoto,
new Rectangle(destX, destY, destWidth, destHeight),
new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight),
GraphicsUnit.Pixel);
grPhoto.Dispose();
imgPhoto.Dispose();
return bmPhoto;
}
I use such a code to scale down images, but there is a problem that after the images are scaled down, the remaining spaces remain black. Something that should definitely not happen. What is the solution? The background color must be white.
public static class ResizeImage
{
/// <summary>
/// Return new resized size to display the image
/// </summary>
/// <param name="srcrectanle">source rectangle of image or you can pass the
bitmap and set the size accrodingly</param>
/// <param name="initSize">initial size of the page to draw image</param>
/// <returns></returns>
public static SizeF getResizedRectangle(RectangleF srcrectanle, SizeF initSize)
{
float sw = srcrectanle.Width;
float sh = srcrectanle.Height;
float dw = initSize.Width;
float dh = initSize.Height;
float finalHeight, finalWidth;
float Sourceratio = sw / sh;
if (Sourceratio >= 1)
{
finalWidth = (int)dw;
float ratio = sw / dw;
finalHeight = (sh / ratio);
}
else
{
finalHeight = (int)dh;
float ratio = sh / dh;
finalWidth = (sw / ratio);
}
return new SizeF(finalHeight, finalHeight);
}
}
Use this function to resize your image. Hope you have the knowledge of source rectangle and destination rectangle.

Image Getting Stretched when trying to Resize It keeping the aspect Ratio

Im using the following code to resize an image preserving the aspect ratio
public Bitmap resizeImage(System.Drawing.Image imgToResize, SizeF size)
{
int sourceWidth = imgToResize.Width;
int sourceHeight = imgToResize.Height;
float nPercent = 0;
float nPercentW = 0;
float nPercentH = 0;
nPercentW = ((float)size.Width / (float)sourceWidth);
nPercentH = ((float)size.Height / (float)sourceHeight);
if (nPercentH < nPercentW)
nPercent = nPercentH;
else
nPercent = nPercentW;
int destWidth = (int)(sourceWidth * nPercent);
int destHeight = (int)(sourceHeight * nPercent);
Bitmap b = new Bitmap(destWidth, destHeight);
Graphics g = Graphics.FromImage((System.Drawing.Image)b);
// Used to Prevent White Line Border
// g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
g.Dispose();
return b;
}
But images with large width gets compressed and the contents seem packed up into a small space.What im trying to achieve is this : Resize the Large Size/Large Resolution image because processing this will take huge time,So when the image width or height exceeds say 1000 i want to resize the image to a Smaller size eg:1000 Width or Height which ever is larger,so that i can save computation time.But it seems the above code is forcibly trying to fit the image into the 1000X1000 Box when i do
if (y.Width > 1000 || y.Height > 1000)
{
y = new Bitmap( resizeImage(y, new Size(1000, 1000)));
}
Try this, its a bit neater
public static Bitmap ResizeImage(Bitmap source, Size size)
{
var scale = Math.Min(size.Width / (double)source.Width, size.Height / (double)source.Height);
var bmp = new Bitmap((int)(source.Width * scale), (int)(source.Height * scale));
using (var graph = Graphics.FromImage(bmp))
{
graph.InterpolationMode = InterpolationMode.High;
graph.CompositingQuality = CompositingQuality.HighQuality;
graph.SmoothingMode = SmoothingMode.AntiAlias;
graph.DrawImage(source, 0, 0, bmp.Width, bmp.Height);
}
return bmp;
}

Changing Size of PictureBox in Stretch Size Mode to achieve closest Aspect Ratio Match [duplicate]

I'm trying to resize an image while preserving the aspect ratio from the original image so the new image doesn't look squashed.
eg:
Convert a 150*100 image into a 150*150 image.
The extra 50 pixels of the height need to be padded with a white background color.
This is the current code I am using.
It works well for resizing but changing the aspect ratio of the original image squashes the new image.
private void resizeImage(string path, string originalFilename,
int width, int height)
{
Image image = Image.FromFile(path + originalFilename);
System.Drawing.Image thumbnail = new Bitmap(width, height);
System.Drawing.Graphics graphic =
System.Drawing.Graphics.FromImage(thumbnail);
graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphic.SmoothingMode = SmoothingMode.HighQuality;
graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphic.CompositingQuality = CompositingQuality.HighQuality;
graphic.DrawImage(image, 0, 0, width, height);
System.Drawing.Imaging.ImageCodecInfo[] info =
ImageCodecInfo.GetImageEncoders();
EncoderParameters encoderParameters;
encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality,
100L);
thumbnail.Save(path + width + "." + originalFilename, info[1],
encoderParameters);
}
EDIT: I'd like to have the image padded instead of cropped
This should do it.
private void resizeImage(string path, string originalFilename,
/* note changed names */
int canvasWidth, int canvasHeight,
/* new */
int originalWidth, int originalHeight)
{
Image image = Image.FromFile(path + originalFilename);
System.Drawing.Image thumbnail =
new Bitmap(canvasWidth, canvasHeight); // changed parm names
System.Drawing.Graphics graphic =
System.Drawing.Graphics.FromImage(thumbnail);
graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphic.SmoothingMode = SmoothingMode.HighQuality;
graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphic.CompositingQuality = CompositingQuality.HighQuality;
/* ------------------ new code --------------- */
// Figure out the ratio
double ratioX = (double) canvasWidth / (double) originalWidth;
double ratioY = (double) canvasHeight / (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);
// Now calculate the X,Y position of the upper-left corner
// (one of these will always be zero)
int posX = Convert.ToInt32((canvasWidth - (originalWidth * ratio)) / 2);
int posY = Convert.ToInt32((canvasHeight - (originalHeight * ratio)) / 2);
graphic.Clear(Color.White); // white padding
graphic.DrawImage(image, posX, posY, newWidth, newHeight);
/* ------------- end new code ---------------- */
System.Drawing.Imaging.ImageCodecInfo[] info =
ImageCodecInfo.GetImageEncoders();
EncoderParameters encoderParameters;
encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality,
100L);
thumbnail.Save(path + newWidth + "." + originalFilename, info[1],
encoderParameters);
}
Edited to add:
Those who want to improve this code should put it in the comments, or a new answer. Don't edit this code directly.
I found out how to resize AND pad the image by learning from this this CodeProject Article.
static Image FixedSize(Image imgPhoto, int Width, int Height)
{
int sourceWidth = imgPhoto.Width;
int sourceHeight = imgPhoto.Height;
int sourceX = 0;
int sourceY = 0;
int destX = 0;
int destY = 0;
float nPercent = 0;
float nPercentW = 0;
float nPercentH = 0;
nPercentW = ((float)Width / (float)sourceWidth);
nPercentH = ((float)Height / (float)sourceHeight);
if (nPercentH < nPercentW)
{
nPercent = nPercentH;
destX = System.Convert.ToInt16((Width -
(sourceWidth * nPercent)) / 2);
}
else
{
nPercent = nPercentW;
destY = System.Convert.ToInt16((Height -
(sourceHeight * nPercent)) / 2);
}
int destWidth = (int)(sourceWidth * nPercent);
int destHeight = (int)(sourceHeight * nPercent);
Bitmap bmPhoto = new Bitmap(Width, Height,
PixelFormat.Format24bppRgb);
bmPhoto.SetResolution(imgPhoto.HorizontalResolution,
imgPhoto.VerticalResolution);
Graphics grPhoto = Graphics.FromImage(bmPhoto);
grPhoto.Clear(Color.Red);
grPhoto.InterpolationMode =
InterpolationMode.HighQualityBicubic;
grPhoto.DrawImage(imgPhoto,
new Rectangle(destX, destY, destWidth, destHeight),
new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight),
GraphicsUnit.Pixel);
grPhoto.Dispose();
return bmPhoto;
}
I use the following method to calculate the desired image size:
using System.Drawing;
public static Size ResizeKeepAspect(this Size src, int maxWidth, int maxHeight, bool enlarge = false)
{
maxWidth = enlarge ? maxWidth : Math.Min(maxWidth, src.Width);
maxHeight = enlarge ? maxHeight : Math.Min(maxHeight, src.Height);
decimal rnd = Math.Min(maxWidth / (decimal)src.Width, maxHeight / (decimal)src.Height);
return new Size((int)Math.Round(src.Width * rnd), (int)Math.Round(src.Height * rnd));
}
This puts the problem of aspect ratio and dimensions in a separate method.
What does the parameter bool enlarge = false ?
usually you do only shrinking of images because enlarging means quality loss - so I added this optional parameter if you want to do it anyway
To get a faster result, the function that obtains the size could be found in resultSize:
Size original = new Size(640, 480);
int maxSize = 100;
float percent = (new List<float> { (float)maxSize / (float)original.Width , (float)maxSize / (float)original.Height }).Min();
Size resultSize = new Size((int)Math.Floor(original.Width * percent), (int)Math.Floor(original.Height * percent));
Uses Linq to minimize variable and recalculations, as well as unnecesary if/else statements
Just generalizing it down to aspect ratios and sizes, image stuff can be done outside of this function
public static d.RectangleF ScaleRect(d.RectangleF dest, d.RectangleF src,
bool keepWidth, bool keepHeight)
{
d.RectangleF destRect = new d.RectangleF();
float sourceAspect = src.Width / src.Height;
float destAspect = dest.Width / dest.Height;
if (sourceAspect > destAspect)
{
// wider than high keep the width and scale the height
destRect.Width = dest.Width;
destRect.Height = dest.Width / sourceAspect;
if (keepHeight)
{
float resizePerc = dest.Height / destRect.Height;
destRect.Width = dest.Width * resizePerc;
destRect.Height = dest.Height;
}
}
else
{
// higher than wide – keep the height and scale the width
destRect.Height = dest.Height;
destRect.Width = dest.Height * sourceAspect;
if (keepWidth)
{
float resizePerc = dest.Width / destRect.Width;
destRect.Width = dest.Width;
destRect.Height = dest.Height * resizePerc;
}
}
return destRect;
}
I'm going to add my code here too. This code will allow you resize an image with or without the aspect ratio being enforced or to resize with padding. This is a modified version of egrunin's code.
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
namespace ConsoleApplication1
{
public class Program
{
public static void Main(string[] args)
{
var path = Directory.GetParent(Directory.GetCurrentDirectory()).Parent.FullName;
ResizeImage(path, "large.jpg", path, "new.jpg", 100, 100, true, true);
}
/// <summary>Resizes an image to a new width and height.</summary>
/// <param name="originalPath">The folder which holds the original image.</param>
/// <param name="originalFileName">The file name of the original image.</param>
/// <param name="newPath">The folder which will hold the resized image.</param>
/// <param name="newFileName">The file name of the resized image.</param>
/// <param name="maximumWidth">When resizing the image, this is the maximum width to resize the image to.</param>
/// <param name="maximumHeight">When resizing the image, this is the maximum height to resize the image to.</param>
/// <param name="enforceRatio">Indicates whether to keep the width/height ratio aspect or not. If set to false, images with an unequal width and height will be distorted and padding is disregarded. If set to true, the width/height ratio aspect is maintained and distortion does not occur.</param>
/// <param name="addPadding">Indicates whether fill the smaller dimension of the image with a white background. If set to true, the white padding fills the smaller dimension until it reach the specified max width or height. This is used for maintaining a 1:1 ratio if the max width and height are the same.</param>
private static void ResizeImage(string originalPath, string originalFileName, string newPath, string newFileName, int maximumWidth, int maximumHeight, bool enforceRatio, bool addPadding)
{
var image = Image.FromFile(originalPath + "\\" + originalFileName);
var imageEncoders = ImageCodecInfo.GetImageEncoders();
EncoderParameters encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, 100L);
var canvasWidth = maximumWidth;
var canvasHeight = maximumHeight;
var newImageWidth = maximumWidth;
var newImageHeight = maximumHeight;
var xPosition = 0;
var yPosition = 0;
if (enforceRatio)
{
var ratioX = maximumWidth / (double)image.Width;
var ratioY = maximumHeight / (double)image.Height;
var ratio = ratioX < ratioY ? ratioX : ratioY;
newImageHeight = (int)(image.Height * ratio);
newImageWidth = (int)(image.Width * ratio);
if (addPadding)
{
xPosition = (int)((maximumWidth - (image.Width * ratio)) / 2);
yPosition = (int)((maximumHeight - (image.Height * ratio)) / 2);
}
else
{
canvasWidth = newImageWidth;
canvasHeight = newImageHeight;
}
}
var thumbnail = new Bitmap(canvasWidth, canvasHeight);
var graphic = Graphics.FromImage(thumbnail);
if (enforceRatio && addPadding)
{
graphic.Clear(Color.White);
}
graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphic.SmoothingMode = SmoothingMode.HighQuality;
graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphic.CompositingQuality = CompositingQuality.HighQuality;
graphic.DrawImage(image, xPosition, yPosition, newImageWidth, newImageHeight);
thumbnail.Save(newPath + "\\" + newFileName, imageEncoders[1], encoderParameters);
}
}
}
Here's a less specific extension method that works with Image rather than doing the loading and saving for you. It also allows you to specify interpolation method and correctly renders edges when you use NearestNeighbour interpolation.
The image will be rendered within the bounds of the area you specify so you always know your output width and height. e.g:
namespace YourApp
{
#region Namespaces
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
#endregion
/// <summary>Generic helper functions related to graphics.</summary>
public static class ImageExtensions
{
/// <summary>Resizes an image to a new width and height value.</summary>
/// <param name="image">The image to resize.</param>
/// <param name="newWidth">The width of the new image.</param>
/// <param name="newHeight">The height of the new image.</param>
/// <param name="mode">Interpolation mode.</param>
/// <param name="maintainAspectRatio">If true, the image is centered in the middle of the returned image, maintaining the aspect ratio of the original image.</param>
/// <returns>The new image. The old image is unaffected.</returns>
public static Image ResizeImage(this Image image, int newWidth, int newHeight, InterpolationMode mode = InterpolationMode.Default, bool maintainAspectRatio = false)
{
Bitmap output = new Bitmap(newWidth, newHeight, image.PixelFormat);
using (Graphics gfx = Graphics.FromImage(output))
{
gfx.Clear(Color.FromArgb(0, 0, 0, 0));
gfx.InterpolationMode = mode;
if (mode == InterpolationMode.NearestNeighbor)
{
gfx.PixelOffsetMode = PixelOffsetMode.HighQuality;
gfx.SmoothingMode = SmoothingMode.HighQuality;
}
double ratioW = (double)newWidth / (double)image.Width;
double ratioH = (double)newHeight / (double)image.Height;
double ratio = ratioW < ratioH ? ratioW : ratioH;
int insideWidth = (int)(image.Width * ratio);
int insideHeight = (int)(image.Height * ratio);
gfx.DrawImage(image, new Rectangle((newWidth / 2) - (insideWidth / 2), (newHeight / 2) - (insideHeight / 2), insideWidth, insideHeight));
}
return output;
}
}
}
Note: this code resizes and removes everything outside the aspect ratio instead of padding it..
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
namespace MyPhotos.Common
{
public class ThumbCreator
{
public enum VerticalAlign
{
Top,
Middle,
Bottom
}
public enum HorizontalAlign
{
Left,
Middle,
Right
}
public void Convert(string sourceFile, string targetFile, ImageFormat targetFormat, int height, int width, VerticalAlign valign, HorizontalAlign halign)
{
using (Image img = Image.FromFile(sourceFile))
{
using (Image targetImg = Convert(img, height, width, valign, halign))
{
string directory = Path.GetDirectoryName(targetFile);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
if (targetFormat == ImageFormat.Jpeg)
{
SaveJpeg(targetFile, targetImg, 100);
}
else
{
targetImg.Save(targetFile, targetFormat);
}
}
}
}
/// <summary>
/// Saves an image as a jpeg image, with the given quality
/// </summary>
/// <param name="path">Path to which the image would be saved.</param>
// <param name="quality">An integer from 0 to 100, with 100 being the
/// highest quality</param>
public static void SaveJpeg(string path, Image img, int quality)
{
if (quality < 0 || quality > 100)
throw new ArgumentOutOfRangeException("quality must be between 0 and 100.");
// Encoder parameter for image quality
EncoderParameter qualityParam =
new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality);
// Jpeg image codec
ImageCodecInfo jpegCodec = GetEncoderInfo("image/jpeg");
EncoderParameters encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = qualityParam;
img.Save(path, jpegCodec, encoderParams);
}
/// <summary>
/// Returns the image codec with the given mime type
/// </summary>
private static ImageCodecInfo GetEncoderInfo(string mimeType)
{
// Get image codecs for all image formats
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
// Find the correct image codec
for (int i = 0; i < codecs.Length; i++)
if (codecs[i].MimeType == mimeType)
return codecs[i];
return null;
}
public Image Convert(Image img, int height, int width, VerticalAlign valign, HorizontalAlign halign)
{
Bitmap result = new Bitmap(width, height);
using (Graphics g = Graphics.FromImage(result))
{
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
float ratio = (float)height / (float)img.Height;
int temp = (int)((float)img.Width * ratio);
if (temp == width)
{
//no corrections are needed!
g.DrawImage(img, 0, 0, width, height);
return result;
}
else if (temp > width)
{
//den e för bred!
int overFlow = (temp - width);
if (halign == HorizontalAlign.Middle)
{
g.DrawImage(img, 0 - overFlow / 2, 0, temp, height);
}
else if (halign == HorizontalAlign.Left)
{
g.DrawImage(img, 0, 0, temp, height);
}
else if (halign == HorizontalAlign.Right)
{
g.DrawImage(img, -overFlow, 0, temp, height);
}
}
else
{
//den e för hög!
ratio = (float)width / (float)img.Width;
temp = (int)((float)img.Height * ratio);
int overFlow = (temp - height);
if (valign == VerticalAlign.Top)
{
g.DrawImage(img, 0, 0, width, temp);
}
else if (valign == VerticalAlign.Middle)
{
g.DrawImage(img, 0, -overFlow / 2, width, temp);
}
else if (valign == VerticalAlign.Bottom)
{
g.DrawImage(img, 0, -overFlow, width, temp);
}
}
}
return result;
}
}
}
// This allows us to resize the image. It prevents skewed images and
// also vertically long images caused by trying to maintain the aspect
// ratio on images who's height is larger than their width
public void ResizeImage(string OriginalFile, string NewFile, int NewWidth, int MaxHeight, bool OnlyResizeIfWider)
{
System.Drawing.Image FullsizeImage = System.Drawing.Image.FromFile(OriginalFile);
// Prevent using images internal thumbnail
FullsizeImage.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipNone);
FullsizeImage.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipNone);
if (OnlyResizeIfWider)
{
if (FullsizeImage.Width <= NewWidth)
{
NewWidth = FullsizeImage.Width;
}
}
int NewHeight = FullsizeImage.Height * NewWidth / FullsizeImage.Width;
if (NewHeight > MaxHeight)
{
// Resize with height instead
NewWidth = FullsizeImage.Width * MaxHeight / FullsizeImage.Height;
NewHeight = MaxHeight;
}
System.Drawing.Image NewImage = FullsizeImage.GetThumbnailImage(NewWidth, NewHeight, null, IntPtr.Zero);
// Clear handle to original file so that we can overwrite it if necessary
FullsizeImage.Dispose();
// Save resized picture
NewImage.Save(NewFile);
}
I created a extension method that is much simpiler than the answers that are posted.
and the aspect ratio is applied without cropping the image.
public static Image Resize(this Image image, int width, int height) {
var scale = Math.Min(height / (float)image.Height, width / (float)image.Width);
return image.GetThumbnailImage((int)(image.Width * scale), (int)(image.Height * scale), () => false, IntPtr.Zero);
}
Example usage:
using (var img = Image.FromFile(pathToOriginalImage)) {
using (var thumbnail = img.Resize(60, 60)){
// Here you can do whatever you need to do with thumnail
}
}
Maintain aspect Ration and eliminate letterbox and Pillarbox.
static Image FixedSize(Image imgPhoto, int Width, int Height)
{
int sourceWidth = imgPhoto.Width;
int sourceHeight = imgPhoto.Height;
int X = 0;
int Y = 0;
float nPercent = 0;
float nPercentW = 0;
float nPercentH = 0;
nPercentW = ((float)Width / (float)sourceWidth);
nPercentH = ((float)Height / (float)sourceHeight);
if (nPercentH < nPercentW)
{
nPercent = nPercentH;
}
else
{
nPercent = nPercentW;
}
int destWidth = (int)(sourceWidth * nPercent);
int destHeight = (int)(sourceHeight * nPercent);
Bitmap bmPhoto = new Bitmap(destWidth, destHeight, PixelFormat.Format24bppRgb);
bmPhoto.SetResolution(imgPhoto.HorizontalResolution,
imgPhoto.VerticalResolution);
Graphics grPhoto = Graphics.FromImage(bmPhoto);
grPhoto.DrawImage(imgPhoto,
new Rectangle(X, Y, destWidth, destHeight),
new Rectangle(X, Y, sourceWidth, sourceHeight),
GraphicsUnit.Pixel);
grPhoto.Dispose();
return bmPhoto;
}
public static void resizeImage_n_save(Stream sourcePath, string targetPath, int requiredSize)
{
using (var image = System.Drawing.Image.FromStream(sourcePath))
{
double ratio = 0;
var newWidth = 0;
var newHeight = 0;
double w = Convert.ToInt32(image.Width);
double h = Convert.ToInt32(image.Height);
if (w > h)
{
ratio = h / w * 100;
newWidth = requiredSize;
newHeight = Convert.ToInt32(requiredSize * ratio / 100);
}
else
{
ratio = w / h * 100;
newHeight = requiredSize;
newWidth = Convert.ToInt32(requiredSize * ratio / 100);
}
// var newWidth = (int)(image.Width * scaleFactor);
// var newHeight = (int)(image.Height * scaleFactor);
var thumbnailImg = new Bitmap(newWidth, newHeight);
var thumbGraph = Graphics.FromImage(thumbnailImg);
thumbGraph.CompositingQuality = CompositingQuality.HighQuality;
thumbGraph.SmoothingMode = SmoothingMode.HighQuality;
thumbGraph.InterpolationMode = InterpolationMode.HighQualityBicubic;
var imageRectangle = new Rectangle(0, 0, newWidth, newHeight);
thumbGraph.DrawImage(image, imageRectangle);
thumbnailImg.Save(targetPath, image.RawFormat);
//var img = FixedSize(image, requiredSize, requiredSize);
//img.Save(targetPath, image.RawFormat);
}
}
I just wrote this cos none of the answers already here were simple enough. You can replace the hardcoded 128 for whatever you want or base them off the size of the original image. All i wanted was to rescale the image into a 128x128 image, keeping the aspect ratio and centering the result in the new image.
private Bitmap CreateLargeIconForImage(Bitmap src)
{
Bitmap bmp = new Bitmap(128, 128);
Graphics g = Graphics.FromImage(bmp);
float scale = Math.Max((float)src.Width / 128.0f, (float)src.Height / 128.0f);
PointF p = new PointF(128.0f - ((float)src.Width / scale), 128.0f - ((float)src.Height / scale));
SizeF size = new SizeF((float)src.Width / scale, (float)src.Height / scale);
g.DrawImage(src, new RectangleF(p, size));
return bmp;
}
I know this is an older thread. However, this is the first result in a Google search on the topic.
None of the answers fit my requirement. So, here's a solution I put together by understanding the older solutions, but limiting the result image size to the most suitable height and width.
double ratioW = (double)desiredWidthPixels / (double)originalImage.Width;
double ratioH = (double)desiredHeightPixels / (double)originalImage.Height;
double ratio = ratioW < ratioH ? ratioW : ratioH;
int suitableWidth = (int)(originalImage.Width * ratio);
int suitableHeight = (int)(originalImage.Height * ratio);
var resizedPhoto = new Bitmap((int)suitableWidth, (int)suitableHeight);
var graphicsSurface = Graphics.FromImage(resizedPhoto);
graphicsSurface.DrawImage(originalImage, new RectangleF(new PointF(0,0), new SizeF(suitableWidth, suitableHeight)));

Resize image in C# with aspect ratio and crop central image so there are no gaps

I'm trying to resize user uploaded images to a landscape dimensions e.g. 450w and 250h while maintaining aspect ratio, but to avoid resized images like portrait images having gaps on the side I would like to crop the centre of the image to fill the resized dimensions.
I have found plenty of code to resize images while maintaining aspect ratio but not what I am looking for above, I'm hoping someone can help.
You should pass needToFill = true:
public static System.Drawing.Image FixedSize(Image image, int Width, int Height, bool needToFill)
{
#region calculations
int sourceWidth = image.Width;
int sourceHeight = image.Height;
int sourceX = 0;
int sourceY = 0;
double destX = 0;
double destY = 0;
double nScale = 0;
double nScaleW = 0;
double nScaleH = 0;
nScaleW = ((double)Width / (double)sourceWidth);
nScaleH = ((double)Height / (double)sourceHeight);
if (!needToFill)
{
nScale = Math.Min(nScaleH, nScaleW);
}
else
{
nScale = Math.Max(nScaleH, nScaleW);
destY = (Height - sourceHeight * nScale) / 2;
destX = (Width - sourceWidth * nScale) / 2;
}
if (nScale > 1)
nScale = 1;
int destWidth = (int)Math.Round(sourceWidth * nScale);
int destHeight = (int)Math.Round(sourceHeight * nScale);
#endregion
System.Drawing.Bitmap bmPhoto = null;
try
{
bmPhoto = new System.Drawing.Bitmap(destWidth + (int)Math.Round(2 * destX), destHeight + (int)Math.Round(2 * destY));
}
catch (Exception ex)
{
throw new ApplicationException(string.Format("destWidth:{0}, destX:{1}, destHeight:{2}, desxtY:{3}, Width:{4}, Height:{5}",
destWidth, destX, destHeight, destY, Width, Height), ex);
}
using (System.Drawing.Graphics grPhoto = System.Drawing.Graphics.FromImage(bmPhoto))
{
grPhoto.InterpolationMode = InterpolationMode.HighQualityBicubic;
grPhoto.CompositingQuality = CompositingQuality.HighQuality;
grPhoto.SmoothingMode = SmoothingMode.HighQuality;
Rectangle to = new System.Drawing.Rectangle((int)Math.Round(destX), (int)Math.Round(destY), destWidth, destHeight);
Rectangle from = new System.Drawing.Rectangle(sourceX, sourceY, sourceWidth, sourceHeight);
//Console.WriteLine("From: " + from.ToString());
//Console.WriteLine("To: " + to.ToString());
grPhoto.DrawImage(image, to, from, System.Drawing.GraphicsUnit.Pixel);
return bmPhoto;
}
}

c# Image resizing to different size while preserving aspect ratio

I'm trying to resize an image while preserving the aspect ratio from the original image so the new image doesn't look squashed.
eg:
Convert a 150*100 image into a 150*150 image.
The extra 50 pixels of the height need to be padded with a white background color.
This is the current code I am using.
It works well for resizing but changing the aspect ratio of the original image squashes the new image.
private void resizeImage(string path, string originalFilename,
int width, int height)
{
Image image = Image.FromFile(path + originalFilename);
System.Drawing.Image thumbnail = new Bitmap(width, height);
System.Drawing.Graphics graphic =
System.Drawing.Graphics.FromImage(thumbnail);
graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphic.SmoothingMode = SmoothingMode.HighQuality;
graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphic.CompositingQuality = CompositingQuality.HighQuality;
graphic.DrawImage(image, 0, 0, width, height);
System.Drawing.Imaging.ImageCodecInfo[] info =
ImageCodecInfo.GetImageEncoders();
EncoderParameters encoderParameters;
encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality,
100L);
thumbnail.Save(path + width + "." + originalFilename, info[1],
encoderParameters);
}
EDIT: I'd like to have the image padded instead of cropped
This should do it.
private void resizeImage(string path, string originalFilename,
/* note changed names */
int canvasWidth, int canvasHeight,
/* new */
int originalWidth, int originalHeight)
{
Image image = Image.FromFile(path + originalFilename);
System.Drawing.Image thumbnail =
new Bitmap(canvasWidth, canvasHeight); // changed parm names
System.Drawing.Graphics graphic =
System.Drawing.Graphics.FromImage(thumbnail);
graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphic.SmoothingMode = SmoothingMode.HighQuality;
graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphic.CompositingQuality = CompositingQuality.HighQuality;
/* ------------------ new code --------------- */
// Figure out the ratio
double ratioX = (double) canvasWidth / (double) originalWidth;
double ratioY = (double) canvasHeight / (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);
// Now calculate the X,Y position of the upper-left corner
// (one of these will always be zero)
int posX = Convert.ToInt32((canvasWidth - (originalWidth * ratio)) / 2);
int posY = Convert.ToInt32((canvasHeight - (originalHeight * ratio)) / 2);
graphic.Clear(Color.White); // white padding
graphic.DrawImage(image, posX, posY, newWidth, newHeight);
/* ------------- end new code ---------------- */
System.Drawing.Imaging.ImageCodecInfo[] info =
ImageCodecInfo.GetImageEncoders();
EncoderParameters encoderParameters;
encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality,
100L);
thumbnail.Save(path + newWidth + "." + originalFilename, info[1],
encoderParameters);
}
Edited to add:
Those who want to improve this code should put it in the comments, or a new answer. Don't edit this code directly.
I found out how to resize AND pad the image by learning from this this CodeProject Article.
static Image FixedSize(Image imgPhoto, int Width, int Height)
{
int sourceWidth = imgPhoto.Width;
int sourceHeight = imgPhoto.Height;
int sourceX = 0;
int sourceY = 0;
int destX = 0;
int destY = 0;
float nPercent = 0;
float nPercentW = 0;
float nPercentH = 0;
nPercentW = ((float)Width / (float)sourceWidth);
nPercentH = ((float)Height / (float)sourceHeight);
if (nPercentH < nPercentW)
{
nPercent = nPercentH;
destX = System.Convert.ToInt16((Width -
(sourceWidth * nPercent)) / 2);
}
else
{
nPercent = nPercentW;
destY = System.Convert.ToInt16((Height -
(sourceHeight * nPercent)) / 2);
}
int destWidth = (int)(sourceWidth * nPercent);
int destHeight = (int)(sourceHeight * nPercent);
Bitmap bmPhoto = new Bitmap(Width, Height,
PixelFormat.Format24bppRgb);
bmPhoto.SetResolution(imgPhoto.HorizontalResolution,
imgPhoto.VerticalResolution);
Graphics grPhoto = Graphics.FromImage(bmPhoto);
grPhoto.Clear(Color.Red);
grPhoto.InterpolationMode =
InterpolationMode.HighQualityBicubic;
grPhoto.DrawImage(imgPhoto,
new Rectangle(destX, destY, destWidth, destHeight),
new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight),
GraphicsUnit.Pixel);
grPhoto.Dispose();
return bmPhoto;
}
I use the following method to calculate the desired image size:
using System.Drawing;
public static Size ResizeKeepAspect(this Size src, int maxWidth, int maxHeight, bool enlarge = false)
{
maxWidth = enlarge ? maxWidth : Math.Min(maxWidth, src.Width);
maxHeight = enlarge ? maxHeight : Math.Min(maxHeight, src.Height);
decimal rnd = Math.Min(maxWidth / (decimal)src.Width, maxHeight / (decimal)src.Height);
return new Size((int)Math.Round(src.Width * rnd), (int)Math.Round(src.Height * rnd));
}
This puts the problem of aspect ratio and dimensions in a separate method.
What does the parameter bool enlarge = false ?
usually you do only shrinking of images because enlarging means quality loss - so I added this optional parameter if you want to do it anyway
To get a faster result, the function that obtains the size could be found in resultSize:
Size original = new Size(640, 480);
int maxSize = 100;
float percent = (new List<float> { (float)maxSize / (float)original.Width , (float)maxSize / (float)original.Height }).Min();
Size resultSize = new Size((int)Math.Floor(original.Width * percent), (int)Math.Floor(original.Height * percent));
Uses Linq to minimize variable and recalculations, as well as unnecesary if/else statements
Just generalizing it down to aspect ratios and sizes, image stuff can be done outside of this function
public static d.RectangleF ScaleRect(d.RectangleF dest, d.RectangleF src,
bool keepWidth, bool keepHeight)
{
d.RectangleF destRect = new d.RectangleF();
float sourceAspect = src.Width / src.Height;
float destAspect = dest.Width / dest.Height;
if (sourceAspect > destAspect)
{
// wider than high keep the width and scale the height
destRect.Width = dest.Width;
destRect.Height = dest.Width / sourceAspect;
if (keepHeight)
{
float resizePerc = dest.Height / destRect.Height;
destRect.Width = dest.Width * resizePerc;
destRect.Height = dest.Height;
}
}
else
{
// higher than wide – keep the height and scale the width
destRect.Height = dest.Height;
destRect.Width = dest.Height * sourceAspect;
if (keepWidth)
{
float resizePerc = dest.Width / destRect.Width;
destRect.Width = dest.Width;
destRect.Height = dest.Height * resizePerc;
}
}
return destRect;
}
I'm going to add my code here too. This code will allow you resize an image with or without the aspect ratio being enforced or to resize with padding. This is a modified version of egrunin's code.
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
namespace ConsoleApplication1
{
public class Program
{
public static void Main(string[] args)
{
var path = Directory.GetParent(Directory.GetCurrentDirectory()).Parent.FullName;
ResizeImage(path, "large.jpg", path, "new.jpg", 100, 100, true, true);
}
/// <summary>Resizes an image to a new width and height.</summary>
/// <param name="originalPath">The folder which holds the original image.</param>
/// <param name="originalFileName">The file name of the original image.</param>
/// <param name="newPath">The folder which will hold the resized image.</param>
/// <param name="newFileName">The file name of the resized image.</param>
/// <param name="maximumWidth">When resizing the image, this is the maximum width to resize the image to.</param>
/// <param name="maximumHeight">When resizing the image, this is the maximum height to resize the image to.</param>
/// <param name="enforceRatio">Indicates whether to keep the width/height ratio aspect or not. If set to false, images with an unequal width and height will be distorted and padding is disregarded. If set to true, the width/height ratio aspect is maintained and distortion does not occur.</param>
/// <param name="addPadding">Indicates whether fill the smaller dimension of the image with a white background. If set to true, the white padding fills the smaller dimension until it reach the specified max width or height. This is used for maintaining a 1:1 ratio if the max width and height are the same.</param>
private static void ResizeImage(string originalPath, string originalFileName, string newPath, string newFileName, int maximumWidth, int maximumHeight, bool enforceRatio, bool addPadding)
{
var image = Image.FromFile(originalPath + "\\" + originalFileName);
var imageEncoders = ImageCodecInfo.GetImageEncoders();
EncoderParameters encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, 100L);
var canvasWidth = maximumWidth;
var canvasHeight = maximumHeight;
var newImageWidth = maximumWidth;
var newImageHeight = maximumHeight;
var xPosition = 0;
var yPosition = 0;
if (enforceRatio)
{
var ratioX = maximumWidth / (double)image.Width;
var ratioY = maximumHeight / (double)image.Height;
var ratio = ratioX < ratioY ? ratioX : ratioY;
newImageHeight = (int)(image.Height * ratio);
newImageWidth = (int)(image.Width * ratio);
if (addPadding)
{
xPosition = (int)((maximumWidth - (image.Width * ratio)) / 2);
yPosition = (int)((maximumHeight - (image.Height * ratio)) / 2);
}
else
{
canvasWidth = newImageWidth;
canvasHeight = newImageHeight;
}
}
var thumbnail = new Bitmap(canvasWidth, canvasHeight);
var graphic = Graphics.FromImage(thumbnail);
if (enforceRatio && addPadding)
{
graphic.Clear(Color.White);
}
graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphic.SmoothingMode = SmoothingMode.HighQuality;
graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphic.CompositingQuality = CompositingQuality.HighQuality;
graphic.DrawImage(image, xPosition, yPosition, newImageWidth, newImageHeight);
thumbnail.Save(newPath + "\\" + newFileName, imageEncoders[1], encoderParameters);
}
}
}
Here's a less specific extension method that works with Image rather than doing the loading and saving for you. It also allows you to specify interpolation method and correctly renders edges when you use NearestNeighbour interpolation.
The image will be rendered within the bounds of the area you specify so you always know your output width and height. e.g:
namespace YourApp
{
#region Namespaces
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
#endregion
/// <summary>Generic helper functions related to graphics.</summary>
public static class ImageExtensions
{
/// <summary>Resizes an image to a new width and height value.</summary>
/// <param name="image">The image to resize.</param>
/// <param name="newWidth">The width of the new image.</param>
/// <param name="newHeight">The height of the new image.</param>
/// <param name="mode">Interpolation mode.</param>
/// <param name="maintainAspectRatio">If true, the image is centered in the middle of the returned image, maintaining the aspect ratio of the original image.</param>
/// <returns>The new image. The old image is unaffected.</returns>
public static Image ResizeImage(this Image image, int newWidth, int newHeight, InterpolationMode mode = InterpolationMode.Default, bool maintainAspectRatio = false)
{
Bitmap output = new Bitmap(newWidth, newHeight, image.PixelFormat);
using (Graphics gfx = Graphics.FromImage(output))
{
gfx.Clear(Color.FromArgb(0, 0, 0, 0));
gfx.InterpolationMode = mode;
if (mode == InterpolationMode.NearestNeighbor)
{
gfx.PixelOffsetMode = PixelOffsetMode.HighQuality;
gfx.SmoothingMode = SmoothingMode.HighQuality;
}
double ratioW = (double)newWidth / (double)image.Width;
double ratioH = (double)newHeight / (double)image.Height;
double ratio = ratioW < ratioH ? ratioW : ratioH;
int insideWidth = (int)(image.Width * ratio);
int insideHeight = (int)(image.Height * ratio);
gfx.DrawImage(image, new Rectangle((newWidth / 2) - (insideWidth / 2), (newHeight / 2) - (insideHeight / 2), insideWidth, insideHeight));
}
return output;
}
}
}
Note: this code resizes and removes everything outside the aspect ratio instead of padding it..
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
namespace MyPhotos.Common
{
public class ThumbCreator
{
public enum VerticalAlign
{
Top,
Middle,
Bottom
}
public enum HorizontalAlign
{
Left,
Middle,
Right
}
public void Convert(string sourceFile, string targetFile, ImageFormat targetFormat, int height, int width, VerticalAlign valign, HorizontalAlign halign)
{
using (Image img = Image.FromFile(sourceFile))
{
using (Image targetImg = Convert(img, height, width, valign, halign))
{
string directory = Path.GetDirectoryName(targetFile);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
if (targetFormat == ImageFormat.Jpeg)
{
SaveJpeg(targetFile, targetImg, 100);
}
else
{
targetImg.Save(targetFile, targetFormat);
}
}
}
}
/// <summary>
/// Saves an image as a jpeg image, with the given quality
/// </summary>
/// <param name="path">Path to which the image would be saved.</param>
// <param name="quality">An integer from 0 to 100, with 100 being the
/// highest quality</param>
public static void SaveJpeg(string path, Image img, int quality)
{
if (quality < 0 || quality > 100)
throw new ArgumentOutOfRangeException("quality must be between 0 and 100.");
// Encoder parameter for image quality
EncoderParameter qualityParam =
new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality);
// Jpeg image codec
ImageCodecInfo jpegCodec = GetEncoderInfo("image/jpeg");
EncoderParameters encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = qualityParam;
img.Save(path, jpegCodec, encoderParams);
}
/// <summary>
/// Returns the image codec with the given mime type
/// </summary>
private static ImageCodecInfo GetEncoderInfo(string mimeType)
{
// Get image codecs for all image formats
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
// Find the correct image codec
for (int i = 0; i < codecs.Length; i++)
if (codecs[i].MimeType == mimeType)
return codecs[i];
return null;
}
public Image Convert(Image img, int height, int width, VerticalAlign valign, HorizontalAlign halign)
{
Bitmap result = new Bitmap(width, height);
using (Graphics g = Graphics.FromImage(result))
{
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
float ratio = (float)height / (float)img.Height;
int temp = (int)((float)img.Width * ratio);
if (temp == width)
{
//no corrections are needed!
g.DrawImage(img, 0, 0, width, height);
return result;
}
else if (temp > width)
{
//den e för bred!
int overFlow = (temp - width);
if (halign == HorizontalAlign.Middle)
{
g.DrawImage(img, 0 - overFlow / 2, 0, temp, height);
}
else if (halign == HorizontalAlign.Left)
{
g.DrawImage(img, 0, 0, temp, height);
}
else if (halign == HorizontalAlign.Right)
{
g.DrawImage(img, -overFlow, 0, temp, height);
}
}
else
{
//den e för hög!
ratio = (float)width / (float)img.Width;
temp = (int)((float)img.Height * ratio);
int overFlow = (temp - height);
if (valign == VerticalAlign.Top)
{
g.DrawImage(img, 0, 0, width, temp);
}
else if (valign == VerticalAlign.Middle)
{
g.DrawImage(img, 0, -overFlow / 2, width, temp);
}
else if (valign == VerticalAlign.Bottom)
{
g.DrawImage(img, 0, -overFlow, width, temp);
}
}
}
return result;
}
}
}
// This allows us to resize the image. It prevents skewed images and
// also vertically long images caused by trying to maintain the aspect
// ratio on images who's height is larger than their width
public void ResizeImage(string OriginalFile, string NewFile, int NewWidth, int MaxHeight, bool OnlyResizeIfWider)
{
System.Drawing.Image FullsizeImage = System.Drawing.Image.FromFile(OriginalFile);
// Prevent using images internal thumbnail
FullsizeImage.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipNone);
FullsizeImage.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipNone);
if (OnlyResizeIfWider)
{
if (FullsizeImage.Width <= NewWidth)
{
NewWidth = FullsizeImage.Width;
}
}
int NewHeight = FullsizeImage.Height * NewWidth / FullsizeImage.Width;
if (NewHeight > MaxHeight)
{
// Resize with height instead
NewWidth = FullsizeImage.Width * MaxHeight / FullsizeImage.Height;
NewHeight = MaxHeight;
}
System.Drawing.Image NewImage = FullsizeImage.GetThumbnailImage(NewWidth, NewHeight, null, IntPtr.Zero);
// Clear handle to original file so that we can overwrite it if necessary
FullsizeImage.Dispose();
// Save resized picture
NewImage.Save(NewFile);
}
I created a extension method that is much simpiler than the answers that are posted.
and the aspect ratio is applied without cropping the image.
public static Image Resize(this Image image, int width, int height) {
var scale = Math.Min(height / (float)image.Height, width / (float)image.Width);
return image.GetThumbnailImage((int)(image.Width * scale), (int)(image.Height * scale), () => false, IntPtr.Zero);
}
Example usage:
using (var img = Image.FromFile(pathToOriginalImage)) {
using (var thumbnail = img.Resize(60, 60)){
// Here you can do whatever you need to do with thumnail
}
}
Maintain aspect Ration and eliminate letterbox and Pillarbox.
static Image FixedSize(Image imgPhoto, int Width, int Height)
{
int sourceWidth = imgPhoto.Width;
int sourceHeight = imgPhoto.Height;
int X = 0;
int Y = 0;
float nPercent = 0;
float nPercentW = 0;
float nPercentH = 0;
nPercentW = ((float)Width / (float)sourceWidth);
nPercentH = ((float)Height / (float)sourceHeight);
if (nPercentH < nPercentW)
{
nPercent = nPercentH;
}
else
{
nPercent = nPercentW;
}
int destWidth = (int)(sourceWidth * nPercent);
int destHeight = (int)(sourceHeight * nPercent);
Bitmap bmPhoto = new Bitmap(destWidth, destHeight, PixelFormat.Format24bppRgb);
bmPhoto.SetResolution(imgPhoto.HorizontalResolution,
imgPhoto.VerticalResolution);
Graphics grPhoto = Graphics.FromImage(bmPhoto);
grPhoto.DrawImage(imgPhoto,
new Rectangle(X, Y, destWidth, destHeight),
new Rectangle(X, Y, sourceWidth, sourceHeight),
GraphicsUnit.Pixel);
grPhoto.Dispose();
return bmPhoto;
}
public static void resizeImage_n_save(Stream sourcePath, string targetPath, int requiredSize)
{
using (var image = System.Drawing.Image.FromStream(sourcePath))
{
double ratio = 0;
var newWidth = 0;
var newHeight = 0;
double w = Convert.ToInt32(image.Width);
double h = Convert.ToInt32(image.Height);
if (w > h)
{
ratio = h / w * 100;
newWidth = requiredSize;
newHeight = Convert.ToInt32(requiredSize * ratio / 100);
}
else
{
ratio = w / h * 100;
newHeight = requiredSize;
newWidth = Convert.ToInt32(requiredSize * ratio / 100);
}
// var newWidth = (int)(image.Width * scaleFactor);
// var newHeight = (int)(image.Height * scaleFactor);
var thumbnailImg = new Bitmap(newWidth, newHeight);
var thumbGraph = Graphics.FromImage(thumbnailImg);
thumbGraph.CompositingQuality = CompositingQuality.HighQuality;
thumbGraph.SmoothingMode = SmoothingMode.HighQuality;
thumbGraph.InterpolationMode = InterpolationMode.HighQualityBicubic;
var imageRectangle = new Rectangle(0, 0, newWidth, newHeight);
thumbGraph.DrawImage(image, imageRectangle);
thumbnailImg.Save(targetPath, image.RawFormat);
//var img = FixedSize(image, requiredSize, requiredSize);
//img.Save(targetPath, image.RawFormat);
}
}
I just wrote this cos none of the answers already here were simple enough. You can replace the hardcoded 128 for whatever you want or base them off the size of the original image. All i wanted was to rescale the image into a 128x128 image, keeping the aspect ratio and centering the result in the new image.
private Bitmap CreateLargeIconForImage(Bitmap src)
{
Bitmap bmp = new Bitmap(128, 128);
Graphics g = Graphics.FromImage(bmp);
float scale = Math.Max((float)src.Width / 128.0f, (float)src.Height / 128.0f);
PointF p = new PointF(128.0f - ((float)src.Width / scale), 128.0f - ((float)src.Height / scale));
SizeF size = new SizeF((float)src.Width / scale, (float)src.Height / scale);
g.DrawImage(src, new RectangleF(p, size));
return bmp;
}
I know this is an older thread. However, this is the first result in a Google search on the topic.
None of the answers fit my requirement. So, here's a solution I put together by understanding the older solutions, but limiting the result image size to the most suitable height and width.
double ratioW = (double)desiredWidthPixels / (double)originalImage.Width;
double ratioH = (double)desiredHeightPixels / (double)originalImage.Height;
double ratio = ratioW < ratioH ? ratioW : ratioH;
int suitableWidth = (int)(originalImage.Width * ratio);
int suitableHeight = (int)(originalImage.Height * ratio);
var resizedPhoto = new Bitmap((int)suitableWidth, (int)suitableHeight);
var graphicsSurface = Graphics.FromImage(resizedPhoto);
graphicsSurface.DrawImage(originalImage, new RectangleF(new PointF(0,0), new SizeF(suitableWidth, suitableHeight)));

Categories