Image.Save (..) генерирует исключение GDI +, потому что поток памяти закрыт - PullRequest
103 голосов
/ 03 декабря 2008

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

это код:

[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.
}

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

Я действительно запутался: (

Ответы [ 14 ]

157 голосов
/ 03 декабря 2008

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

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

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

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

86 голосов
/ 04 апреля 2012

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

14 голосов
/ 26 октября 2011

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

4 голосов
/ 12 марта 2014

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

2 голосов
/ 15 января 2015

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

2 голосов
/ 31 марта 2010

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

При рисовании изображения: 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");
    }
1 голос
/ 07 февраля 2017

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

1 голос
/ 07 февраля 2014

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

1 голос
/ 19 ноября 2013

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

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;
    }
}
0 голосов
/ 30 июля 2018

Попробуйте этот код:

static void Main(string[] args)
{
    byte[] data = null;
    string fullPath = @"c:\testimage.jpg";

    using (MemoryStream ms = new MemoryStream())
    using (Bitmap tmp = (Bitmap)Bitmap.FromFile(fullPath))
    using (Bitmap bm = new Bitmap(tmp))
    {
        bm.SetResolution(96, 96);
        using (EncoderParameters eps = new EncoderParameters(1))
        {   
            eps.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
            bm.Save(ms, GetEncoderInfo("image/jpeg"), eps);
        }

        data = ms.ToArray();
    }

    File.WriteAllBytes(fullPath, data);
}

private static ImageCodecInfo GetEncoderInfo(string mimeType)
{
        ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();

        for (int j = 0; j < encoders.Length; ++j)
        {
            if (String.Equals(encoders[j].MimeType, mimeType, StringComparison.InvariantCultureIgnoreCase))
                return encoders[j];
        }
    return null;
}
...