开发者

How can I get better results when shrinking an image

I'm scaling images down in c#, and I've compared my methods with the best method in Photoshop cs5 and cannot replicate it.

In PS i'm using bicubic sharper, which looks really good. However, when trying to do the 开发者_JAVA技巧same in c# I don't get as high quality results. I've tried bicubic interpolation as well as HQ bicubic, smoothing mode HQ/None/AA. Composition modes, I've tried about 50 different variations and each one comes out pretty close to the image on the right.

You'll notice the pixelation on her back and around the title, as well as the authors name not coming out too well.

(Left is PS, right is c#.)

How can I get better results when shrinking an image

It seems that c# bicubic does too much smoothing even with smoothing set to none. I've been playing around with many variations of the following code:

 g.CompositingQuality = CompositingQuality.HighQuality;
 g.InterpolationMode = InterpolationMode.HighQualityBicubic;
 g.PixelOffsetMode = PixelOffsetMode.None;
 g.SmoothingMode = SmoothingMode.None;

Edit: As requested here is the starting image (1mb).

How can I get better results when shrinking an image


Perhaps I am missing something, but I have typically used the following code below to resize/compress JPEG Images. Personally, I think the result turned out pretty well based on your source image. The code doesn't handle a few edge cases concerning input parameters, but overall gets the job done (I have additional extension methods for Cropping, and Combining image transformations if interested).

Image Scaled to 25% original size and using 90% Compression. (~30KB output file)

How can I get better results when shrinking an image

Image Scaling Extension Methods:

public static Image Resize(this Image image, Single scale)
{
  if (image == null)
    return null;

  scale = Math.Max(0.0F, scale);

  Int32 scaledWidth = Convert.ToInt32(image.Width * scale);
  Int32 scaledHeight = Convert.ToInt32(image.Height * scale);

  return image.Resize(new Size(scaledWidth, scaledHeight));
}

public static Image Resize(this Image image, Size size)
{
  if (image == null || size.IsEmpty)
    return null;

  var resizedImage = new Bitmap(size.Width, size.Height, image.PixelFormat);
  resizedImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);

  using (var g = Graphics.FromImage(resizedImage))
  {
    var location = new Point(0, 0);
    g.InterpolationMode = InterpolationMode.HighQualityBicubic;
    g.DrawImage(image, new Rectangle(location, size), new Rectangle(location, image.Size), GraphicsUnit.Pixel);
  }

  return resizedImage;
}

Compression Extension Method:

public static Image Compress(this Image image, Int32 quality)
{
  if (image == null)
    return null;

  quality = Math.Max(0, Math.Min(100, quality));

  using (var encoderParameters = new EncoderParameters(1))
  {
    var imageCodecInfo = ImageCodecInfo.GetImageEncoders().First(encoder => String.Compare(encoder.MimeType, "image/jpeg", StringComparison.OrdinalIgnoreCase) == 0);
    var memoryStream = new MemoryStream();

    encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, Convert.ToInt64(quality));

    image.Save(memoryStream, imageCodecInfo, encoderParameters);

    return Image.FromStream(memoryStream);
  }
}

Usage:

  using(var source = Image.FromFile(@"C:\~\Source.jpg"))
  using(var resized = source.Resize(0.25F))
  using(var compressed = resized.Compress(90))
    compressed.Save(@"C:\~\Output.jpg");

NOTE: For anyone who may comment, you cannot dispose the MemoryStream created in the Compress method until after the image is disposed. If you reflect in to the implementation of Dispose on MemoryStream, it is actually save to not explicitly call dispose. The only alternative would be to wrap the image/memory stream in a custom implementation of a class that implements Image/IDisposable.


Looking at the amount of JPEG artifacts, especially at the top of the image, I think you set the jpg compression to high. That results in a smaller (filesize) file, but reduces image quality and seems to add more blur.

Can you try saving it in a higher quality? I assume the line containing CompositingQuality.HighQuality does this already, but maybe you can find an even higher quality mode. What are the differences in file size between Photoshop and C#? And how does the Photoshop image look after you saved it and reopened it? Just resizing in Photoshop doesn't introduce any jpg data loss. You will only notice that after you've saved the image as jpg and then closed and reopened it.


I stumbled upon this question.

I used this code to use no compression of the jpeg and it comes out like the PS version:

ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders(); 
    ImageCodecInfo ici = null; 
    foreach (ImageCodecInfo codec in codecs)
    { 
        if (codec.MimeType == "image/jpeg") 
            ici = codec; 
    } 

    EncoderParameters ep = new EncoderParameters(); 
    ep.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)100);
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