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

时间:2008-12-03 07:04:11

标签: c# image exception 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(因为它发生在其他地方的其他代码中)。

我真的很困惑:(

17 个答案:

答案 0 :(得分:157)

由于它是一个MemoryStream,你真的不需要需要来关闭流 - 如果你不这样做会发生任何不好的事情,尽管显然最好处理任何可以丢弃的东西。 (有关详细信息,请参阅this question。)

但是,你应该处理Bitmap - 这将关闭你的流。基本上,一旦你给Bitmap构造函数一个流,它“拥有”流,你不应该关闭它。正如the docs for that constructor所说:

  

你必须保持流开放   Bitmap的生命周期。

我在处理位图时找不到任何承诺关闭流的文档,但是你应该能够相当容易地验证它。

答案 1 :(得分:86)

GDI +中发生了一般错误。 也可能来自不正确的保存路径! 我花了半天才注意到这一点。 因此,请确保您已双重检查路径以保存图像。

答案 2 :(得分:14)

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

答案 3 :(得分:3)

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

答案 4 :(得分:2)

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

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

答案 5 :(得分:2)

当我从Citrix尝试时,我发生了这个错误。图像文件夹在服务器中设置为C:\,我没有权限。将图像文件夹移动到共享驱动器后,错误就消失了。

答案 6 :(得分:1)

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

答案 7 :(得分:1)

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

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 :(得分:1)

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

答案 9 :(得分:0)

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

答案 10 :(得分:0)

当我试图将图像保存到路径中时,它也出现在我身上

C:\Program Files (x86)\some_directory

并且.exe没有被执行以管理员身份运行,我希望这可以帮助那些也有同样问题的人。

答案 11 :(得分:0)

对我来说,下面的代码在保存到A generic error occurred in GDI+的行上与MemoryStream崩溃了。代码在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);
                }
            }
        }
    }

答案 12 :(得分:0)

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

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

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

修改

在听说CacheOption属性后(感谢@Nyerguds)我找到了解决方案: 因此,在设置<input v-model="something"> is syntactic sugar for: <input v-bind:value="something" v-on:input="something = $event.target.value"> CacheOption后,我必须设置Uri,而不是使用Bitmap构造函数。(下面的BitmapCacheOption.OnLoad是Wpf Image1元素)

而不是

Image

使用:

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

请参阅:WPF Image Caching

答案 13 :(得分:0)

尝试以下代码:

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

答案 14 :(得分:0)

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

抬头看了一会后,我尝试回收应用程序池并进行宾果游戏。所以我在这里记下,希望对您有所帮助;)

欢呼

答案 15 :(得分:0)

今天,当同一代码在本地和我们的DEV服务器上运行正常,但在PRODUCTION上却无法正常运行时,我在服务器上遇到此错误。重新启动服务器即可解决。

答案 16 :(得分:0)

public static int CarsVar;
public static int Cars;
public static string[] carReg; 
public static float[] carSpeed;
public static bool[] carRegis;
public static int[] carCosts;


static void Main(string[] args) {
  firstInput();
  Cars = CarsVar;
  carReg = new string[Cars]; 
  carSpeed = new float[Cars];
  carRegis = new bool[Cars];
  carCosts = new int[Cars];
  Input();  
  Calculate();
  Display();
}