无法从带有索引像素格式的图像创建 Graphics 对象

编程知识 更新时间:2023-05-01 14:30:48

在使用Graphics.FromImage方法的时候,如果传入的System.Drawing.Image图像是索引像素格式,那么将会引发异常并提示以下消息:“无法从带有索引像素格式的图像创建 Graphics 对象。”。

先说下本人遇到的具体情况:由于网站需要添加一个上传图片自动打水印的功能,所以需要使用System.Drawing.Graphics类对图像重新绘制,将水印图片绘制到图片上。但在实际测试中,发现上传图片后,有的图片可以打水印成功,有的则会抛出异常,出现错误信息:A Graphics object cannot be created from an image that has an indexed pixel format。
后来断点调试,发现主要出错的地方是在Graphics.FromImage方法那,查阅了MSDN才发现这是由于索引像素格式的图片造成的(一般大多数的GIF格式图片都是这种类型):

官方文档:https://msdn.microsoft/zh-cn/library/system.drawing.graphics.fromimage.aspx

这里说下解决的思路,既然问题出在索引像素格式的图像上,那么只要对其进行处理即可。

根据官方文档所描述,一共有这8种像素格式会出现带有索引像素格式的图像无法创建 Graphics 对象的错误:Format1bppIndexed、Format4bppIndexed、Format8bppIndexed、Undefined、DontCare、Format16bppArgb1555、Format16bppGrayScale

我们使用下面的方法来判断图像的像素格式是否会引发异常:

/// <summary>
/// 判断图片是否索引像素格式,是否是引发异常的像素格式
/// </summary>
/// <param name="imagePixelFormat">图片的像素格式</param>
/// <returns></returns>
private bool IsIndexedPixelFormat(System.Drawing.Imaging.PixelFormat imagePixelFormat)
{
    PixelFormat[] pixelFormatArray = {
                                            PixelFormat.Format1bppIndexed
                                            ,PixelFormat.Format4bppIndexed
                                            ,PixelFormat.Format8bppIndexed
                                            ,PixelFormat.Undefined
                                            ,PixelFormat.DontCare
                                            ,PixelFormat.Format16bppArgb1555
                                            ,PixelFormat.Format16bppGrayScale
                                        };
    foreach (PixelFormat pf in pixelFormatArray)
    {
        if (imagePixelFormat == pf)
        {
            return true;
        }
    }
    return false;
}

我们只要传入当前Image对象的PixelFormat属性,就可以判断当前图像是否会抛出异常。那么接下来就可以根据自己的业务需求进行操作。

这里有多种方法,比如官方文档上所说的使用Image.Save(String, ImageFormat) 方法将索引的图像保存为另一种格式,然后为此新图像检索 Graphics 对象。

也可以使用Graphics.DrawImage方法将图像重新绘制到一个Bitmap对象中,并指定像素格式,从而去除索引,简单的范例:

using (System.Drawing.Image img = System.Drawing.Image.FromFile("要打水印的图片的路径"))
{

    if (IsIndexedPixelFormat(img.PixelFormat))
    {
        Bitmap bmp = new Bitmap(img.Width, img.Height, PixelFormat.Format32bppArgb);
        using (Graphics g = Graphics.FromImage(bmp))
        {
            g.DrawImage(img, 0, 0);
        }
    }
}

当然也可以直接禁止对索引像素格式的图片进行操作,如果想要偷懒,还可以直接使用try catch将异常捕获处理。无论使用什么方法,就是一定要注意带有索引像素格式的图片不能使用FromImage方法Graphics对象。


无法从带有索引像素格式的图像创建graphics对象问题解决

今天在一个项目中突然遇到一个问题,上传图片不能上传。于是断点跟踪。程序每次运行到Graphics g = Graphics.FromImage(img);就爆出如下错误:

“无法从带有索引像素格式的图像创建graphics对象”这个错误,对应的英文错误提示是“A Graphics object cannot be created from an image that has an indexed pixel format
于是通过查询 MSDN, 我们可以看到如下的提示信息:

通过上面的错误解释,我们可以看到,原因是因为图片是索引像素格式的。为了避免此问题的发生,我们在做水印之前,可以先判断原图片是否是索引像素格式的,如果是,则可以采用将此图片先clone到一张BMP上的方法来解决:

/// <summary>
/// 会产生graphics异常的PixelFormat
/// </summary>
private static PixelFormat[] indexedPixelFormats = { PixelFormat.Undefined, PixelFormat.DontCare,
PixelFormat.Format16bppArgb1555, PixelFormat.Format1bppIndexed, PixelFormat.Format4bppIndexed,
PixelFormat.Format8bppIndexed
    };

/// <summary>
/// 判断图片的PixelFormat 是否在 引发异常的 PixelFormat 之中
/// </summary>
/// <param name="imgPixelFormat">原图片的PixelFormat</param>
/// <returns></returns>
private static bool IsPixelFormatIndexed(PixelFormat imgPixelFormat)
{
    foreach (PixelFormat pf in indexedPixelFormats)
    {
        if (pf.Equals(imgPixelFormat)) return true;
    }

    return false;
}

//.........使用
using (Image img = Image.FromFile("原图片路径"))
{
    //如果原图片是索引像素格式之列的,则需要转换
    if (IsPixelFormatIndexed(img.PixelFormat))
    {
        Bitmap bmp = new Bitmap(img.Width, img.Height, PixelFormat.Format32bppArgb);
        using (Graphics g = Graphics.FromImage(bmp))
        {
            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
            g.DrawImage(img, 0, 0);
        }
        //下面的水印操作,就直接对 bmp 进行了
        //......
    }
    else //否则直接操作
    {
         //直接对img进行水印操作
    }
}

更多推荐

无法从带有索引像素格式的图像创建 Graphics 对象

本文发布于:2023-04-23 16:19:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/d29183526a74552ff765a7391b76b0c4.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:像素   索引   图像   对象   格式

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!

  • 98833文章数
  • 25706阅读数
  • 0评论数