Как найти причину ошибки Generic GDI + при сохранении изображения?
Имея код, который работает веками при загрузке и хранении изображений, я обнаружил, что у меня есть одно изображение, которое нарушает этот код:
const string i1Path = @"c:\my\i1.jpg"; const string i2Path = @"c:\my\i2.jpg"; var i = Image.FromFile(i1Path); i.Save(i2Path, ImageFormat.Jpeg);
Исключение составляет:
Возникло событие System.Runtime.InteropServices.ExternalException
- Как сделать снимок экрана с помощью элемента управления WPF?
- File.Delete не удалось, когда Image.FromFile был вызван до него, несмотря на то, что он сделал копию загруженного изображения и уничтожил оригинал
- Манипулирование изображениями с помощью .NET Core
- Выбор размера System.Drawing.Icon?
- Захват экрана на сеансе рабочего стола сервера
Общая ошибка произошла в GDI +.
в System.Drawing.Image.Save (String filename, кодировщик ImageCodecInfo, EncoderParameters encoderParams)
в System.Drawing.Image.Save (String filename, формат ImageFormat)
в …
Насколько я вижу, в изображении нет ничего особенного. Он имеет размер около 250 пикселей и может быть открыт, например, Windows Image Viewer или Paint.NET:
(Так как изображение выше, после загрузки в Stack Overflow больше не приводит к ошибке, я поместил исходное изображение здесь )
Я обнаружил, что при вызове метода Save
файл образа назначения создается с нулевыми байтами.
Я действительно не знаю, что вызывает ошибку.
Мои вопросы:
- Можете ли вы придумать какую-либо особую вещь, которая помешала бы .NET сохранить изображение?
- Есть ли способ (помимо панировки) сузить подобные ошибки?
В то время как я все еще не выяснил причину того, что именно вызвало ошибку при сохранении изображения, я нашел обходное решение:
const string i1Path = @"c:\my\i1.jpg"; const string i2Path = @"c:\my\i2.jpg"; var i = Image.FromFile(i1Path); var i2 = new Bitmap(i); i2.Save(i2Path, ImageFormat.Jpeg);
Т.е. путем копирования изображения внутри экземпляра Bitmap
и сохранения этого изображения вместо исходного изображения ошибка исчезла.
Я предполагаю, что, скопировав его, ошибочные части, вызванные сбоем первоначального вызова Save
, удаляются или нормализуются, что позволяет успешно завершить операцию сохранения.
Интересно, что у сохраненного изображения есть меньший файл на диске (16 kB), чем его исходный источник (26 kB).
Прежде всего убедитесь, что желаемая папка имеет разрешения на чтение / запись. Изменение разрешений решило эту проблему для меня.
Решение здесь, вы должны удалить объект изображения, чтобы освободить память на сервере. Попробуйте использовать инструкцию using
. Убедитесь, что каталог назначения на сервере существует.
мое решение состояло в том, чтобы написать, написать временный контент (File.WriteAllText) непосредственно перед сохранением файла
Вот код:
var i = Image.FromFile(i1Path); File.WriteAllText(i2Path, "empty"); // <---- magic goes here i.Save(i2Path, ImageFormat.Jpeg);
Пожалуйста, дайте мне знать
Причина может заключаться в том, что изображение загружается лениво, и процесс загрузки еще не завершен, когда вы пытаетесь его сохранить.
Следуя тому, что было сказано в этом сообщении в блоге (предполагая, что вы немецкий на картинке, которую вы связали в своем вопросе), можно найти возможное решение. Также принятый ответ этого вопроса указывает, что это связано с тем, что файл изображения, который вы пытаетесь сохранить, заблокирован.
РЕДАКТИРОВАТЬ
Для Ulysses Alves из связанной записи в блоге: если вы загружаете изображение с помощью Image.FromFile()
оно остается заблокированным до его удаления. Это предотвращает вызовы Save()
.
pictureBox1.Image = Image.FromFile("C:\\test\\test1.jpg"); pictureBox1.Image.Save("C:\\test\\test2.jpg");
Вышеприведенный код вызывает ошибку.
Чтобы заставить его работать, вам нужно скопировать изображение. Следующий код работает:
pictureBox1.Image = Image.FromFile("C:\\test\\test1.jpg"); Image copy = pictureBox1.Image; copy.Save("C:\\test\\test2.jpg")
Открыть в программе
const string i1Path = @"c:\my\i1.jpg"; const string i2Path = @"c:\my\i2.jpg"; var i = Image.FromFile(i1Path); i.Save(i2Path, ImageFormat.Jpeg); i.Dispose();