Resizing images in C# - c#

I have the below method which I found online,which resizes an image to an approximate size, while keeping the aspect ratio.
public Image ResizeImage(Size size)
{
int sourceWidth = _Image.Width;
int sourceHeight = _Image.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(_Image, 0, 0, destWidth, destHeight);
g.Dispose();
return (Image)b;
}
I usually pass in a size with a width of 100px and a height of 100px - as part of my requirements I can't have any single dimension (height or width) being under 100px, so if the aspect ratio isn't square the other dimension would be higher.
What I'm finding with this method is occasionally one of the dimensions will be under 100px - such as 96px or 99px. How can I change this method to ensure this doesn't happen?

The code is just inappropriate. It doesn't score points for using floating point math, that has a knack for rounding the wrong way so you can easily end up with 99 pixels instead of 100. Always favor integer math so you can control the rounding. And it just doesn't do anything to ensure that one of the dimensions is large enough, the way to end up with 96 pixels. Just write better code. Like:
public static Image ResizeImage(Image img, int minsize) {
var size = img.Size;
if (size.Width >= size.Height) {
// Could be: if (size.Height < minsize) size.Height = minsize;
size.Height = minsize;
size.Width = (size.Height * img.Width + img.Height - 1) / img.Height;
}
else {
size.Width = minsize;
size.Height = (size.Width * img.Height + img.Width - 1) / img.Width;
}
return new Bitmap(img, size);
}
I left a comment to show what you do if you are only want to make sure the image is large enough and accept larger images. It wasn't clear from the question. If that's the case then replicate that if statement in the else clause as well.

Related

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

Scale or resize an 8bit image with 8bit image as result (PixelFormat.Format8bppIndexed)

I try to scale a grey8 image for video transmission via TCP-clients in C#/.NET.
My image from an IpCam is currently 1920x1080 and I want to resize it to 640x480 in order to reduce traffic on the connection:
I found a working example here on Stack Overflow the only problem is.
public static Image ResizeImage(Bitmap image, Size size, bool preserveAspectRatio = true)
{
int newWidth;
int newHeight;
if (preserveAspectRatio)
{
int originalWidth = image.Width;
int originalHeight = image.Height;
float percentWidth = (float)size.Width / (float)originalWidth;
float percentHeight = (float)size.Height / (float)originalHeight;
float percent = percentHeight < percentWidth ? percentHeight : percentWidth;
newWidth = (int)(originalWidth * percent);
newHeight = (int)(originalHeight * percent);
}
else
{
newWidth = size.Width;
newHeight = size.Height;
}
Image newImage = new Bitmap(newWidth, newHeight);
using (Graphics graphicsHandle = Graphics.FromImage(newImage))
{
graphicsHandle.InterpolationMode = InterpolationMode.HighQualityBicubic; //NearestNeighbor
graphicsHandle.DrawImage(image, 0, 0, newWidth, newHeight);
}
return(newImage);
}
.the image I get from this function is a 32ARgb image, which is not what I want. Because it introduces 3 additional color channels (Alpha and RBG).
Is there a way of scaling the image down without changing the color pattern?
I also tried to use the InterpolationMode.NearestNeighbor but I only got a 32bit-bitmap out of it.

Translate/Detect Rectangle portion of Image from Resized Image

I have a Large size image.Since it takes long to process high res images i resize it keeping the aspect ratio.From the resized image i detect a rectangle and i have the coordinates of the rectangle.
Bitmap ResizekeepAspectRatio(Bitmap 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;
}
Is there a way by which i can translate/Map this rectangle to the Large image so that i get the same area.Im doing this to save time.
Some clarification:
I have a Large Original Image.. i resize it keeping the aspect ratio and using some processing i get a rectangle portion in it( Just the coordinates).Since the Image quality of this portion is not good i need to find a way to map this coordinate to the large image.
Ok, so if I understand it clear here it is:
You have a viewport in what you select a rectangle and you want to scale this rectangle to the unscaled image.
So we will have a function like this:
public RectangleF TranslateScale(RectangleF CropRectangle, Bitmap imgPhoto)
First of all what we need is to calculate the multiplier to fit the image on the viewport, exactly like your function:
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;
else
nPercent = nPercentW;
Now that we know the scale percentage we just take the inverse of your function, instead of multiply just divide the rectangle size and position:
CropRectangle.X /= nPercent;
CropRectangle.Y /= nPercent;
CropRectangle.Width /= nPercent;
CropRectangle.Height /= nPercent
return CropRectangle;
And that's it, now you have the rectangle scaled to the original image size, you now can crop that rectangle.

How to control image size while download from URL using C#

there is has any possible way to control the image size while download the image directly from URL using c#. I have image that download from URL by using this code:
webClient.DownloadFile("remoteFileUrl", "localFilePath");
My problem is I do not want that image width to large that over than 800px, if image size of width smaller than 800px doesn't matter and should keep download by the original size. But if the image width is larger than 800px I want the image resize to maximum width is 800px only.
But if the image width is larger than 800px I want the image resize to
maximum width is 800px only.
You have to download the image in order to re-size. Download the image and check if it has larger width then your required width then you can re-size image. This article explains it very well, that following re-size method is also take from the mentioned article.
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;
}

Resizing image get damage in pixel

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.

Categories