Image.Save(..) 抛出一个 GDI+ 异常,因为内存流已关闭

发布于 2024-07-09 13:16:47 字数 925 浏览 5 评论 0原文

我有一些二进制数据,我想将其保存为图像。 当我尝试保存图像时,如果用于创建图像的内存流在保存之前已关闭,则会引发异常。 我这样做的原因是因为我正在动态创建图像,因此..我需要使用内存流。

这是代码:

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

有人对如何在关闭流的情况下保存图像有任何建议吗? 我不能指望开发人员记得在保存图像后关闭流。 事实上,开发人员不知道图像是使用内存流生成的(因为它发生在其他地方的其他代码中)。

我真的很困惑:(

i've got some binary data which i want to save as an image. When i try to save the image, it throws an exception if the memory stream used to create the image, was closed before the save. The reason i do this is because i'm dynamically creating images and as such .. i need to use a memory stream.

this is the code:

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

Does anyone have any suggestions to how i could save an image with the stream closed? I cannot rely on the developers to remember to close the stream after the image is saved. In fact, the developer would have NO IDEA that the image was generated using a memory stream (because it happens in some other code, elsewhere).

I'm really confused :(

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(17

淤浪 2024-07-16 13:16:47

因为它是一个 MemoryStream,所以您实际上不需要关闭该流 - 如果您不关闭流,也不会发生什么不好的事情,尽管显然处置任何一次性的东西是一个很好的做法。 (有关此问题的更多信息,请参阅此问题。)

但是,您应该处理位图 - 并且将为您关闭流。 基本上,一旦您为位图构造函数提供了一个流,它就“拥有”该流,并且您不应该关闭它。 正如该构造函数的文档所说:

您必须保持流打开
位图的生命周期。

我找不到任何承诺在处置位图时关闭流的文档,但您应该能够相当容易地验证这一点。

As it's a MemoryStream, you really don't need to close the stream - nothing bad will happen if you don't, although obviously it's good practice to dispose anything that's disposable anyway. (See this question for more on this.)

However, you should be disposing the Bitmap - and that will close the stream for you. Basically once you give the Bitmap constructor a stream, it "owns" the stream and you shouldn't close it. As the docs for that constructor say:

You must keep the stream open for the
lifetime of the Bitmap.

I can't find any docs promising to close the stream when you dispose the bitmap, but you should be able to verify that fairly easily.

沫离伤花 2024-07-16 13:16:47

GDI+ 中发生一般错误。
也可能是由于保存路径不正确造成的!
我花了半天才注意到这一点。
因此,请确保您也仔细检查了保存图像的路径。

A generic error occurred in GDI+.
May also result from incorrect save path!
Took me half a day to notice that.
So make sure that you have double checked the path to save the image as well.

凡间太子 2024-07-16 13:16:47

也许值得一提的是,如果 C:\Temp 目录不存在,即使您的流仍然存在,它也会抛出此异常。

Perhaps it is worth mentioning that if the C:\Temp directory does not exist, it will also throw this exception even if your stream is still existent.

在巴黎塔顶看东京樱花 2024-07-16 13:16:47

复制位图。 您必须在位图的生命周期内保持流打开。

绘制图像时: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");
    }

Copy the Bitmap. You have to keep the stream open for the lifetime of the bitmap.

When drawing an image: System.Runtime.InteropServices.ExternalException: A generic error occurred in 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");
    }
简单 2024-07-16 13:16:47

我也遇到了同样的问题,但实际上原因是应用程序没有权限在 C 上保存文件。当我更改为“D:\..”时,图片已保存。

I had the same problem but actually the cause was that the application didn't have permission to save files on C. When I changed to "D:\.." the picture has been saved.

青巷忧颜 2024-07-16 13:16:47

您可以尝试创建位图的另一个副本:

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

You can try to create another copy of bitmap:

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;
    }
}
流云如水 2024-07-16 13:16:47

当我尝试使用 Citrix 时,出现了此错误。 图像文件夹设置为服务器中的 C:\,我没有权限。 将图像文件夹移动到共享驱动器后,错误就消失了。

This error occurred to me when I was trying from Citrix. The image folder was set to C:\ in the server, for which I do not have privilege. Once the image folder was moved to a shared drive, the error was gone.

浅浅 2024-07-16 13:16:47

GDI+ 中发生一般错误。 它可能是由于图像存储路径问题而发生的,我收到此错误是因为我的存储路径太长,我通过首先将图像存储在最短路径中并使用长路径处理技术将其移动到正确的位置来解决此问题。

A generic error occurred in GDI+. It can occur because of image storing paths issues,I got this error because my storing path is too long, I fixed this by first storing the image in a shortest path and move it to the correct location with long path handling techniques.

皇甫轩 2024-07-16 13:16:47

我收到此错误,因为我正在执行的自动化测试试图将快照存储到不存在的文件夹中。 创建文件夹后,错误解决了

