C# WPF Picture ratio vertical and/or horizontal - c#

Hey all I found this image resize code here and I am trying to adapt it to my current code.
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);
}
And my current code:
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string path = value as string;
if (path != null) {
//create new stream and create bitmap frame
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = new FileStream(path, FileMode.Open, FileAccess.Read);
//load the image now so we can immediately dispose of the stream
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
//clean up the stream to avoid file access exceptions when attempting to delete images
bitmapImage.StreamSource.Dispose();
return bitmapImage;
} else {
return DependencyProperty.UnsetValue;
}
}
Problem being is that the resizeImage code uses Image and my current code uses BitmapImage.
I've been trying to find ways to convert either/or to one format or the other but I do not seem to be successful in doing that.
Not sure if the resizeImage is what I am needing since I am unable to run it as is but all I am looking to do is detect if the image is horizontal or vertical. If its vertical then resize it (either being bigger or smaller) so that it fits into my designated area. Likewise, the horizontal would be the same way as the vertical.

There are many ways to convert sizes, but I wanted to answer your question directly since there's not much on the web about converting from a BitmapSource to a System.Drawing.Bitmap. (There are many articles on going the other way).
This function will convert any WPF BitmapSource -- including BitmapImage, which is a BitmapSource -- to a System.Drawing.Bitmap:
private System.Drawing.Bitmap ConvertBitmapSourceToDrawingBitmap(BitmapSource image)
{
int width = Convert.ToInt32(image.Width);
int height = Convert.ToInt32(image.Height);
int stride = Convert.ToInt32(width * ((image.Format.BitsPerPixel + 7) / 8) + 0.5);
byte[] bits = new byte[height * stride];
image.CopyPixels(bits, stride, 0);
System.Drawing.Bitmap bitmap = null;
unsafe
{
fixed (byte* pBits = bits)
{
IntPtr ptr = new IntPtr(pBits);
bitmap = new System.Drawing.Bitmap(width, height, stride, System.Drawing.Imaging.PixelFormat.Format32bppPArgb, ptr);
}
}
return bitmap;
}
To test it, I used this code:
System.Windows.Media.Imaging.BitmapSource bitmapSource;
using (System.IO.Stream stm = System.IO.File.Open("c:\\foo_in.png", System.IO.FileMode.Open, System.IO.FileAccess.Read))
{
// Since we're not specifying a System.Windows.Media.Imaging.BitmapCacheOption, the pixel format
// will be System.Windows.Media.PixelFormats.Pbgra32.
bitmapSource = System.Windows.Media.Imaging.BitmapFrame.Create(
stm,
System.Windows.Media.Imaging.BitmapCreateOptions.None,
System.Windows.Media.Imaging.BitmapCacheOption.OnLoad);
}
System.Drawing.Bitmap bmp = ConvertBitmapSourceToDrawingBitmap(bitmapSource);
bmp.Save("c:\\foo_out.png", System.Drawing.Imaging.ImageFormat.Png);

Related

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)));

Reduce bitmap image physical size?

I am loading images onto an excel page, once done this excel is around 48,284 KB This is to large and affects the download speed and is not efficient to what we are trying to achieve.
I am trying to reduce this Excel file size as much as possible and think that reducing the image sizes would do the trick as the excel file without images is around 1000 kb.
This is what i have tried so far with no affect:
public Image ReduceImageSize(Image img)
{
float iwidth = 150;
float iheight = 150;
var brush = new SolidBrush(Color.Black);
var Resizedimage = new Bitmap(img);
float scale = Math.Min(iwidth / Resizedimage.Width, iheight / Resizedimage.Height);
var graph = Graphics.FromImage(Resizedimage);
graph.InterpolationMode = InterpolationMode.Low;
graph.CompositingQuality = CompositingQuality.Default;
graph.SmoothingMode = SmoothingMode.None;
var scaleWidth = (int)(Resizedimage.Width * scale);
var scaleHeight = (int)(Resizedimage.Height * scale);
graph.FillRectangle(brush, new RectangleF(0, 0, iwidth, iheight));
graph.DrawImage(Resizedimage, new Rectangle(((int)iwidth - scaleWidth) / 2, ((int)iheight - scaleHeight) / 2, scaleWidth, scaleHeight));
return Resizedimage;
}
At this point i'm looking for any way to reduce the size if it involves losing some quality or reducing the images dimensions.
Please help.
You made Resizedimage the same size as img.
Use the following code to fix the result image size:
var Resizedimage = new Bitmap(iwidth,iheight);
An example resizing an image keeping the aspect ratio:
Image img = Image.FromFile(#"c:\temp\1.jpg");
Bitmap resizedImg = new Bitmap(150, 150);
double ratioX = (double)resizedImg.Width / (double)img.Width;
double ratioY = (double)resizedImg.Height / (double)img.Height;
double ratio = ratioX < ratioY ? ratioX : ratioY;
int newHeight = Convert.ToInt32(img.Height * ratio);
int newWidth = Convert.ToInt32(img.Width * ratio);
using (Graphics g = Graphics.FromImage(resizedImg))
{
g.DrawImage(img, 0, 0, newWidth, newHeight);
}
resizedImg.Save(#"c:\temp\2.jpg");

Grey and unsharp images when resizing using GDI+

I'm using asp.net mvc 3 to stream resized images. But the output of the image is greyish and blury eventhough I've set smoothingmode and interpolationmode to highbiqubic.
public ActionResult ImageTEST(int fileID, int width, int height)
{
var file = _fileRep.GetFile(fileID);
byte[] newFile;
float ratioX = (float)width / (float)file.Width;
float ratioY = (float)height / (float)file.Height;
float ratio = Math.Min(ratioX, ratioY);
int newWidth = (int)(file.Width * ratio);
int newHeight = (int)(file.Height * ratio);
using (var resizedImage = new Bitmap(newWidth, newHeight))
{
using (var source = new Bitmap(new MemoryStream(file.FileContent)))
{
using (var g = Graphics.FromImage(resizedImage))
{
g.SmoothingMode = SmoothingMode.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(source, 0, 0, newWidth, newHeight);
}
}
using (var ms = new MemoryStream())
{
resizedImage.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
newFile = ms.ToArray();
}
}
return new FileContentResult(newFile, "image/jpeg");
}
Result:
The right one is the exakt same picture but resized in photoshop.
How can I tune this to make quality much better?
First, try to save in a higher quality.
EncoderParameters ep = new EncoderParameters();
ep.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)100);
foo.Save(filename, ici, ep);
If that is not satisfiable, you may need to use other libraries such as Emgu cv.
The grey problem may because that the color space (AdobeRGB or sRGB) of original image and the one you saved are not the same.

C# Image Resizer with Canvas Handler

I'm incredibly new to C# (just started today)
I need to be able to make a C# Image resizer with a canvas handler. For example a 500 x 500 image needs to retain its aspect ration. it will be getting resized to 1024x500. To do this it will remain 500x500 but then fill the rest of the space with white space (the canvas).
I will also be resizing the same original image to 300 x 500, where the image will again retain its 1:1 ration and be resized to 300x300 and the remaining space again used as canvas white space.
Can anybody help me to produce a C# console application for this, that I can understand?
Here is what I have managed to find that I could reasonably understand (due to nice commenting).
What I find with code is that I can read it, but when it comes to me actually writing some I just fall apart. I mainly do HTML and CSS. Starting to branch out into JQuery and C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Drawing.Imaging;
namespace ImageResizer
{
class ImageResize
{
static void Main(string[] args)
{
}
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);
}
}
}
Try To Go For This>>
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 + width + "." + originalFilename, info[1],
encoderParameters);
}

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