Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
330 views
in Technique[技术] by (71.8m points)

c# - Unexpected "Bitmap Region is already Locked" exception with GetEncoderParameterList. Any ideas?

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 + "
" + "Guid category: " + encParams[i].Encoder.Guid + "
");

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

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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=.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...