Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/288.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# OutOfMemoryException:内存不足-System.Drawing.Graphics.FromImage_C#_.net_Graphics_System.drawing - Fatal编程技术网

C# OutOfMemoryException:内存不足-System.Drawing.Graphics.FromImage

C# OutOfMemoryException:内存不足-System.Drawing.Graphics.FromImage,c#,.net,graphics,system.drawing,C#,.net,Graphics,System.drawing,使用System.Drawing.Graphics.FromImage(在Windows 2012 server上使用最新版本的.NET软件)时出现内存不足异常,仅适用于极少数特定的图像文件。大多数情况下,代码工作正常 上述问题的典型答案表明某些资源没有被释放 请在回答之前考虑如下:-< /强> 此特定图像的大小为34KB,是一个.JPG图像。服务器处于空闲状态,内存超过32GB 如果我看一下 此jpg文件使用windows资源管理器,通过右键单击文件,windows显示:96 dpi和3

使用System.Drawing.Graphics.FromImage(在Windows 2012 server上使用最新版本的.NET软件)时出现内存不足异常,仅适用于极少数特定的图像文件。大多数情况下,代码工作正常

上述问题的典型答案表明某些资源没有被释放

<强>请在回答之前考虑如下:-< /强>

  • 此特定图像的大小为34KB,是一个.JPG图像。服务器处于空闲状态,内存超过32GB
  • 如果我看一下 此jpg文件使用windows资源管理器,通过右键单击文件,windows显示:96 dpi和32位深度
  • 但是,如果我使用任何图形程序(如photoshop)打开此jpg文件,文件属性将显示为:72 dpi和24位深度
  • 因此,我认为文件头属性之间有一个错误匹配 说出文件实际包含的内容
  • 此外,如果我打开jpg 使用图形程序保存文件,只需重新保存,无需更改 任何内容,windows资源管理器中的文件属性现在匹配/读取正确 (72 dpi和24位深度);而文件由 System.Drawing.Graphics正确,没有引发异常
由于我对该主题的了解有限,我不知道图像文件的文件头是否包含与实际文件内容不同的数据

问题:

我如何解决这个问题?或者,如何让System.Drawing.Graphics忽略文件头数据,只查看实际的图像文件内容?(就像photoshop等所有图形程序一样)


谢谢

虽然我不是JPEG文件格式的专家,但我对这一主题做了一些研究,以下是我的发现,可以帮助您解决您的问题

请注意,由于缺少示例文件来检查和说明它与.Net/GDI+JPEG/JFIF解码器期望的不同之处,此答案将假定而不是具体指出问题的根源

JPEG/JFIF格式 首先,您可能想了解一下JPEG/JFIF格式本身。毕竟,您刚刚遇到了一个.Net/GDI+无法加载/解析的文件。由于我没有您遇到问题的文件,我建议您将其加载到所选的十六进制编辑器中。。。它能够基于模板/代码/解析器突出显示文件

我使用了来自Sweetscape在线模板库的和。 010编辑器提供30天免费试用

您要特别查找的是坏JPEG中的SOFn标识符和数据

SOFn数据中,我可以看到我的图像是Y(154)像素高,X(640)像素宽,使用3个分量,每个分量的精度为8位,使其成为每个像素24位。

JPEG/JFIF格式是许多不同实现/格式的巨大混合。显然,在奇怪的JPEG格式出现之前很久就存在的任何库中,都找不到该格式的所有变体。这是GDI+库所拥有的

在您的情况下,我怀疑您在JPEG文件中遇到了CMYK颜色配置文件

Net实现 您说过您使用了System.Drawing.Graphics.FromImage,因此我假设您的代码如下所示:

Graphics.FromImage(Image.FromFile("nope.jpg"));
Graphics.FromImage(Image.FromFile("nope.jpg", true));
Graphics.FromImage(Image.FromStream(nopeJpegStream));
从这些调用中,当本机gdiplus.dll调用

  • GdipGetImageGraphicsContext
  • GdipLoadImageFromFile
  • GdipLoadImageFromFileICM(或其各自的*流变体)或
  • GdipImageForceValidation
。。。返回代码3或5(内存不足或缓冲区不足)

