Общая ошибка произошла в 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 в свойствах проекта.