Общая ошибка произошла в GDI +, JPEG-изображении в MemoryStream

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

Странно, что это отлично работает с png, но дает вышеприведенную ошибку с jpg и gif, что довольно запутывает.

Большинство подобных проблем связаны с сохранением изображений в файлах без разрешений. По иронии судьбы решение заключается в использовании потока памяти, как я делаю....

public static byte[] ConvertImageToByteArray(Image imageToConvert)
{
    using (var ms = new MemoryStream())
    {
        ImageFormat format;
        switch (imageToConvert.MimeType())
        {
            case "image/png":
                format = ImageFormat.Png;
                break;
            case "image/gif":
                format = ImageFormat.Gif;
                break;
            default:
                format = ImageFormat.Jpeg;
                break;
        }

        imageToConvert.Save(ms, format);
        return ms.ToArray();
    }
}

Подробнее об исключении. Причина, по которой возникает так много проблем, заключается в отсутствии объяснений: (

System.Runtime.InteropServices.ExternalException was unhandled by user code
Message="A generic error occurred in GDI+."
Source="System.Drawing"
ErrorCode=-2147467259
StackTrace:
   at System.Drawing.Image.Save(Stream stream, ImageCodecInfo encoder, EncoderParameters    encoderParams)
   at System.Drawing.Image.Save(Stream stream, ImageFormat format)
   at Caldoo.Infrastructure.PhotoEditor.ConvertImageToByteArray(Image imageToConvert) in C:\Users\Ian\SVN\Caldoo\Caldoo.Coordinator\PhotoEditor.cs:line 139
   at Caldoo.Web.Controllers.PictureController.Croppable() in C:\Users\Ian\SVN\Caldoo\Caldoo.Web\Controllers\PictureController.cs:line 132
   at lambda_method(ExecutionScope , ControllerBase , Object[] )
   at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters)
   at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
   at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClassa.<InvokeActionMethodWithFilters>b__7()
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
 InnerException: 

Хорошо, что я пробовал до сих пор.

  • Клонирование изображения и работа над этим.
  • Возврат кодера для этого MIME-передачи, который с настройкой качества jpeg.

Ответ 1

ОК. Кажется, я нашел причину просто из-за удачи и ничего плохого в этом конкретном методе, это еще больше подкрепляет стек вызовов.

Раньше я изменял размер изображения и как часть этого метода возвращаю измененный объект следующим образом. Я вставил два вызова вышеописанного метода и прямое сохранение в файл.

// At this point the new bitmap has no MimeType
// Need to output to memory stream
using (var m = new MemoryStream())
{
       dst.Save(m, format);

       var img = Image.FromStream(m);

       //TEST
       img.Save("C:\\test.jpg");
       var bytes = PhotoEditor.ConvertImageToByteArray(img);


       return img;
 }

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

Я только возвращаюсь из потока, потому что после использования кода изменения размера, подобного this, в целевом файле есть неизвестный тип mime (img.RawFormat.Guid) и Id тип Mime должен быть правильным на всех объектах изображения, так как он в противном случае затрудняет запись общего кода обработки.

ИЗМЕНИТЬ

Это не произошло в моем первоначальном поиске, но вот ответ от Jon Skeet

Ответ 2

Если вы получаете эту ошибку, я могу сказать, что ваше приложение не имеет права на запись в какой-либо каталог.

Например, если вы пытаетесь сохранить изображение из потока памяти в файловую систему, вы можете получить эту ошибку.

Пожалуйста, если вы используете XP, не забудьте добавить разрешение записи для учетной записи aspnet в этой папке.

Если вы используете сервер Windows (2003,2008) или Vista, убедитесь, что добавили права на запись для учетной записи службы сети.

Надеюсь, что это поможет кому-то.

Ответ 3

Я добавлю эту причину ошибки, а также надеюсь, что она поможет будущему интернет-путешественнику.:)

GDI + ограничивает максимальную высоту изображения до 65500

Мы делаем базовое изменение размера изображения, но при изменении размера мы стараемся поддерживать соотношение сторон. У нас есть парень с QA, который слишком хорошо справляется с этой работой; он решил проверить это с помощью одной фотографии с широким пикселом, которая была 480 пикселей в высоту. Когда изображение было масштабировано, чтобы соответствовать нашим измерениям, высота была севернее 68 000 пикселей, и наше приложение взорвалось с помощью A generic error occurred in GDI+.

