views:

135

answers:

1

I'm trying to use this sample code from Microsoft to determine what encoder options are available for the JPEG encoder. (The real problem I'm trying to solve is to see if I can set the Chroma subsampling parameters explicitly)

http://msdn.microsoft.com/en-us/library/bb882589.aspx

private void GetSupportedParameters(PaintEventArgs e)
{
    Bitmap bitmap1 = new Bitmap(1, 1);
    ImageCodecInfo jpgEncoder = GetEncoder(ImageFormat.Jpeg);
    EncoderParameters paramList = bitmap1.GetEncoderParameterList(jpgEncoder.Clsid);
    EncoderParameter[] encParams = paramList.Param;
    StringBuilder paramInfo = new StringBuilder();

    for (int i = 0; i < encParams.Length; i++)
    {
        paramInfo.Append("Param " + i + " holds " + encParams[i].NumberOfValues +
            " items of type " +
            encParams[i].ValueType + "\r\n" + "Guid category: " + encParams[i].Encoder.Guid + "\r\n");

    }
    e.Graphics.DrawString(paramInfo.ToString(), this.Font, Brushes.Red, 10.0F, 10.0F);
}

private ImageCodecInfo GetEncoder(ImageFormat format)
{

    ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();

    foreach (ImageCodecInfo codec in codecs)
    {
        if (codec.FormatID == format.Guid)
        {
            return codec;
        }
    }
    return null;
}

The problem is, "GetEncoderParameterList" always throws an exception: Bitmap Region Is already Locked.

I tried putting the code at the very beginning of my program, and not in an on-paint event handler. Same thing. I tried changing the bit depth on the bitmap, and creating bitmaps in other ways, no difference.

Any idea why .NET would think a freshly created bitmap has a locked region?


Update! Some more info: If I use a TIFF encoder, it doesn't fail:

    Bitmap bitmap1 = new Bitmap(1, 1);
    ImageCodecInfo jpgEncoder = GetEncoder(ImageFormat.TIFF);  // TIFF instead of JPEG
    EncoderParameters paramList = bitmap1.GetEncoderParameterList(jpgEncoder.Clsid);
    EncoderParameter[] encParams = paramList.Param;

So I think this may just be a bug/limitation of GetEncoderparameterList for jpeg....

+2  A: 

I repro this. The exception message is bogus, that's common for GDI+ exceptions. The source of the problem is the jpeg codec, GetEncoderParameterList() queries it for the list of parameters it supports. The list it gets back contains one bad entry, the NumberOfValues is 0. That causes Marshal.AllocHGlobal() to return a NULL, misinterpreted as an out-of-memory exception, which is turn is misinterpreted as a "Bitmap region is already locked" exception.

Ugh, GDI+ sure is a mess. This problem is almost certainly specific to GDI+ version 1.10, the version that first shipped with Vista. Could be Win7 specific too, I've seen several forum posting about problems with the JPEG codec on that operating system.

Well, nothing you can do about it until the next Windows service pack becomes available, if then. To address your specific query, no, probably not. The list of encoder parameters that GDI+ knows about is listed in the GdiPlusImaging.h SDK header file. The only one that's close is "EncoderChrominanceTable", available as Encoder.ChrominanceTable.Guid in the .NET framework. No idea if that's close to what you are looking for.

You should really consider the WPF JpegBitmapEncoder class, a major improvement over GDI=.

Hans Passant
Thanks! Setting the Chrominance was _exactly_ what I was trying to do.
ראובן