这是我从referencesource.microsoft.com收集的,查看了那里的.Net源代码。
在任何情况下,这很可能不是.Net的问题,而是GDI+(gdiplus.dll)的问题,Microsoft没有为其提供源代码。这也意味着无法使用.Net包装器控制映像的加载方式,也无法检查其失败的原因。(尽管我仍然怀疑您的JPEG是用CMYK保存的)

不幸的是,当您在GDI+land中前进时,您将发现更多这些奇怪的异常/错误。因为该库几乎被弃用,取而代之的是Windows演示框架(WPF)和Windows映像组件。(WIC)

我自己的测试 由于你从未提供过关于这个主题的图片或任何其他细节,我试图重现你的问题。这本身就是一项任务,Image.FromFile(GdipLoadImageFromFile)将在许多不同的文件格式上失败。至少它不在乎文件扩展名是什么,幸好Photoshop做到了这一点

根据你的信息,我最终复制了一个.jpg文件,它在Photoshop中加载良好,显示DPI为96,位深度为32。当然,如果我对JPEG格式有更多的了解,我可能会马上找到解决方案

在010编辑器中显示这个文件(我必须在Photoshop中将其设置为CMYK颜色空间)给了我以下SOFn数据:Y(154)像素高,X(640)像素宽,使用4组件,每个组件的精度为8位,每个像素32位

我怀疑你会在你的“坏”文件上看到同样的情况。
是的,Image.FromFile现在抛出OutOfMemoryException

可能的解决方案
  • 使用外部库加载图像文件。(我留给你做的练习,但A.K.A似乎是个不错的选择)
  • 使用可以将图像从一种格式转换为另一种格式的命令行工具(在出现此异常时调用)。或者从JPEG转换为JPEG,就像在这种情况下一样。(同样,ImageMagick的“转换”命令行工具似乎是一个不错的选择)
  • <
    public static Image ImageFromFileWpf(string filename) {
        /* Load the image into an encoder using the Presentation Framework.
         * This is done by adding a frame (which in laymans terms is a layer) to a class derived BitmapEncoder.
         * Only TIFF, Gif and JPEG XR supports multiple frames.
         * Since we are going to convert our image to a GDI+ resource we won't support this as GDI+ doesn't (really) support it either.
         * If you want/need support for layers/animated Gif files, create a similar method to this one that takes a BitmapFrame as an argument and then...
         *  1. Instanciate the appropriate BitmapDecoder.
         *  2. Iterate over the BitmapDecoders frames, feeding them to the new method.
         *  3. Store the returned images in a collection of images.
         * 
         * Finally, i opted to use a PngBitmapEncoder here which supports image transparency.
         */
        var bitmapEncoder = new PngBitmapEncoder();
        bitmapEncoder.Frames.Add(BitmapFrame.Create(new Uri(filename)));
    
        // Use a memorystream as a handover from one file format to another.
        using (var memoryStream = new MemoryStream()) {
            bitmapEncoder.Save(memoryStream);
            /* We MUST create a copy of our image from stream, MSDN specifically states that the stream must remain
             * open throughout the lifetime of the image.
             * We cannot instanciate the Image class, so we instanciate a Bitmap from our temporary image instead.
             * Bitmaps are derived from Image anyways, so this is perfectly fine.
             */
            var tempImage = Image.FromStream(memoryStream);
            return new Bitmap(tempImage);
        }
    }
    
    foreach (var encoder in ImageCodecInfo.GetImageEncoders()) {
        if (encoder.MimeType == "image/jpeg")
            image.Save(filename, encoder, new EncoderParameters { Param = new [] { new EncoderParameter(Encoder.Quality, 100L) }});
    }
    
    Image bitmap = Bitmap.FromFile(filename, false);
    Graphics graphics = null;
    try
    {
        graphics = Graphics.FromImage(bitmap);
    }
    catch (OutOfMemoryException oome)
    {
        // Well, this looks like a buggy image. 
        // Try using alternate method    
        ImageMagick.MagickImage image = new ImageMagick.MagickImage(filename);
        image.Resize(image.Width, image.Height);
        image.Quality = 90;
        image.CompressionMethod = ImageMagick.CompressionMethod.JPEG;  
        graphics = Graphics.FromImage(image.ToBitmap());            
    }