This question already has an answer here:
How resize image without losing quality
(1 answer)
Closed 5 years ago.
So I'm trying to resize HUGE images, like 5500x3500 JPGs down to 1024x768 or less. The following function works, but it really runs the quality, makes the text all fuzzy.
static public Bitmap 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);
Bitmap bmp = new Bitmap(newImage);
return bmp;
}
Any idea of a better way to do this?
As suggested in comment, you should use Interpolation mode to control image quality during scaling. To know how to use it, refer to the following doc from Microsoft,
https://learn.microsoft.com/en-us/dotnet/framework/winforms/advanced/how-to-use-interpolation-mode-to-control-image-quality-during-scaling
You should set the quality-properties in Graphics-object to HighQuality:
static public Bitmap 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);
using (Bitmap newImage = new Bitmap(newWidth, newHeight))
{
using (Graphics g = Graphics.FromImage(newImage))
{
g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
Bitmap bmp = new Bitmap(newImage);
return bmp;
}
}
}
Also be sure to use using-block with objects that implements iDisposable: Image, Bitmap and Graphichs all do.
Related
We are resizing the image and we are facing a issue.Only portion of image is getting resized and we are using below code.
public Bitmap ScaleImage(Bitmap image, int maxWidth, int maxHeight)
{
var ratioX = (double)maxWidth / image.Width;
var ratioY = (double)maxHeight / image.Height;
var ratio = 1.0;
if (maxWidth == 0)
{
ratio = ratioY;
}
else if (maxHeight == 0)
{
ratio = ratioX;
}
else
{
ratio = Math.Min(ratioX, ratioY);
}
var newWidth = (int)(image.Width * ratio);
var newHeight = (int)(image.Height * ratio);
Graphics graphicsObj;
var newImage = new Bitmap(newWidth, newHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
//var newImage = new Bitmap(newWidth, newHeight);
graphicsObj = Graphics.FromImage(newImage);
graphicsObj.Clear(Color.White);
Graphics.FromImage(newImage).DrawImage(image, 0, 0, newWidth, newHeight);
return newImage;
}
Please follow this link for example.
I seem to be having trouble up-scaling an image that is 8x8 pixels. When testing, I wanted to scale the image up to 64x64 pixels. However, when doing so, this was the result:
Rescaling it the way I did below, removes 4 pixels height on the top, and 4 pixels width on the left, and adds 4 black pixels height on the bottom, and 4 pixels width on the right.
Here is the code I am using to rescale the image:
private static Image ScaleImage(string username, int size)
{
Image avatar = MergeImage(username);
int originalWidth = avatar.Width;
int originalHeight = avatar.Height;
float ratioX = (float)size / (float)originalWidth;
float ratioY = (float)size / (float)originalHeight;
float ratio = Math.Min(ratioX, ratioY);
int newWidth = (int)(originalWidth * ratio);
int newHeight = (int)(originalHeight * ratio);
Bitmap newImage = new Bitmap(newWidth, newHeight, PixelFormat.Format48bppRgb);
using (Graphics g = Graphics.FromImage(newImage))
{
g.InterpolationMode = InterpolationMode.NearestNeighbor;
g.DrawImage(avatar, 0, 0, newWidth, newHeight);
}
return newImage;
}
I am unsure of what is going wrong here. Any help would be greatly appreciated.
Add this before g.DrawImage:
g.PixelOffsetMode = PixelOffsetMode.Half;
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");
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.
I would like to add a layer to an image with the logo of the company.
The logo should be placed on the center of the image (little opacity).
How can I do that?
Here is one I made earlier which creates a new badge for some images:
EDIT, I designed the function which I supply a maxWidth and a maxHeight, it resizes without distortion.
Requirements:
using System.IO;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
The Code
using (Image i = Image.FromFile(HttpContext.Current.Server.MapPath(fileName)))
{
float imageWidth = i.PhysicalDimension.Width;
float imageHeight = i.PhysicalDimension.Height;
float percentage = maxWidth / imageWidth;
float newWidth = imageWidth * percentage;
float newHeight = imageHeight * percentage;
if (newHeight > maxHeight)
{
percentage = maxHeight / newHeight;
newWidth = newWidth * percentage;
newHeight = newHeight * percentage;
}
using (Bitmap b = new Bitmap((int)newWidth, (int)newHeight))
{
using (Graphics g = Graphics.FromImage(b))
{
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.SmoothingMode = SmoothingMode.AntiAlias;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.CompositingQuality = CompositingQuality.HighQuality;
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
g.DrawImage(i, new Rectangle(0, 0, b.Width, b.Height));
if (effect == "new")
{
using (Image j = Image.FromFile(HttpContext.Current.Server.MapPath("/ImageEffects/") + "new.png", true))
{
g.DrawImage(j, new Rectangle(0, 0, 60, 60));
}
}
Image newImage = Image.FromHbitmap(b.GetHbitmap());
return newImage;
}
}
}
}