Подтвердить что ты не робот

Общая ошибка произошла в GDI + при сохранении растрового изображения в MemoryStream

У меня есть код, который отлично работает на нескольких машинах (разработка, QA, UAT). К сожалению, на производстве я получаю "Общая ошибка в GDI +" на bmp.Save(ms, ImageFormat.Png);. В результате я предполагаю, что вы не сможете воспроизвести проблему, но, возможно, кто-то может обнаружить мою ошибку.

Несколько заметок, я много искал для общих решений, обратите внимание, что это сохраняется в MemoryStream, поэтому проблемы с правами на доступ к файлам, которые большинство людей предлагают, не применяются, а также не блокируется "bmp while open", потому что снова я пишу где-то еще. Наконец, это не потому, что для png требуется поток для поиска, потому что MemoryStream доступен для поиска.

Обратите внимание, что если я изменю его на ImageFormat.Jpeg, он отлично работает. У меня проблема с PNG. Я нашел упоминание раздела реестра HKEY_CLASSES_ROOT\CLSID\{FAE3D380-FEA4-4623-8C75-C6B61110B681}, потенциально являющегося проблемой из-за разрешений. В результате я установил ключ, чтобы позволить Everyone иметь доступ на чтение к этому ключу, без изменений.

public static MemoryStream GenerateImage(string text)
{
    MemoryStream ms = new MemoryStream();
    using (Bitmap bmp = new Bitmap(400,400))
    {
        bmp.Save(ms, ImageFormat.Png);
        ms.Position = 0;
    }
    return ms;
}

Вот полная трассировка стека:

[ExternalException (0x80004005): Общая ошибка произошла в GDI +.]
System.Drawing.Image.Save(поток потока, кодировщик ImageCodecInfo, EncoderParameters encoderParams) +616457
WP.Tools.Img.GenerateImage(String текст) +383

Примечание: мой вопрос уже перечисляет решения в предлагаемом дубликате. Ничего не стоит. Если бы они были, это не удавалось бы для JPEG.

4b9b3361

Ответ 1

Исходный код .NET-справочника здесь в случае сохранения в поток получает значение статуса из вызова метода native GdipSaveImageToStream

public void Save(Stream stream, ImageCodecInfo encoder, EncoderParameters encoderParams) {

    ...

    if (!saved)
    {
        status = SafeNativeMethods.Gdip.GdipSaveImageToStream(new HandleRef(this,nativeImage),new UnsafeNativeMethods.ComStreamFromDataStream(stream),ref g,new HandleRef(encoderParams, encoderParamsMemory));
    }

    ...

}

это значение статуса является единственным возвращаемым значением API, используемым для исключения исключения из этого метода. Когда мы смотрим дальше в функцию StatusException, которая решает, какое исключение выбрасывать на основе кода состояния, мы обнаруживаем только одно возможное значение статуса, которое приведет к полученному ExternalException (из Gdiplus.cs, строка 3167):

switch (status)
{
    case GenericError:
        return new ExternalException(SR.GetString(SR.GdiplusGenericError), E_FAIL);

    ...
}

0x80004005 - это "неуказанная ошибка", а SR.GdiplusGenericError - это текст "Общая ошибка, произошедшая в GDI +". ты получил. Это исключает несколько других возможностей, которые мы могли бы заподозрить (что приведет к разным исключениям), а именно:

  • вне памяти
  • объект занят
  • недостаточный буфер
  • win32error
  • valueoverflow
  • unknownimageformat
  • свойство не найдено/не поддерживается
  • unsupportedgdiplusversion

Нативный метод находится в gdiplus.dll. Короче говоря, запустите ваш производственный сервер, отремонтированный .NET framework. Подробнее:

  • сравнить версии этой DLL в% windir%\system32 между хорошо известными машинами и производственной машиной. DLL имеет сотни зависимостей, поэтому, даже если версия самого файла соответствует, см., Чтобы получить исправленную вашу ОС.
  • встроенный кодек для формата PNG является частью WIC-компонента Windows и находится в WindowsCodecs.dll и WindowsCodecsExt.dll - проверьте версии этих библиотеки. Вы также упомянули раздел реестра WindowsCodecsExt.dll.
  • не на основе recherche, просто идеи: вы получаете доступ к производственному серверу через соединение виртуализации/удаленного рабочего стола? Попробуйте консольный сеанс, если сможете. Попробуйте различные разрешения экрана и глубину цвета. Попробуйте сборку отладки/выпуска. Убедитесь, что вы действительно очистили проверку DEBUG в своей конфигурации сборки релиза. Попробуйте создать x64 и MSIL. Если вы используете NGEN для производства, попробуйте без него.