调整图像大小而不丢失任何质量

如何在图像质量不受影响的情况下调整图像的大小?

189337 次浏览

Unless you're doing vector graphics, there's no way to resize an image without potentially losing some image quality.

As rcar says, you can't without losing some quality, the best you can do in c# is:

Bitmap newImage = new Bitmap(newWidth, newHeight);
using (Graphics gr = Graphics.FromImage(newImage))
{
gr.SmoothingMode = SmoothingMode.HighQuality;
gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
gr.PixelOffsetMode = PixelOffsetMode.HighQuality;
gr.DrawImage(srcImage, new Rectangle(0, 0, newWidth, newHeight));
}

You can't resize an image without losing some quality, simply because you are reducing the number of pixels.

Don't reduce the size client side, because browsers don't do a good job of resizing images.

What you can do is programatically change the size before you render it, or as a user uploads it.

Here is an article that explains one way to do this in c#: http://www.codeproject.com/KB/GDI-plus/imageresize.aspx

Unless you resize up, you cannot do this with raster graphics.

What you can do with good filtering and smoothing is to resize without losing any noticable quality.

You can also alter the DPI metadata of the image (assuming it has some) which will keep exactly the same pixel count, but will alter how image editors think of it in 'real-world' measurements.

And just to cover all bases, if you really meant just the file size of the image and not the actual image dimensions, I suggest you look at a lossless encoding of the image data. My suggestion for this would be to resave the image as a .png file (I tend to use paint as a free transcoder for images in windows. Load image in paint, save as in the new format)

There is something out there, context aware resizing, don't know if you will be able to use it, but it's worth looking at, that's for sure

A nice video demo (Enlarging appears towards the middle) http://www.youtube.com/watch?v=vIFCV2spKtg

Here there could be some code. http://www.semanticmetadata.net/2007/08/30/content-aware-image-resizing-gpl-implementation/

Was that overkill? Maybe there are some easy filters you can apply to an enlarged image to blur the pixels a bit, you could look into that.

Are you resizing larger, or smaller? By a small % or by a larger factor like 2x, 3x? What do you mean by quality for your application? And what type of images - photographs, hard-edged line drawings, or what? Writing your own low-level pixel grinding code or trying to do it as much as possible with existing libraries (.net or whatever)?

There is a large body of knowledge on this topic. The key concept is interpolation.

Browsing recommendations:
* http://www.all-in-one.ee/~dersch/interpolator/interpolator.html
* http://www.cambridgeincolour.com/tutorials/image-interpolation.htm
* for C#: https://secure.codeproject.com/KB/GDI-plus/imageprocessing4.aspx?display=PrintAll&fid=3657&df=90&mpp=25&noise=3&sort=Position&view=Quick&fr=26&select=629945 * this is java-specific but might be educational - http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html

Here is a forum thread that provides a C# image resizing code sample. You could use one of the GD library binders to do resampling in C#.

See if you like the image resizing quality of this open source ASP.NET module. There's a live demo, so you can mess around with it yourself. It yields results that are (to me) impossible to distinguish from Photoshop output. It also has similar file sizes - MS did a good job on their JPEG encoder.

I believe what you're looking to do is "Resize/Resample" your images. Here is a good site that gives instructions and provides a utility class(That I also happen to use):

http://www.codeproject.com/KB/GDI-plus/imgresizoutperfgdiplus.aspx

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

from here

Here you can find also add watermark codes in this class :

public class ImageProcessor
{
public Bitmap Resize(Bitmap image, int newWidth, int newHeight, string message)
{
try
{
Bitmap newImage = new Bitmap(newWidth, Calculations(image.Width, image.Height, newWidth));


using (Graphics gr = Graphics.FromImage(newImage))
{
gr.SmoothingMode = SmoothingMode.AntiAlias;
gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
gr.PixelOffsetMode = PixelOffsetMode.HighQuality;
gr.DrawImage(image, new Rectangle(0, 0, newImage.Width, newImage.Height));


var myBrush = new SolidBrush(Color.FromArgb(70, 205, 205, 205));


double diagonal = Math.Sqrt(newImage.Width * newImage.Width + newImage.Height * newImage.Height);


Rectangle containerBox = new Rectangle();


containerBox.X = (int)(diagonal / 10);
float messageLength = (float)(diagonal / message.Length * 1);
containerBox.Y = -(int)(messageLength / 1.6);


Font stringFont = new Font("verdana", messageLength);


StringFormat sf = new StringFormat();


float slope = (float)(Math.Atan2(newImage.Height, newImage.Width) * 180 / Math.PI);


gr.RotateTransform(slope);
gr.DrawString(message, stringFont, myBrush, containerBox, sf);
return newImage;
}
}
catch (Exception exc)
{
throw exc;
}
}


public int Calculations(decimal w1, decimal h1, int newWidth)
{
decimal height = 0;
decimal ratio = 0;




if (newWidth < w1)
{
ratio = w1 / newWidth;
height = h1 / ratio;


return height.To<int>();
}


if (w1 < newWidth)
{
ratio = newWidth / w1;
height = h1 * ratio;
return height.To<int>();
}


return height.To<int>();
}


}