I was getting this error, because the automated test I was executing, was trying to store snapshots into a folder that didn't exist. After I created the folder, the error resolved

南城旧梦 2024-07-16 13:16:47

一种奇怪的解决方案使我的代码能够工作。
在paint中打开图像并将其另存为具有相同格式的新文件(.jpg)。 现在尝试使用这个新文件,它可以工作。 它清楚地向您解释该文件可能以某种方式损坏。
仅当您的代码修复了所有其他错误时这才有帮助

One strange solution which made my code to work.
Open the image in paint and save it as a new file with same format(.jpg). Now try with this new file and it works. It clearly explains you that the file might be corrupted in someway.
This can help only if your code has every other bugs fixed

川水往事 2024-07-16 13:16:47

当我尝试将图像保存到路径

C:\Program Files (x86)\some_directory

.exe 未执行运行时, 它也出现在我身上作为管理员,我希望这可以帮助也有同样问题的人。

It has also appeared with me when I was trying to save an image into path

C:\Program Files (x86)\some_directory

and the .exe wasn't executed to run as administrator, I hope this may help someone who has same issue too.

寄意 2024-07-16 13:16:47

对我来说,下面的代码崩溃了,并在保存到MemoryStream的行上发生了GDI+中发生一般错误。 该代码在 Web 服务器上运行,我通过停止并启动正在运行该站点的应用程序池来解决该问题。

一定是 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);
                }
            }
        }
    }

For me the code below crashed with A generic error occurred in GDI+on the line which Saves to a MemoryStream. The code was running on a web server and I resolved it by stopping and starting the Application Pool that was running the site.

Must have been some internal error in 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);
                }
            }
        }
    }
无言温柔 2024-07-16 13:16:47

当我在 WPF 应用程序中尝试进行简单的图像编辑时,遇到了此错误。

将图像元素的源设置为位图会阻止文件保存。
即使设置 Source=null 似乎也不会释放该文件。

现在我只是从不使用图像作为图像元素的源,所以我可以在编辑后覆盖!

编辑

在听说 CacheOption 属性后(感谢@Nyerguds)我找到了解决方案:
因此,我必须在设置 CacheOption BitmapCacheOption.OnLoad 之后设置 Uri,而不是使用 Bitmap 构造函数。(下面的 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 图像缓存

I came across this error when I was trying a simple image editing in a WPF app.

Setting an Image element's Source to the bitmap prevents file saving.
Even setting Source=null doesn't seem to release the file.

Now I just never use the image as the Source of Image element, so I can overwrite after editing!

EDIT

After hearing about the CacheOption property(Thanks to @Nyerguds) I found the solution:
So instead of using the Bitmap constructor I must set the Uri after setting CacheOption BitmapCacheOption.OnLoad.(Image1 below is the Wpf Image element)

Instead of

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

Use:

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

See this: WPF Image Caching

左秋 2024-07-16 13:16:47

试试这个代码:

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

Try this code:

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;
}
橘味果▽酱 2024-07-16 13:16:47

我使用图像处理器调整图像大小,有一天我收到“GDI+ 中发生一般错误”异常。

查找了一段时间后,我尝试回收应用程序池,结果成功了。 所以我在这里记下来,希望它有所帮助;)

干杯

I used imageprocessor to resize images and one day I got "A generic error occurred in GDI+" exception.

After looked up a while I tried to recycle the application pool and bingo it works. So I note it here, hope it help ;)

Cheers

萧瑟寒风 2024-07-16 13:16:47

今天,当相同的代码在本地和我们的开发服务器上运行良好但在生产服务器上运行良好时,我在服务器上遇到了此错误。 重启服务器解决了。

I was getting this error today on a server when the same code worked fine locally and on our DEV server but not on PRODUCTION. Rebooting the server resolved it.

我做我的改变 2024-07-16 13:16:47
public static byte[] SetImageToByte(Image img)
    {
        ImageConverter converter = new ImageConverter();
        return (byte[])converter.ConvertTo(img, typeof(byte[]));
    }
public static Bitmap SetByteToImage(byte[] blob)
    {
        MemoryStream mStream = new MemoryStream();
        byte[] pData = blob;
        mStream.Write(pData, 0, Convert.ToInt32(pData.Length));
        Bitmap bm = new Bitmap(mStream, false);
        mStream.Dispose();
        return bm;
    }
public static byte[] SetImageToByte(Image img)
    {
        ImageConverter converter = new ImageConverter();
        return (byte[])converter.ConvertTo(img, typeof(byte[]));
    }
public static Bitmap SetByteToImage(byte[] blob)
    {
        MemoryStream mStream = new MemoryStream();
        byte[] pData = blob;
        mStream.Write(pData, 0, Convert.ToInt32(pData.Length));
        Bitmap bm = new Bitmap(mStream, false);
        mStream.Dispose();
        return bm;
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文