Вы можете проверить это самостоятельно с помощью теста:

  int width = 480;
  var height = UInt16.MaxValue - 36; //succeeds at 65499, 65500
  try
  {
    while(true)
    {
      var image = new Bitmap(width, height);
      using(MemoryStream ms = new MemoryStream())
      {
        //error will throw from here
        image.Save(ms, ImageFormat.Jpeg);
      }
      height += 1;
    }
  }
  catch(Exception ex)
  {
    //explodes at 65501 with "A generic error occurred in GDI+."
  }

Слишком плохо, что нет дружественного .net ArgumentException, брошенного в конструкторе Bitmap.

Ответ 4

В этой статье подробно объясняется, что именно происходит: зависимости растрового изображения и изображения

Короче говоря, для жизни Image, построенного из потока, поток не должен быть уничтожен.

Итак, вместо

using (var strm = new ... )  {
    myImage = Image.FromStream(strm);
}

попробуйте это

Stream imageStream;
...

    imageStream = new ...;
    myImage = Image.FromStream(strm);

и закрыть imageStream в закрытии формы или закрыть веб-страницу.

Ответ 5

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

Если вы не на 100% уверены, что путь к файлу доступен, а права правильные, попробуйте записать текст в текстовый файл. Это займет всего несколько секунд, чтобы исключить, что было бы очень простым исправлением.

var img = System.Drawing.Image.FromStream(incomingStream);

// img.Save(path);
System.IO.File.WriteAllText(path, "Testing valid path & permissions.");

И не забудьте очистить файл.

Ответ 6

Сохранить изображение в битмап-переменной

using (var ms = new MemoryStream())
{
    Bitmap bmp = new Bitmap(imageToConvert);
    bmp.Save(ms, format);
    return ms.ToArray();
}

Ответ 7

На всякий случай, если кто-то делает так глупо, как я. 1. Убедитесь, что путь существует. 2. Убедитесь, что у вас есть разрешения на запись. 3. убедитесь, что ваш путь верен, в моем случае я потерял имя файла в TargetPath: (

он должен был сказать, ваш путь отстой, чем "Общая ошибка, произошедшая в GDI +"

Ответ 8

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

Другими словами, если я попытался сохранить в "C:\Documents and Settings\myusername\Local Settings\Temp\ABC DEF M1 Trends Values ​​\ Images\picture.png", то он выбросил общее исключение.

Имя моей папки генерировалось из имени файла, у которого было завершающее пространство, поэтому было легко использовать .Trim() и двигаться дальше.

Ответ 9

Я также получил эту ошибку при сохранении JPEG, но только для определенных изображений.

Мой окончательный код:

  try
  {
    img.SaveJpeg(tmpFile, quality); // This is always successful for say image1.jpg, but always throws the GDI+ exception for image2.jpg
  }
  catch (Exception ex)
  {
    // Try HU method: Convert it to a Bitmap first
    img = new Bitmap(img); 
    img.SaveJpeg(tmpFile, quality); // This is always successful
  }

Я не создавал изображения, поэтому я не могу сказать, в чем разница.
Буду признателен, если кто-нибудь сможет это объяснить.

Это моя функция SaveJpeg просто для справки:

private static void SaveJpeg(this Image img, string filename, int quality)
{
  EncoderParameter qualityParam = new EncoderParameter(Encoder.Quality, (long)quality);
  ImageCodecInfo jpegCodec = GetEncoderInfo("image/jpeg");
  EncoderParameters encoderParams = new EncoderParameters(1);
  encoderParams.Param[0] = qualityParam;
  img.Save(filename, jpegCodec, encoderParams);
}

private static ImageCodecInfo GetEncoderInfo(string mimeType)
{
    var encoders = ImageCodecInfo.GetImageEncoders();
    var encoder = encoders.SingleOrDefault(c => string.Equals(c.MimeType, mimeType, StringComparison.InvariantCultureIgnoreCase));
    if (encoder == null) throw new Exception($"Encoder not found for mime type {mimeType}");
    return encoder;
}

Ответ 10

Это расширение/квалификация Fred-ответа, в котором говорится: "GDI ограничивает высоту изображения до 65534". Мы столкнулись с этой проблемой с одним из наших приложений .NET, и, увидев сообщение, наша команда аутсорсинга подняла руки в воздухе и сказала, что они не могут решить проблему без серьезных изменений.

Основываясь на моем тестировании, можно создавать/обрабатывать изображения с высотой более 65534, но проблема возникает при сохранении в потоке или файле В НЕКОТОРЫХ ФОРМАХ. В следующем коде вызов метода t.Save() выдает нашему другу общее исключение, когда высота пикселя составляет 65501 для меня. По соображениям любопытства я повторил тест на ширину и тот же самый предел, примененный к сохранению.

    for (int i = 65498; i <= 100000; i++)
    {
        using (Bitmap t = new Bitmap(800, i))
        using (Graphics gBmp = Graphics.FromImage(t))
        {
            Color green = Color.FromArgb(0x40, 0, 0xff, 0);
            using (Brush greenBrush = new SolidBrush(green))
            {
                // draw a green rectangle to the bitmap in memory
                gBmp.FillRectangle(greenBrush, 0, 0, 799, i);
                if (File.Exists("c:\\temp\\i.jpg"))
                {
                    File.Delete("c:\\temp\\i.jpg");
                }
                t.Save("c:\\temp\\i.jpg", ImageFormat.Jpeg);
            }
        }
        GC.Collect();
    }

Такая же ошибка возникает и при записи в поток памяти.

Чтобы обойти это, вы можете повторить вышеуказанный код и заменить ImageFormat.Tiff или ImageFormat.Bmp для ImageFormat.Jpeg.

Это соответствует высоте/ширине 100 000 для меня - я не тестировал пределы. Как это бывает. Tiff был для нас жизнеспособным вариантом.

ПРЕДУПРЕЖДЕНИЕ

Потоки/файлы TIFF в памяти потребляют больше памяти, чем их JPG-копии.

Ответ 11

если ваш код выглядит следующим образом, и эта ошибка возникает

private Image GetImage(byte[] byteArray)
{
   using (var stream = new MemoryStream(byteArray))
   {
       return Image.FromStream(stream);
    }
}

Правильный -

private Image GetImage(byte[] byteArray)
{
   var stream = new MemoryStream(byteArray))
   return Image.FromStream(stream);        
}

