Image.Save(..) генерирует исключение GDI +, поскольку поток памяти закрыт

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

это код:

[TestMethod]
public void TestMethod1()
{
    // Grab the binary data.
    byte[] data = File.ReadAllBytes("Chick.jpg");

    // Read in the data but do not close, before using the stream.
    Stream originalBinaryDataStream = new MemoryStream(data);
    Bitmap image = new Bitmap(originalBinaryDataStream);
    image.Save(@"c:\test.jpg");
    originalBinaryDataStream.Dispose();

    // Now lets use a nice dispose, etc...
    Bitmap2 image2;
    using (Stream originalBinaryDataStream2 = new MemoryStream(data))
    {
        image2 = new Bitmap(originalBinaryDataStream2);
    }

    image2.Save(@"C:\temp\pewpew.jpg"); // This throws the GDI+ exception.
}

Есть ли у кого-нибудь предложения, как я могу сохранить изображение с закрытым потоком? Я не могу полагаться на разработчиков, чтобы не забудьте закрыть поток после сохранения изображения. Фактически у разработчика не было бы ИДЕИ, чтобы изображение было сгенерировано с использованием потока памяти (потому что это происходит в другом коде, в другом месте).

Я действительно смущен: (

Ответ 1

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

Однако вам следует удалять битмап - и это закроет поток для вас. В принципе, когда вы даете конструктору Bitmap поток, он "владеет" потоком, и вы не должны его закрывать. Как документы для этого конструктора говорят:

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

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

Ответ 2

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

Ответ 3

Возможно, стоит упомянуть, что если каталог C:\Temp не существует, он также выкинет это исключение, даже если ваш поток все еще существует.

Ответ 4

У меня была та же проблема, но на самом деле причина заключалась в том, что у приложения не было разрешения на сохранение файлов на C. Когда я изменился на "D: \..", изображение было сохранено.

Ответ 5

Эта ошибка возникла у меня, когда я пытался использовать Citrix. Папка изображения была установлена ​​на C:\на сервере, для которой у меня нет привилегий. После того, как папка с изображениями была перенесена на общий диск, ошибка исчезла.

Ответ 6

Скопировать растровое изображение. Вы должны держать поток открытым для жизни растрового изображения.

При рисовании изображения: System.Runtime.InteropServices.ExternalException: Общая ошибка в GDI

    public static Image ToImage(this byte[] bytes)
    {
        using (var stream = new MemoryStream(bytes))
        using (var image = Image.FromStream(stream, false, true))
        {
            return new Bitmap(image);
        }
    }

    [Test]
    public void ShouldCreateImageThatCanBeSavedWithoutOpenStream()
    {
        var imageBytes = File.ReadAllBytes("bitmap.bmp");

        var image = imageBytes.ToImage();

        image.Save("output.bmp");
    }

Ответ 7

Вы можете попытаться создать другую копию растрового изображения:

using (var memoryStream = new MemoryStream())
{
    // write to memory stream here

    memoryStream.Position = 0;
    using (var bitmap = new Bitmap(memoryStream))
    {
        var bitmap2 = new Bitmap(bitmap);
        return bitmap2;
    }
}

Ответ 8

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

Ответ 9

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

Ответ 10

Одно странное решение, которое заставило мой код работать. Откройте изображение в краске и сохраните его как новый файл с таким же форматом (.jpg). Теперь попробуйте этот новый файл, и он работает. Это ясно объясняет вам, что файл может быть поврежден каким-то образом. Это может помочь только в том случае, если в вашем коде исправлены все другие ошибки.

Ответ 11

Он также появился со мной, когда я пытался сохранить изображение в пути

C:\Program Files (x86)\some_directory

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

Ответ 12

Для меня код ниже разбился с A generic error occurred in GDI+ на строке, которая сохраняет значение MemoryStream. Код выполнялся на веб-сервере, и я разрешил его, остановив и запустив пул приложений, на котором был запущен сайт.

Должна быть некоторая внутренняя ошибка в GDI +

    private static string GetThumbnailImageAsBase64String(string path)
    {
        if (path == null || !File.Exists(path))
        {
            var log = ContainerResolver.Container.GetInstance<ILog>();
            log.Info($"No file was found at path: {path}");
            return null;
        }

        var width = LibraryItemFileSettings.Instance.ThumbnailImageWidth;

        using (var image = Image.FromFile(path))
        {
            using (var thumbnail = image.GetThumbnailImage(width, width * image.Height / image.Width, null, IntPtr.Zero))
            {
                using (var memoryStream = new MemoryStream())
                {
                    thumbnail.Save(memoryStream, ImageFormat.Png); // <= crash here 
                    var bytes = new byte[memoryStream.Length];
                    memoryStream.Position = 0;
                    memoryStream.Read(bytes, 0, bytes.Length);
                    return Convert.ToBase64String(bytes, 0, bytes.Length);
                }
            }
        }
    }