views:

486

answers:

4

I'm fighting an issue where my resized images looses color saturation when I manipulate them using GDI.

I'm loading an JPG as original, resize it and the resulting image has a lot less saturation (color intensity) than the original picture. What can I do to improve that? this is my code:


using ( var original = System.Drawing.Image.FromStream( new MemoryStream( image.RawData ) ) )
{
    using ( var dst = new Bitmap( width, height, PixelFormat.Format32bppArgb ) )
    {
     using ( var g = Graphics.FromImage( dst ) )
     {
      g.SmoothingMode = SmoothingMode.HighQuality;
      g.PixelOffsetMode = PixelOffsetMode.HighQuality;
      g.CompositingQuality = CompositingQuality.HighQuality;

      g.DrawImage( original, 0, 0, dst.Width, dst.Height );
      g.InterpolationMode = InterpolationMode.HighQualityBicubic;
      g.DrawImage( original, 0, 0, dst.Width, dst.Height );

      var jpgEncoder = GetEncoder( ImageFormat.Jpeg );
      var myEncoderParameters = new EncoderParameters( 1 );
      var quality = 95;
      var myEncoderParameter = new EncoderParameter( Encoder.Quality, quality );
      myEncoderParameters.Param[0] = myEncoderParameter;

      dst.Save( buffer, jpgEncoder, myEncoderParameters );
     }
    }
}

I've tried with different pixelformats, removing all filters etc but I always get the same result. Is this some known issue with GDI, or have I missed something?

Addon: When opening the image in Paint.NET, I get the same issue with low saturation, even without rescaling, so I guess it's the way GDI+ loads images (jpgs)?

This image was saved from photoshop with color profile sRGB, but afaik JPG doesn't have info about colorprofiles embedded. And even if it did, I believe that firefox doesn't obey them (which is what I've tested with)

More testing shows that it looks different in IE8 in contrast to firefox. JPGs seems to support color profiles, but most applications doesn't obey them. FF3.5 however, seems to do it. And it was Adobe RGB, not sRGB on the image.

A: 

Been there, done that. Silly as it may sound, this makes difference:

var quality = 95;
var myEncoderParameter = new EncoderParameter( Encoder.Quality, (long)quality );

or

long quality = 95;
var myEncoderParameter = new EncoderParameter( Encoder.Quality, quality );

or

var quality = 95L;
var myEncoderParameter = new EncoderParameter( Encoder.Quality, quality );

Just pick one.

danbystrom
I don't have problem with the compression-quality, just the color saturation. Tried your suggestion but unfortunately it didn't make any difference...
jishi
A: 

I have an image-rescaling code I use, and I don't see the effect you mention.

the main difference I see is that I use Format24bppRgb and not Format24bpp**A**Rgb

Keep in mind that JPG has no Alpha channel anyway (afaik)

Ken Egozi
A: 

Coming at this from another angle, I would highly recommend http://nathanaeljones.com/products/asp-net-image-resizer/ if you want to take the pain out of doing this yourself. It even takes care of disk caching!

TimS
+2  A: 

I found the answer myself. It has to do with color-profiles not beeing applied by default in GDI+. Many people claims that you cannot automatically apply color-profiles using GDI, but apparently, the only change I needed to do was this:

using ( var original = System.Drawing.Image.FromStream( new MemoryStream( image.RawData ) ) )

to

using ( var original = new Bitmap( new MemoryStream( image.RawData ), true ) )

Apparently, Bitmap was a derived class if Image, and the constructor for Bitmap can take both a stream aswell as a boolean for "useIcm". That did the trick for me.

jishi
Thank you so much for explaining this! I deep into reading up on chroma subsampling and other possible issues causing color loss. After setting uselcm flag true my jpeg photos are perfect in color.
jesperlind