将PNG图像保存到内存流中会导致错误

10

我有一个WebAPI端点(托管在IIS中),从数据库(字节数组)读取图像并以PNG格式返回它们。这段代码很简单:

  Image img = ImageHelper.ReadFromDatabase(…);
  using (MemoryStream ms = new MemoryStream())
  {
      img.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
      HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK);
      response.Content = new ByteArrayContent(ms.ToArray());
      response.Content.Headers.ContentType = new MediaTypeHeaderValue("image/png");
      response.ConfigureResponseCachability(parseConceptVersion, TimeSpan.FromHours(1));
      return response;
  }

我有三个网站服务器,其中一个会出现上述代码引起的错误:A generic error occurred in GDI+. at at System.Drawing.Image.Save()

更多关于服务器的细节

这些服务器运行不同的操作系统版本:

  • 服务器1,工作正常:Windows Server 2012 Standard
  • 服务器2,工作正常:Windows Server 2008 R2 Standard
  • 服务器3,无法工作:Windows Server 2012 R2 Datacenter (Core)

JPEG是一种解决方法

我已将上述代码更改为返回JPEG而不是PNG,并解决了问题。

  img.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);

我必须发送PNG图像,因此我需要找到根本原因。

使用WPF类而非Windows Form类

我将代码转换为使用WPF类(System.Windows.Media),而不是Windows Form类。结果很有趣:我也无法创建PNG,这次错误是The component registration is invalid. (Exception from HRESULT: 0x88982F8A)System.Windows.Media.Imaging.BitmapEncoder.SaveFrame()处。

服务器上是否缺少某些东西?

我的服务器是否缺少保存PNG所必需的低级组件?

谢谢


@Chris Pratt要求查看从字节数组创建图像的代码。在WebAPI代码和SqlDataReader调用之间有几个层次,但这里是从数据库中读取的字节数组转换为图像的代码。

/// <summary>
/// Creates a bitmap from a byte array
/// </summary>
public static Bitmap CreateBitmapFromBytes(byte[] bytes, int width, int height)
{
    // Make sure bytes were specified.
    if (bytes == null ||
        bytes.Length == 0)
    {
        return null;
    }

    using (MemoryStream imageStream = new MemoryStream(bytes))
    {
        Bitmap bitmap;

        try
        {
            bitmap = (Bitmap)Bitmap.FromStream(imageStream);
        }
        catch(ArgumentException)
        {
            return GetEmptyBitmap(width, height);
        }

        using (bitmap)
        {
            return new Bitmap(bitmap, width, height);
        }
    }
}

2
原帖作者说JPEG格式的图片可以正常工作。从逻辑上讲,如果您能够处理任何图像格式,那么除非未安装特定的辅助库以处理该特定格式,否则您应该能够处理所有格式。 - Chris Pratt
@juharr:那个链接是针对Server 2008 Core的。我的意图是提供一个关于Server Core的概述链接,而不是特定版本的链接。 - Sylvain
你看过这个吗?https://dev59.com/KGPVa4cB1Zd3GeqP9MwJ#16340060 -- HKEY_CLASSES_ROOT\CLSID{FAE3D380-FEA4-4623-8C75-C6B61110B681}的权限问题。 - J.H.
@J.H. 测试正在进行中...谢谢 - Sylvain
不用谢。如果有问题,请告诉我们。 - J.H.
显示剩余9条评论
2个回答

1
System.Drawing命名空间在处理图像时有很多已知的缺陷。请参考this article,其中包含了详细的解释。
当使用这个命名空间时,你必须非常小心地处理内存流、位图等可释放对象。你的问题听起来与这些可释放对象有关。
话虽如此,一个好的替代方案是使用ImageSharp库,它可以很好地处理从字节数组中读取图像并将其保存为png格式等功能。
你可以使用Image.Load方法
    var img = Image.Load(ImageHelper.ReadFromDatabaseAsByteArray());

并将其保存为png格式到MemoryStream中以供进一步使用:

using (var memStream = new MemoryStream())
{
   image.SaveAsPng(memStream);
   // Do something with the memStream, for example prepare http response
}

0

1) .NET框架>= 3.0应该有一个内置的编码器。检查是否有适合正确图像MIME类型的编码器。

 public static ImageCodecInfo GetEncoderInfo(string mimeType)
        {
             string lookupKey = mimeType.ToLower(); 
            ImageCodecInfo foundCodec = null; 
            if (Encoders.ContainsKey(lookupKey))
            { 
                foundCodec = Encoders[lookupKey];
            } 
            return foundCodec;
        }

(你需要一个编码器查找表)

  private static Dictionary<string, ImageCodecInfo> _encoders;

        /// <summary>
        ///     A quick lookup for getting image encoders
        /// </summary>
        private static Dictionary<string, ImageCodecInfo> Encoders
        {
            get
            {
                if (_encoders == null)
                {
                    _encoders = new Dictionary<string, ImageCodecInfo>();
                }
                if (_encoders.Count == 0)
                {
                    foreach (ImageCodecInfo codec in ImageCodecInfo.GetImageEncoders())
                    {
                        _encoders.Add(codec.MimeType.ToLower(), codec);
                    }
                }
                return _encoders;
            }
        }

然后您可以尝试使用您喜欢的编码器保存或获取字节

  public static void Save(string path, Image img, string mimeType)
        {
            using (var ms = File.OpenWrite(path))
            {
                ImageCodecInfo encoder = GetEncoderInfo(mimeType);
                img.Save(ms, encoder, null); 
            }
        }

2) 有时我会遇到保存索引图像的问题。请查看yourImage.PixelFormat,如果需要,请尝试将图像转换为其他格式。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接