Общая ошибка произошла в 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:UsersIanSVNCaldooCaldoo.CoordinatorPhotoEditor.cs:line 139
   at Caldoo.Web.Controllers.PictureController.Croppable() in C:UsersIanSVNCaldooCaldoo.WebControllersPictureController.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: 

OK вещи, которые я пробовал до сих пор.

  1. клонирование изображения и работа над этим.
  2. получение кодировщика для этого MIME, передающего это с настройкой качества jpeg.

28 ответов


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

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

// 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;
 }

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

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

редактировать

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


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

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

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

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

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


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

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.


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

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

Итак, вместо

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

попробуй такое

Stream imageStream;
...

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

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


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

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

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

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

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


Сохранить изображение в переменную растрового изображения

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

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

другими словами, если бы я попытался сохранить "C:\Documents и настройки\myusername\локальные настройки\Temp\ABC DEF M1 трендовые значения \Images\picture.png " затем он выбросил общее исключение.

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


Это расширение / квалификация ответа Фреда, который заявил:"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.


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

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


Я также получил эту ошибку при сохранении 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's method: Convert it to a Bitmap first
    img = new Bitmap(img); 
    img.SaveJpeg(tmpFile, quality); // This is always successful
  }

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

Это моя функция SaveJpeg просто FYI:

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 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);        
}

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


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

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

надеюсь, что это помогает.


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

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


ошибка, возникающая из-за разрешения. убедитесь, что у папки есть все разрешения.

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")

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


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

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

Это произойдет!


моя очередь!

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

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


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

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


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

            default:
                format = ImageFormat.Jpeg;
                break;

вы уверены, что формат JPEG, а не что-то другое?

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

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

или imageToConvert.MimeType() на самом деле возвращаются.

обновление

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


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

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

new Bitmap(oldbitmap).Save(filename);

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


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);
}

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

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

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


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

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

перезапустить пул приложений исправить эту проблему.

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


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

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

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

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


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

image_instance = Image.FromFile(file_name);

вместо

image_instance.Load(file_name);

image_instance имеет тип System.Окна.Формы.Управления PictureBox! Picturebox'S Load () размещает поток, из которого было загружено изображение, и я этого не знал.


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

мой, казалось, был проблемой разрешения.