Scaling image to 1600px X 700 px - c#

When an user uploads any image, can we scale it to 1600 X 700?
I'm using the code below to scale the images which are 1996 X 1442 , but it never scales to 1600 X 700.
Any better way or other way to achieve it?
private static Image resizeImage(Image imgToResize, Size 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((Image)b);
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
g.Dispose();
return (Image)b;
}
If you check the comments below, they say it's not possible to archive it without loosing aspect ratio, but if I see the HERO images from airbnb they have images which are of 1600 X 700...
So I think it's somehow possible but I don't know how to achieve it...

Of course not, as 1600 x 700 has a different aspect ratio (0.4375) than 1996 x 1442 (0.7724). The way you do it is to scale keeping the aspect ratio, so you'll never get to 1600 x 700 from 1996 x 1442.
You could:
Scale the image so that the longer corner is 1600 long and then cut out a relevant part of size 1600 x 700 (keeping the aspect ratio).
Scale the image to 1600 x 700, probably distorting the image as it is vertically "squeezed".
Another problem in your code are rounding issues.
int destWidth = (int)...;
int destHeight = (int)...;
simply cuts off the decimal places. Even if the computation result would be 699.9, destWidth would be 699.
You might want to use Math.Round instead, which would round 699.9 to 700 as expected.

Well, actually yes! There is almost nothing impossible in this world. Just try to search information about "seam carving". Sorry, no code here, because I'm not so familiar with these algorithms.

I've tweaked your method in a few ways:
It now scales according to the bigger ratio, not the smaller one, so you will end up trimming bits off your image rather than leaving white(?) letterboxing. (This is just < vs > though so it's easy to change.)
For the side that should be equal, this ensures it's equal, rather than scaling and rounding and hoping you don't end up with one pixel difference.
If the aspect ratios do not match, it centers the drawn image on g so you end up with equal amounts trimmed off left and right or top and bottom. (Without knowing that the original image is in the correct ratio, you have to decide somehow which bits of the image to trim off.)
Give it a try and see if you like the results.
private static Image resizeImage(Image imgToResize, Size size)
{
int sourceWidth = imgToResize.Width;
int sourceHeight = imgToResize.Height;
double wRatio = (double)size.Width / sourceWidth;
double hRatio = (double)size.Height / sourceHeight;
int destWidth, destHeight;
float top, left;
if (wRatio > hRatio) // reverse for white bars rather than trimming
{
destWidth = size.Width;
destHeight = (int)Math.Ceiling(sourceHeight * wRatio);
left = 0;
top = (destHeight - size.Height) / 2f;
}
else
{
destHeight = size.Height;
destWidth = (int)Math.Ceiling(sourceWidth * hRatio);
top = 0;
left = (destWidth - size.Width) / 2f;
}
Bitmap b = new Bitmap(size.Width, size.Height);
Graphics g = Graphics.FromImage((Image)b);
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(imgToResize, left, top, destWidth, destHeight);
g.Dispose();
return (Image)b;
}

This code preserves the Aspect Ratio of the original image. If preserving it is not important, then you can get rid of the ratio calculation part and create a Bitmap object with the size provided directly.
private static Image resizeImage(Image imgToResize, Size size)
{
Bitmap b = new Bitmap(size.Width, size.Height);
Graphics g = Graphics.FromImage((Image)b);
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
g.Dispose();
return (Image)b;
}

Related

After image resize transparency is removed - gdi+

I am reading an image from file that contains transparency area in the center (frame image type).
Image myFrame = Image.FromFile("d:\mypngfile.png");
After i call image resize custome function:
myFrame = resizeImage(myFrame, new Size(otherbmp.Width, otherbmp.Height));
The problem is that after reszing the image it seems transparency is removed.
resize function:
public Image resizeImage(Image imgToResize, Size 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,PixelFormat.Format32bppArgb);
b.MakeTransparent();
Graphics g = Graphics.FromImage((Image)b);
g.CompositingQuality = CompositingQuality.HighQuality;
g.CompositingMode = CompositingMode.SourceOver;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.SmoothingMode = SmoothingMode.AntiAlias;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
g.Dispose();
return (Image)b;
}
After i am checking the alpha pixels which doesn't work after resize (it does work before resizing and returns a value). It always return 0!
public int GetBorderWidth(Bitmap bmp)
{
var hy = bmp.Height/ 2;
while (bmp.GetPixel(0, hy).A == 255 && sz.Width < hx)
sz.Width++;
return sz.width;
}
I can't seem to solve this issue no matter what i try...
I found the issue, it was related that after resizing the image it seems that the border has some transparent pixels ..(like Alpha 150) so the border was not ALPHA 255..
What i did i changed the function GetBorderWidth code with
while (bmp.GetPixel(sz.Width, hy).A > 10 && sz.Width < hx)
sz.Width++;
and it seems it fixed the issue.
thank you all for giving me some idea of what to check.