Это может быть потому, что мы возвращаемся из блока использования

Ответ 12

Была очень похожая проблема, а также попытался клонировать изображение, которое не работает. Я обнаружил, что лучшим решением было создание нового объекта Bitmap из изображения, загруженного из потока памяти. Таким образом, поток может быть удален, например,

using (var m = new MemoryStream())
{
    var img = new Bitmap(Image.FromStream(m));
    return img;
}

Надеюсь, что это поможет.

Ответ 13

SOLVED - У меня была эта точная проблема. Исправить, для меня, было увеличение дисковой квоты для IUSR на сервере IIS. В этом случае у нас есть приложение для каталога с изображениями предметов и т.д. Квота для загрузки для "Анонимного веб-пользователя" была установлена ​​в 100 МБ, что является значением по умолчанию для этих серверов IIS хостинговой компании. Я повысил его до 400 МБ и смог загружать изображения без ошибок.

Возможно, это не ваша проблема, но если это так, это легко исправить.

Ответ 14

Ошибка из-за разрешения. убедитесь, что папка имеет ВСЕ РАЗРЕШЕНИЕ.

public Image Base64ToImage(string base64String)
    {
        // Convert Base64 String to byte[]
        byte[] imageBytes = Convert.FromBase64String(base64String);
        MemoryStream ms = new MemoryStream(imageBytes, 0,
          imageBytes.Length);

        // Convert byte[] to Image
        ms.Write(imageBytes, 0, imageBytes.Length);
        Image image = Image.FromStream(ms, true);
        return image;
    }

 img.Save("YOUR PATH TO SAVE IMAGE")

Ответ 15

В моем случае проблема была в пути, который я сохранял (корень C:\). Изменив его на D:\111\, исключение исчезло.

Ответ 16

Другая причина этой ошибки - путь, который вы указываете в методе сохранения экземпляра Bitmap, не существует или вы не указали полный/допустимый путь.

Просто была эта ошибка, потому что я проходил через имя файла, а не полный путь!

Это происходит!

Ответ 17

Моя очередь!

using (System.Drawing.Image img = Bitmap.FromFile(fileName))
{
      ... do some manipulation of img ...
      img.Save(fileName, System.Drawing.Imaging.ImageFormat.Jpeg);
}

Получил его на .Save... потому что using() удерживает файл открытым, поэтому я не могу его перезаписать. Возможно, это поможет кому-то в будущем.

Ответ 18

Та же проблема, с которой я столкнулся. Но в моем случае я пытался сохранить файл на диске C, и он был недоступен. Поэтому я попытался сохранить в D диск, который был полностью доступен, и мне это удалось.

Итак, сначала проверьте свои папки, в которых вы пытаетесь сохранить. Вы должны иметь все права (для чтения и записи) для этой конкретной папки.

