0

我想按比例保存图像而不损失其质量。如果我这样做,这对吗?

var pathImage = ""; 
var pathFolder = "";  
System.Drawing.Image image;  
System.Drawing.Image thumb;  
image = System.Drawing.Image.FromFile(pathImage);  
var imageWidth = image.Width;  
var imageHeight = image.Height;  
width = (180 * imageWidth) / imageHeight;  
height = 180;  
thumb = image.GetThumbnailImage(width, height, null, System.IntPtr.Zero);  
ImageCodecInfo myCodecInfoEncoder = GetEncoder(ImageFormat.Jpeg);  
var myEncoderParameters = new EncoderParameters(1);  
var myEncoderParameter = new EncoderParameter(Encoder.Quality, 50L);  
myEncoderParameters.Param[0] = myEncoderParameter;  
thumb.Save(pathFolder, myCodecInfoEncoder, myEncoderParameters);  

谢谢。

4

1 回答 1

1

这实际上是多个问题合二为一:

  • 如何从 GDI+ 获得高质量的缩放?
  • 保存时如何保持透明度和原始图像信息?
  • 保存到磁盘时保持图像质量的最佳方法是什么?

在剩下的部分中,我试图回答每一个问题。


高质量缩放

要开始回答第一个问题,您可能不想使用GetThumbnail()例程。它几乎是一个黑匣子,不允许您更改很多设置。相反,你会想要做这样的匆忙制作的例程:

//      aspectScale = when true, create an image that is up to the size (new w, new h)
//                    that maintains original image aspect. When false, just create a
//                    new image that is exactly the (new w, new h)
private static Bitmap ReduceImageSize(Bitmap original, int newWidth, int newHeight, bool aspectScale)
{
    if (original == null || (original.Width < newWidth && original.Height < newHeight)) return original;

    // calculate scale
    var scaleX = newWidth / (float)original.Width;
    var scaleY = newHeight / (float)original.Height;
    if (scaleY < scaleX) scaleX = scaleY;

    // calc new w/h
    var calcWidth = (aspectScale ? (int)Math.Floor(original.Width * scaleX) : newWidth);
    var calcHeight = (aspectScale ? (int)Math.Floor(original.Height * scaleX) : newHeight);
    var resultImg = new Bitmap(calcWidth, calcHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

    using (var offsetMtx = new System.Drawing.Drawing2D.Matrix())
    {
        offsetMtx.Translate(calcWidth / 2.0f, calcHeight / 2.0f);
        offsetMtx.Scale(scaleX, scaleX);
        offsetMtx.Translate(-original.Width / 2.0f, -original.Height / 2.0f);

        using (var resultGraphics = System.Drawing.Graphics.FromImage(resultImg))
        {
            // scale
            resultGraphics.Transform = offsetMtx;

            // IMPORTANT: Compromise between quality and speed for these settings
            resultGraphics.SmoothingMode = SmoothingMode.HighQuality;
            resultGraphics.InterpolationMode = InterpolationMode.Bicubic;

            // For a white background add: resultGraphics.Clear(Color.White);

            // render the image
            resultGraphics.DrawImage(original, Point.Empty);
        }
    }

    return resultImg;
}

关于此例程,您会注意到您可以更改SmoothingMode,也可以更改InterpolationMode. 这些允许您自定义从该例程中获得的缩放质量。要调用我的简单示例,您只需使用:

var newImage = ReduceImageSize(originalImage, 100, 100, true);

这会将您的原始图像缩放到小于或等于 100px 的宽度和相同的高度(这可能是您想要的)。

高品质节省

对于另一部分 - 如何保存,如果您需要透明度,则不能使用 JPEG。作为一个简单的起点,我建议使用 PNG 格式进行保存。看起来像:

newImage.Save(fileName + ".png", ImageFormat.Png);

默认情况下,PNG 包含一定程度的压缩(很像 JPEG),但它也保持透明度,这对您来说似乎很重要。如果您需要进一步压缩,您可以查看已有的 JPEG 文件,减少像素深度或索引颜色。如果你在 google 上搜索,你应该想出很好的方法来支持其中的每一个。

维护原始数据

你没有问过它,但要意识到的是,图像不仅仅是一堆像素——它们还有元数据。元数据包括诸如 EXIF 信息或其他描述图像拍摄方式的数据。当 .NET 创建一个新图像并保存时,您已经有效地从图像中删除了这些数据(这可能是也可能不是这里的目标)。如果您想保留此数据,则可以从使用PropertyItems列表开始。您可以在旧图像上迭代此数组,复制到新图像。

这实际上并没有公开所有可用的数据。如果您真的想完整地将元数据从原始图像复制到输出图像,您可能需要阅读图像规范或使用诸如 Phil Harvey 提供的工具:http://www.sno。 phy.queensu.ca/~phil/exiftool/

希望这有助于您朝着正确的方向前进!祝你好运!

于 2014-04-17T19:01:52.447 回答