After resize bitmap the result of the new bitmap is smooth bitmnap

I using simple re-size method to change my bitmap to new size.
The original bitmap size is 320x240 and i change the size two times
To 250x160
Doing some process on the bitmap
Change it back to 320x240
I found out that after i change it back to 320x240 i see that the bitmap is little smooth and not as i excepted.
How can i avoid this smooth to appear ?
The Resize method:
private static Image resizeImage(Image imgToResize, Size 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((Image)b);
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
g.Dispose();
return (Image)b;
}
The sad thing is you cannot.
When you resize your bitmap to a smaller size, information is lost. And information is interpolated from the small image (with less information) to create the new redimensionned image with the original size. It's this interpolation that gives the resulting image its smooth aspect.
To avoid this, the only thing you can do is finding a way to do the processing you have to without resizing down your image as part of your process.
Since you're using the HighQualityBicubic interpolation mode, the image will be prefiltered and resized using the highest possible quality, resulting in the "smoothing effect".
You can try setting the InterpolationMode property to NearestNeighbor to obtain a "rougher" result:
Bitmap b = new Bitmap(destWidth, destHeight);
using (Graphics g = Graphics.FromImage((Image) b)) {
g.InterpolationMode = InterpolationMode.NearestNeighbor;
g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
}

Quality problem when resizing image?

I'am using this code to resize image. But result is not fine, I want to best quality. I know its low quality because I also resize same image with photoshop and result is different so better. How do I fix it?
private static Image resizeImage(Image imgToResize, Size 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((Image)b);
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
g.Dispose();
return (Image)b;
}
This is the routine I use. Perhaps you'll find it useful. It is an extension method, to boot. The only difference is that I omit the code to preserve the aspect ratio, which you could just as easily plug in.
public static Image GetImageHiQualityResized(this Image image, int width, int height)
{
var thumb = new Bitmap(width, height);
using (var g = Graphics.FromImage(thumb))
{
g.SmoothingMode = SmoothingMode.HighQuality;
g.CompositingQuality = CompositingQuality.HighQuality;
g.InterpolationMode = InterpolationMode.High;
g.DrawImage(image, new Rectangle(0, 0, thumb.Width, thumb.Height));
return thumb;
}
}
Example usage of this extension method could include:
// Load the original image
using(var original = Image.FromFile(#"C:\myimage.jpg"))
using(var thumb = image.GetImageHiQualityResized(120, 80))
{
thumb.Save(#"C:\mythumb.png", ImageFormat.Png);
}
Notes
See http://msdn.microsoft.com/en-us/library/84767bxk.aspx for additional methods of saving and loading images.
The difference between the default JPG encoding and the default PNG encoding is, indeed, very different. Below are two thumbs using your example, one saved with ImageFormat.Png and one with ImageFormat.Jpeg.
PNG Image
JPEG Image
You may find the work done by the original poster in this question to be helpful if you determine that you absolutely must use JPEG. It involves configuring the image codec and encoding parameters to high-quality settings. .NET Saving jpeg with the same quality as it was loaded
Were it me, I'd just as soon use the PNG format, as it is lossless.

how to resize an image whileing saving in an folder

i have an image file which is of (600* 800 size) or any size . now i need to convert them into an thubnail image size which is of size ****(110*110)****
but if i reduce the size of an image i should not change the Quality of image. as once we reduce an image size the the Quality of the image is gone
is there any way without affecting the Quality of the image we can convert them into an thumbnail image[ is there any built in class for that in .net)
any help would be great
Well, about how to do it, there's a interesting material here the may help you.
About losing quality, if you mean resolution, there's no way as long as you are downsizing an image, you are throwing away spacial information that no longer can be rebuilt. Of course if you use some sort of interpolation, but it will never be the same as your original picture.
What you can do is store one version of each.
Here's the code got from the link and honestly, I think that the last 5 lines of code starting at Bitmap b = new Bitmap(destWidth, destHeight); is enough to solve your problem.
private static Image resizeImage(Image imgToResize, Size 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((Image)b);
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
g.Dispose();
return (Image)b;
}
when you downsize an image you do not reduce it's quality, only when you try to bring it back to it's original size from the downsized version the quality will be affected.

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