Ответ 19

Я заметил, что ваш случай "jpeg" на самом деле:

            default:
                format = ImageFormat.Jpeg;
                break;

Вы уверены, что формат jpeg, а не что-то еще?

Я бы попробовал:

            case "image/jpg": // or "image/jpeg" !
                format = ImageFormat.Jpeg;
                break;

Или проверьте, что действительно возвращается imageToConvert.MimeType().

UPDATE

Есть ли другая инициализация, которую нужно сделать для объекта MemoryStream?

Ответ 20

Просто, чтобы добавить другое возможное решение, я упомяну случай, с которым столкнулся, с этим сообщением об ошибке. Метод Bitmap.Save это исключение при сохранении растрового изображения, которое я преобразовал и отображал. Я обнаружил, что оно не будет генерировать исключение, если в операторе есть точка останова, и не будет, если Bitmap.Save предшествует Thread.Sleep(500) так что я предполагаю, что происходит какое-то соперничество за ресурсы.

Простого копирования изображения в новый растровый объект было достаточно для предотвращения появления этого исключения:

new Bitmap(oldbitmap).Save(filename);

Ответ 21

  • У меня была эта проблема на тестовом сервере, но не на реальном сервере.
  • Я писал изображение в поток, поэтому это не было проблемой разрешения.
  • Я непосредственно развертывал некоторые из .dll на тестовом сервере.
  • Развертывание всего решения устранило проблему, поэтому, возможно, это было странное несоответствие компиляции

Ответ 22

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

Ответ 23

byte[] bts = (byte[])page1.EnhMetaFileBits; 
using (var ms = new MemoryStream(bts)) 
{ 
    var image = System.Drawing.Image.FromStream(ms); 
    System.Drawing.Image img = image.GetThumbnailImage(200, 260, null, IntPtr.Zero);      
    img.Save(NewPath, System.Drawing.Imaging.ImageFormat.Png);
}

Ответ 24

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

Убедитесь, что вы не сохраняете изображения с дублирующимся именем.

Используйте, например, функцию "Случайный" (Как работает генератор случайных чисел С#?) или, например, генерировать Guid (http://betterexplained.com/articles/the-quick-guide-to-guids/)

Ответ 25

у нас была такая же проблема при создании PDF на рабочем сервере.

Перезапустите пул приложений, чтобы устранить проблему.

Надеюсь, это поможет кому-то.

Ответ 26

Для меня я использовал Image.Save(Stream, ImageCodecInfo, EncoderParameters) и, видимо, это вызывало печально известную ошибку A generic error occurred in GDI+.

Я пытался использовать EncoderParameter для сохранения jpegs со 100% качеством. Это отлично работало на "моей машине" (doh!), А не на производстве.

Когда я использовал Image.Save(Stream, ImageFormat), ошибка исчезла! Так что, как идиот, я продолжал использовать последний, хотя он сохраняет их по умолчанию, и я предполагаю, что это всего лишь 50%.

Надеюсь, эта информация поможет кому-то.

Ответ 27

Я тоже столкнулся с проблемой. Проблема была связана с размещением загружаемого потока. Но я не распоряжался им, это было внутри .Net framework. Все, что мне нужно было сделать, это использовать:

image_instance = Image.FromFile(file_name);

вместо

image_instance.Load(file_name);

image_instance имеет тип System.Windows.Forms.PictureBox! PictureBox Load() создает поток, из которого было загружено изображение, и я этого не знал.

Ответ 28

На основе ответа от @savindra, если вы RHM в своем приложении и попробуйте запустить администратор, то он должен решить вашу проблему.

Шахта, похоже, была проблемой разрешения.

Ответ 29

Все просто, создание нового экземпляра Bitmap решает проблему.

string imagePath = Path.Combine(Environment.CurrentDirectory, $"Bhatti{i}.png");
Bitmap bitmap = new Bitmap(image);
bitmap.Save(imagePath);

Ответ 30

Мое консольное приложение получило то же сообщение об ошибке: "Произошла общая ошибка в GDI+". Ошибка произошла в строке newImage.Save, как указано в следующем коде.

for (int i = 1; i <= 1000; i++)
{
   Image newImage = Image.FromFile(@"Sample.tif");
   //...some logic here
   newImage.Save(i + ".tif", , ImageFormat.Tiff);
}

Программа возвратила ошибку, когда объем используемой оперативной памяти составляет около 4 ГБ, и сумела устранить ее, изменив целевую программу на x64 в свойствах проекта.