Исключение GDI+, сохраняющее растровое изображение в MemoryStream

У меня возникла проблема в приложении Windows Forms с ошибкой Bitmap.Save при сохранении в MemoryStream. Проблема, похоже, периодически возникает только на одной машине (пока что), и плохая новость заключается в том, что она находится на сайте клиента. Я не могу отлаживать машину, но я получил трассировку стека, которая сузила проблему до одной строки кода.

Вот сокращенная версия моего кода:

byte[] ConvertPixelsToBytes()
{
    // imagine a picture class that creates a 24 bbp image, and has
    // a method to get an unmanaged pixel buffer.
    // imagine it also has methods for getting the width,
    // height, pitch 

    // I suppose this line could return a bad address, but 
    // I would have expected that the Bitmap constructor would have 
    // failed if it was
    System.IntPtr pPixels = picture.GetPixelData();

    System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(
            picture.width(),
            picture.height(),
            picture.pitch(),
            System.Drawing.Imaging.PixelFormat.Format24bppRgb,
            pPixels );

    // This line doesn't actually free the memory, but it could be freed in a 
    // background thread
    // (2)
    picture.releasePixelData(pPixels);

    System.IO.MemoryStream memStream = new System.IO.MemoryStream();
    try
    {
        // I don't see how this line could fail, but it does
        // (3)
        bmp.Save(memStream, System.Drawing.Imaging.ImageFormat.Bmp);
        return memStream.ToArray();
    }
   catch(System.Runtime.InteropServices.ExternalException e)
   {
       // e.Message is the very helpful " A generic error occurred in GDI+."
   }
   finally
   {
       memStream.Dispose();
   }
   return new byte[0];
}

Есть идеи, что может происходить? Я почти уверен, что мой буфер пикселей правильный, он всегда работает на наших машинах для разработки / тестирования и на других сайтах клиентов.

Мои мысли о возможных причинах неудачи

а. Конструктор растрового изображения не копирует данные пикселя, а сохраняет ссылку на них, и при сохранении происходит сбой, поскольку освобождается память. Я не нахожу документы MSDN ясными по этому вопросу, но я предполагаю, что растровое изображение копирует данные пикселей, а не предполагает, что оно заблокировано.

б. Данные пикселя недействительны и приводят к сбою метода Save. Я сомневаюсь в этом, поскольку мои пиксельные данные составляют 24 бита на пиксель, поэтому, насколько мне известно, они не должны быть недействительными.

в. Есть проблема с .NET framework.

Я был бы признателен за любые мысли о других возможных причинах сбоя, чтобы я мог добавить дополнительные проверки и информацию журнала в свое приложение, чтобы я мог отправить что-нибудь в поле.


person Peter Tate    schedule 06.02.2009    source источник
comment
Какое-то конкретное исключение? Или это одно из тех исключений poseky. Произошла ошибка Gerneic GDI+?   -  person Neil N    schedule 06.02.2009
comment
Это одно из тех исключений Generic GDI+.   -  person Peter Tate    schedule 06.02.2009


Ответы (2)


Документы MSDN для этого конструктора Bitmap не оставляют никаких сомнений:

Примечания Вызывающий объект отвечает за выделение и освобождение блока памяти, указанного параметром scan0, однако память не должна освобождаться до тех пор, пока не будет освобожден соответствующий битмап.

person Hans Passant    schedule 06.02.2009
comment
Спасибо. На самом деле это не задокументировано в библиотеке MSDN для Visual Studio 2005 (в следующий раз я также проверю онлайн-документы). - person Peter Tate; 09.02.2009
comment
У меня есть проблема, которая очень похожа на эту, также с использованием bmp.Save(memStream,... и т. д.) Хотя кажется правдой, что в документации упоминается то, что вы говорите, похоже, это относится к потоку памяти, используемому в конструкторе bmp - теперь это имеет смысл, но что труднее принять, так это то, что поток памяти, в котором сохраняется растровое изображение, должен поддерживаться в актуальном состоянии - я писал в png, это идет не так только на производственной машине и проблема прерывистая, исправляется только если пул приложений переработан.Ранее работало 10 лет без проблем.Но спасибо за информацию! - person Cato; 27.03.2017

Вы пробовали двигаться

   picture.releasePixelData(pPixels);

to

   finally
   {
       memStream.Dispose();
       picture.releasePixelData(pPixels);
   }

это определенно звучит как проблема с потоками (тем более, что вы заявляете, что releasePixelData может произойти в фоновом потоке). Проблемы с потоками всегда возникают только на одной машине и всегда на клиентской машине (вероятно, из-за того, что у них всего 256 мегабайт памяти или что-то нелепое, и сборщик мусора срабатывает рано, или машина имеет четырехъядерный процессор). и ваша машина разработчика двухъядерная или что-то в этом роде).

person Kris Erickson    schedule 06.02.2009