Как найти причину ошибки 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

Общая ошибка произошла в GDI +.

в System.Drawing.Image.Save(имя файла String, кодер ImageCodecInfo, EncoderParameters encoderParams)
  в System.Drawing.Image.Save(имя файла String, формат ImageFormat)
  при...

Насколько я вижу, в изображении нет ничего особенного. Он имеет размер около 250 пикселей и может быть открыт, например. Windows Image Viewer или Paint.NET:

enter image description here

(Так как изображение выше, после загрузки в Qaru больше не вызывает ошибку, я разместил исходное изображение здесь)

Я обнаружил, что при вызове метода Save целевой файл образа создается с нулевыми байтами.

Я действительно не знаю, что вызывает ошибку.

Мои вопросы:

  • Можете ли вы придумать какую-либо особую вещь, которая помешала бы .NET сохранить изображение?
  • Есть ли способ (помимо панировки) сузить такие ошибки?

Ответ 1

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

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 для отказа, удаляются/или нормализуются, что позволяет успешно выполнить операцию сохранения.

saved image i2.jpg

Интересно, что сохраненное изображение имеет меньший файл на диске (16 kB), чем его исходный источник (26 kB).

Ответ 2

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

Ответ 3

Решение здесь, вы должны удалить объект изображения, чтобы освободить память на сервере. Попробуйте использовать оператор using. Убедитесь, что каталог назначения на сервере существует.

Ответ 4

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

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

ИЗМЕНИТЬ
Для 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")

Ответ 5

Мое решение состояло в том, чтобы сделать, написать временный контент (File.WriteAllText) непосредственно перед сохранением файла

Вот код:

var i = Image.FromFile(i1Path);
File.WriteAllText(i2Path, "empty");  // <---- magic goes here
i.Save(i2Path, ImageFormat.Jpeg);

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

Ответ 6

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

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

НЕ РАБОТАЕТ:

Image patternImage;

using (var ms = new MemoryStream(patternBytes)) {
    patternImage = new Bitmap(ms);
}

patternImage.Save(patternFile, ImageFormat.Jpeg);

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

РАБОТАЕТ:

using (var ms = new MemoryStream(patternBytes)) {
    patternImage = new Bitmap(ms);
    patternImage.Save(patternFile, ImageFormat.Jpeg);
}

Что вводит в заблуждение:

  • Сообщение об ошибке на самом деле ничего не говорит вам
  • Вы можете видеть свойства изображения, такие как ширина и высота, но не можете сохранить его

Ответ 7

Открыть в программе

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

Ответ 8

Ключевая информация:

// Using System.Drawing.Imaging:
new Bitmap(image).Save(memoryStream, ImageFormat.Jpeg);

Вы ДОЛЖНЫ преобразовать изображение в растровое изображение, чтобы сохранить его.

С помощью:

// Using System.Drawing.Imaging:
image.Save(memoryStream, ImageFormat.Jpeg);

БУДЕТ сгенерировать ошибку:

Общая ошибка GDI+ при сохранении изображения

Ответ 9

Проблема заключается в том, что вы не можете сохранить в корневом разделе диска C:. Сохраните в другом месте, и у вас не будет проблем.