it-roy-ru.com

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

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

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

101
Pure.Krome

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

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

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

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

157
Jon Skeet

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

84
Houman

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

13
Rojzik

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

3
Morad Aktam

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

При рисовании изображения: 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");
    }
2
Brian Low

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

2
Jay K

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

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;
    }
}
1
Yuri Perekupko

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

1
P.Lisa

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

1
S.Roshanth

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

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;
}
0
BogdanRB

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

C:\Program Files (x86)\some_directory

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

0
Ali Ezzat Odeh

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

0
Vinothkumar

Для меня код ниже потерпел крах с 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);
                }
            }
        }
    }
0
mortb

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

Установка в качестве источника для элемента Image растрового изображения предотвращает сохранение файла . Даже установка Source = null, похоже, не освобождает файл.

Теперь я просто никогда не использую изображение в качестве элемента Source of Image, поэтому я могу переписать его после редактирования!

ПРАВКА

Услышав о свойстве CacheOption (спасибо @Nyerguds), я нашел решение: Поэтому вместо использования конструктора Bitmap я должен установить Uri после установки CacheOptionBitmapCacheOption.OnLoad. (Image1 ниже - это элемент Wpf Image)

Вместо

Image1.Source = new BitmapImage(new Uri(filepath));

Использование:

var image = new BitmapImage();
image.BeginInit();
image.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
image.CacheOption = BitmapCacheOption.OnLoad;
image.UriSource = new Uri(filepath);
image.EndInit();
Image1.Source = image;

Смотрите это: WPF Image Caching

0
mkb