Resize image width in c# but not the height - c#

How do you resize the width of a image in C# without resizing the height using image.resize()
When I do it this way:
image.Resize(width: 800, preserveAspectRatio: true,preventEnlarge:true);
This is the full code:
var imagePath = "";
var newFileName = "";
var imageThumbPath = "";
WebImage image = null;
image = WebImage.GetImageFromRequest();
if (image != null)
{
newFileName = Path.GetFileName(image.FileName);
imagePath = #"pages/"+newFileName;
image.Resize(width:800, preserveAspectRatio:true, preventEnlarge:true);
image.Save(#"~/images/" + imagePath);
imageThumbPath = #"pages/thumbnail/"+newFileName;
image.Resize(width: 150, height:150, preserveAspectRatio:true, preventEnlarge:true);
image.Save(#"~/images/" + imageThumbPath);
}
I get this error message:
No overload for method 'Resize' takes 3 arguments

The documentation is garbage, so I peeked at the source code. The logic they are using is to look at the values passed for height and width and compute aspect ratios for each comparing the new value to the current value. Whichever value (height or width) has the greater aspect ratio gets its value computed from the other value. Here's the relevant snippet:
double hRatio = (height * 100.0) / image.Height;
double wRatio = (width * 100.0) / image.Width;
if (hRatio > wRatio)
{
height = (int)Math.Round((wRatio * image.Height) / 100);
}
else if (hRatio < wRatio)
{
width = (int)Math.Round((hRatio * image.Width) / 100);
}
So, what that means is that, if you don't want to compute the height value yourself, just pass in a height value that is very large.
image.Resize(800, 100000, true, true);
This will cause hRatio to be larger than wRatio and then height will be computed based on width.
Since you have preventEnlarge set to true, you could just pass image.Height in.
image.Resize(800, image.Height, true, true);
Of course, it's not difficult to just compute height yourself:
int width = 800;
int height = (int)Math.Round(((width * 1.0) / image.Width) * image.Height);
image.Resize(width, height, false, true);

Solution applicable for Winform
Using this function :
public static Image ScaleImage(Image image, int maxWidth)
{
var newImage = new Bitmap(newWidth, image.Height);
Graphics.FromImage(newImage).DrawImage(image, 0, 0, newWidth, image.Height);
return newImage;
}
Usage :
Image resized_image = ScaleImage(image, 800);

Related

actual dimensions of background image with "zoom" layout

With "Zoom" layout background image actual width and height do not always match the width and height of the containing control, as opposed to "Stretch" layout. I am wondering if there is a property or something in winforms to retrieve current image rendered dimensions without doing any math?
This returns the Rectangle pixels from a PictureBox for any of its SizeModes.
But yes, it does take some math for Zoom mode.
It can be adapted easily to the corresponding BackgroudImageLayout values:
Rectangle ImageArea(PictureBox pbox)
{
Size si = pbox.Image.Size;
Size sp = pbox.ClientSize;
if (pbox.SizeMode == PictureBoxSizeMode.StretchImage) return pbox.ClientRectangle;
if (pbox.SizeMode == PictureBoxSizeMode.Normal ||
pbox.SizeMode == PictureBoxSizeMode.AutoSize) return new Rectangle(Point.Empty, si);
if (pbox.SizeMode == PictureBoxSizeMode.CenterImage)
return new Rectangle(new Point( (sp.Width - si.Width) / 2,
(sp.Height - si.Height) / 2), si);
// PictureBoxSizeMode.Zoom
float ri = 1f * si.Width / si.Height;
float rp = 1f * sp.Width / sp.Height;
if (rp > ri)
{
int width = si.Width * sp.Height / si.Height;
int left = (sp.Width - width) / 2;
return new Rectangle(left, 0, width, sp.Height);
}
else
{
int height = si.Height * sp.Width / si.Width;
int top = (sp.Height - height) / 2;
return new Rectangle(0, top, sp.Width, height);
}
}

Calculate Width and Height respecting Aspect Ratio for any given Max Width and Max Height

I was asked to resize any picture to its equivalent thumbnail while respecting the original aspect ratio of the picture.
So far, I've only managed to accomplish this while only passing the max. width, like follows:
public static Size GetSizeAdjustedToAspectRatio(int sourceWidth, int sourceHeight, int dWidth, int dHeight)
{
bool isLandscape = sourceWidth > sourceHeight;
int fixedSize = dWidth;
double aspectRatio = (double)sourceWidth / (double)sourceHeight; ;
if (isLandscape)
return new Size(fixedSize, (int)((fixedSize / aspectRatio) + 0.5));
else
return new Size((int)((fixedSize * aspectRatio) + 0.5), fixedSize);
}
I've tried several ways of calculating it so that it will accept any given max. height and max. width in order to keep the original aspect ratio on the end result picture.
Here:
public static Size GetSizeAdjustedToAspectRatio(int sourceWidth, int sourceHeight, int dWidth, int dHeight) {
bool isLandscape = sourceWidth > sourceHeight;
int newHeight;
int newWidth;
if (isLandscape) {
newHeight = dWidth * sourceHeight / sourceWidth;
newWidth = dWidth;
}
else {
newWidth = dHeight * sourceWidth / sourceHeight;
newHeight = dHeight;
}
return new Size(newWidth, newHeight);
}
In landscape, you set the thumbnail width to the destination box width and height is found by rule of three. In portrait, you set the thumbnail height to the destination box height and calculate width.

How to resize an image maintaining the aspect ratio in C#

I need to know of a way to resize an image to fit in a box without the image stretching too much. The box has set width and height and I want the image to fill as much of the box as possible but maintain the aspect ratio it originally had.
//calculate the ratio
double dbl = (double)image.Width / (double)image.Height;
//set height of image to boxHeight and check if resulting width is less than boxWidth,
//else set width of image to boxWidth and calculate new height
if( (int)((double)boxHeight * dbl) <= boxWidth )
{
resizedImage = new Bitmap(original, (int)((double)boxHeight * dbl), boxHeight);
}
else
{
resizedImage = new Bitmap(original, boxWidth, (int)((double)boxWidth / dbl) );
}
The formula for scaling with the same ratio is:
newWidth = (int)((double)boxHeight * dbl)
or
newHeight = (int)((double)boxWidth / dbl)
A Math.Max could simplify the problem:
double ratio = Math.Max((double)image.width / (double)box.width , (double)image.height / (double)box.height);
image.width = (int)(image.width / ratio);
image.height = (int)(image.height / ratio);
Bitmap original,resizedImage;
try
{
using (FileStream fs = new System.IO.FileStream(imageLabel.Text, System.IO.FileMode.Open))
{
original = new Bitmap(fs);
}
int rectHeight = BOXWIDTH;
int rectWidth = BOXWIDTH;
//if the image is squared set it's height and width to the smallest of the desired dimensions (our box). In the current example rectHeight<rectWidth
if (original.Height == original.Width)
{
resizedImage = new Bitmap(original, rectHeight, rectHeight);
}
else
{
//calculate aspect ratio
float aspect = original.Width / (float)original.Height;
int newWidth, newHeight;
//calculate new dimensions based on aspect ratio
newWidth = (int)(rectWidth * aspect);
newHeight = (int)(newWidth / aspect);
//if one of the two dimensions exceed the box dimensions
if (newWidth > rectWidth || newHeight > rectHeight)
{
//depending on which of the two exceeds the box dimensions set it as the box dimension and calculate the other one based on the aspect ratio
if (newWidth > newHeight)
{
newWidth = rectWidth;
newHeight = (int)(newWidth / aspect);
}
else
{
newHeight = rectHeight;
newWidth = (int)(newHeight * aspect);
}
}
resizedImage = new Bitmap(original, newWidth, newHeight);
}
}
catch (Exception ex)
{
MessageBox.Show( ex.Message);
}
}
The accepted answer probably works but I stared at it for a long time and could not understand exactly how, so I thought I would share what I came up with: shrink height first, then check width and shrink again if needed, always preserving the aspect ratio.
I used SixLabors.ImageSharp because it's compatible with Linux, but you can easily swap out the resizing function once you have the newHeight and newWidth.
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
public class ImageSharpService : IImageService
{
public async Task ShrinkAndSaveAsync(Stream stream, string savePath, int maxHeight, int maxWidth)
{
using Image image = Image.Load(stream);
// check if resize is needed
if (ResizeNeeded(image.Height, image.Width, maxHeight, maxWidth, out int newHeight, out int newWidth))
// swap this part out if not using ImageSharp
image.Mutate(x => x.Resize(new ResizeOptions
{
Size = new Size(newWidth, newHeight)
}));
await image.SaveAsync(savePath);
}
private bool ResizeNeeded(int height, int width, int maxHeight, int maxWidth, out int newHeight, out int newWidth)
{
// first use existing dimensions
newHeight = height;
newWidth = width;
// if below max on both then do nothing
if (height <= maxHeight && width <= maxWidth) return false;
// naively check height first
if (height > maxHeight)
{
// set down to max height
newHeight = maxHeight;
// calculate what new width would be
var heightReductionRatio = maxHeight / height; // ratio of maxHeight:image.Height
newWidth = width * heightReductionRatio; // apply ratio to image.Width
}
// does width need to be reduced?
// (this will also re-check width after shrinking by height dimension)
if (newWidth > maxWidth)
{
// if so, re-calculate height to fit for maxWidth
var widthReductionRatio = maxWidth / newWidth; // ratio of maxWidth:newWidth (height reduction ratio may have been applied)
newHeight = maxHeight * widthReductionRatio; // apply new ratio to maxHeight to get final height
newWidth = maxWidth;
}
// if we got here, resize needed and out vars have been set
return true;
}
}
I believe that if you only change the height or only the width it will remain in better ratios and the width/height will change with it. So you can try that

C# : How to resize image proportionately with max height

I need to resize my image proportionately without changing aspect ratio.I have the code to resize with fixed hight and width but I need to resize image proportionately with max height(say 600 pixels). How can I modify the code to suit my requirement?
public static void Main()
{
var image = Image.FromFile(#"c:\logo.png");
var newImage = ScaleImage(image, 300, 400);
newImage.Save(#"c:\test.png", ImageFormat.Png);
}
public static Image ScaleImage(Image image, int maxWidth, int maxHeight)
{
var ratioX = (double)maxWidth / image.Width;
var ratioY = (double)maxHeight / image.Height;
var ratio = Math.Min(ratioX, ratioY);
var newWidth = (int)(image.Width * ratio);
var newHeight = (int)(image.Height * ratio);
var newImage = new Bitmap(newWidth, newHeight);
Graphics.FromImage(newImage).DrawImage(image, 0, 0, newWidth, newHeight);
return newImage;
}
Please provide your valuable thoughts.
This almost feels to easy and I feel I'm missing something. Anyway, won't that do the trick?
public static Image ScaleImage(Image image, int maxHeight)
{
var ratio = (double)maxHeight / image.Height;
var newWidth = (int)(image.Width * ratio);
var newHeight = (int)(image.Height * ratio);
var newImage = new Bitmap(newWidth, newHeight);
using (var g = Graphics.FromImage(newImage))
{
g.DrawImage(image, 0, 0, newWidth, newHeight);
}
return newImage;
}
Use the following function
public Bitmap ProportionallyResizeBitmapByHeight(Bitmap imgToResize, int height)
{
int sourceWidth = imgToResize.Width;
int sourceHeight = imgToResize.Height;
float scale = 0;
scale = (height / (float)sourceHeight);
int destWidth = (int)(sourceWidth * scale);
int destHeight = (int)(sourceHeight * scale);
Bitmap result = new Bitmap(destWidth, destHeight);
result.SetResolution(imgToResize.HorizontalResolution, imgToResize.VerticalResolution);
Graphics g = Graphics.FromImage(result);
g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
g.Dispose();
return result;
}
Well, thinking through the process:
if you have an image that 800 x 600 in size and want to resize it to newWidth x 400 height (plus whatever the respective newWidth will be), you get the ratio by dividing the newHeight (maxHeight in your case) with 600 and multiply 800 with this ratio, right?
So, in this case you need to change maxWidth and maxHeight to optional parameters (say 800 by 600) to give yourself some dynamism and get the following:
public static Image ScaleImage(Image image, int maxWidth = 800, int maxHeight = 600)
{
int newWidth;
int newHeight;
double ratio = image.Height / image.Width;
if(maxHeight != 600) {
newWidth = image.Width * ratio;
newHeight = maxHeight;
}
Bitmap newImage = new Bitmap(newWidth, newHeight);
Graphics.FromImage(newImage).DrawImage(image, 0, 0, newWidth, newHeight);
return newImage;
}
I hope this helps. I didn't test it, but I've rewritten my VB code, so allegedly it should be okay...
There's also a ResizeStream method here: http://forums.asp.net/t/1576697.aspx/1 that you might find useful.
If you want to keep image quality, you can use the CompositingQuality and SmoothingMode, etc. variables.
100% Worked
private static BitmapFrame CreateResizedImage(ImageSource source, int Max_width, int Max_height, int margin)
{
float scaleHeight = (float)Max_width / (float)source.Height;
float scaleWidth = (float)Max_height / (float)source.Width;
float scale = Math.Min(scaleHeight, scaleWidth);
int width = (int)(source.Width * scale);
int height = (int)(source.Height * scale);
var rect = new Rect(margin, margin, width - margin * 2, height - margin * 2);
var group = new DrawingGroup();
RenderOptions.SetBitmapScalingMode(group, BitmapScalingMode.HighQuality);
group.Children.Add(new ImageDrawing(source, rect));
var drawingVisual = new DrawingVisual();
using (var drawingContext = drawingVisual.RenderOpen())
drawingContext.DrawDrawing(group);
var resizedImage = new RenderTargetBitmap(
width, height, // Resized dimensions
96, 96, // Default DPI values
PixelFormats.Default); // Default pixel format
resizedImage.Render(drawingVisual);
return BitmapFrame.Create(resizedImage);
}
//--------Main------------//
BitmapImage imageSource = (BitmapImage)ImagePreview.Source;
var NewImage= CreateResizedImage(imageSource , 300, 300, 0);

ASP.Net MVC Image Upload Resizing by downscaling or padding

A user will be able to upload an image. If the image is greater than a set size I want to downsize it to that size. Obviously it doesn't have to match exactly due to ratios, the width would be the key size so the height would be variable.
If the image is smaller than the set size I would like to create a new image to the set size with a background of a defined colour and then centre the uploaded image into it therefore the result is the original with paddded colour.
Any code examples or links greatly appreciated
Here's a snippet of code I quickly knocked up for resizing it based on the width. I'm sure you could figure out how to add a background color to the Bitmap. It's not complete code but just an idea of how to do things.
public static void ResizeLogo(string originalFilename, string resizeFilename)
{
Image imgOriginal = Image.FromFile(originalFilename);
//pass in whatever value you want for the width (180)
Image imgActual = ScaleBySize(imgOriginal, 180);
imgActual.Save(resizeFilename);
imgActual.Dispose();
}
public static Image ScaleBySize(Image imgPhoto, int size)
{
int logoSize = size;
float sourceWidth = imgPhoto.Width;
float sourceHeight = imgPhoto.Height;
float destHeight = 0;
float destWidth = 0;
int sourceX = 0;
int sourceY = 0;
int destX = 0;
int destY = 0;
// Resize Image to have the height = logoSize/2 or width = logoSize.
// Height is greater than width, set Height = logoSize and resize width accordingly
if (sourceWidth > (2 * sourceHeight))
{
destWidth = logoSize;
destHeight = (float)(sourceHeight * logoSize / sourceWidth);
}
else
{
int h = logoSize / 2;
destHeight = h;
destWidth = (float)(sourceWidth * h / sourceHeight);
}
// Width is greater than height, set Width = logoSize and resize height accordingly
Bitmap bmPhoto = new Bitmap((int)destWidth, (int)destHeight,
PixelFormat.Format32bppPArgb);
bmPhoto.SetResolution(imgPhoto.HorizontalResolution, imgPhoto.VerticalResolution);
Graphics grPhoto = Graphics.FromImage(bmPhoto);
grPhoto.InterpolationMode = InterpolationMode.HighQualityBicubic;
grPhoto.DrawImage(imgPhoto,
new Rectangle(destX, destY, (int)destWidth, (int)destHeight),
new Rectangle(sourceX, sourceY, (int)sourceWidth, (int)sourceHeight),
GraphicsUnit.Pixel);
grPhoto.Dispose();
return bmPhoto;
}
You can just load the file into a bitmap object:
http://msdn.microsoft.com/en-us/library/system.drawing.bitmap.aspx
Then just check the width on the object. For the second part of your problem, I would recommend using a tool like ImageMagick
http://www.imagemagick.org/script/index.php
to accurately resize the first image or to create the background image and merge the two images together.

Categories

Resources