为什么Bitmap.Save忽略了Bitmap的PixelFormat属性?

4

我需要处理并保存图像,保留它们原始的bpp值(1-黑白,8-灰度,24-彩色)。 处理后,由于使用了Aforge.Net进行处理,图像总是变成了24bpp。我将原始的bpp值传递给保存函数,并使用以下代码进行保存:

private static Bitmap changePixelFormat(Bitmap input, PixelFormat format)
    {
        Bitmap retval = new Bitmap(input.Width, input.Height, format);
        retval.SetResolution(input.HorizontalResolution, input.VerticalResolution);
        Graphics g = Graphics.FromImage(retval);
        g.DrawImage(input, 0, 0);
        g.Dispose();
        return retval;
    }

当我传递时:

PixelFormat.Format8bppIndexed

我遇到了一个异常:“Graphics object can't create image in indexed pixel format”,出现在以下代码行中:

Graphics g = Graphics.FromImage(retval);

我尝试了下面的代码:

Bitmap s = new Bitmap("gray.jpg");
        Bitmap NewPicture = s.Clone(new Rectangle(0, 0, s.Width, s.Height),                   PixelFormat.Format8bppIndexed);

在这之后,“NewImage”具有了PixelFormat 8bppIndexed,但当我保存“NewImage”时:

NewPicture.Save("hello.jpg", ImageFormat.Jpeg);

hello.jpg是24bpp。

我需要保留原始图像的bpp和图像格式。

为什么Bitmap.Save会忽略Bitmap的PixelFormat?

=======================================================

谢谢大家,我找到了解决方案:http://freeimage.sourceforge.net/license.html

借助这个免费库,可以将图像(尤其是JPEG)保存为灰度8位。


所以,问题是什么?为什么 Bitmap.Save 忽略正在保存的图像的 PixelFormat?或者,我该如何解决使用索引像素格式时 Graphics.FromImage 抛出的异常? - Cody Gray
为什么?我有一张灰色的JPEG(源图像),我需要将其保存为灰色的JPEG。我无法更改ImageFormat。 - xZ6a33YaYEfmv
我所需要的就是保留原始图像的bpp和图像格式。我尝试在24bpp图像上使用"Format16bppGrayScale",但是我得到了异常:"内存不足",并且在这一行中也出现了问题:"Graphics g = Graphics.FromImage(retval);" - xZ6a33YaYEfmv
3
您不能使用GDI+完成此操作,因为它对索引像素格式的支持非常弱。而且,这并没有太大的意义,因为它在Windows 3时代非常重要。那时操作系统仅仅和您今天使用的桌面壁纸图像一样大。 - Hans Passant
2
@HansPassant 如果你处理非常大的位图,仍然有意义(例如:http://www.naturalearthdata.com/downloads/10m-raster-data/10m-gray-earth/)。 - Igor Brejc
显示剩余4条评论
4个回答

5
我非常确定JPEG图像格式不支持索引图像。因此,即使您创建了指定PixelFormat.Format8bppIndexed的图像,当您尝试将其保存为JPEG时,GDI+也会将其转换为不同的格式。在这种情况下,您已经确定它是24 bpp。
相反,您需要将图像保存为BMP或GIF。例如:
NewPicture.Save("hello.jpg", ImageFormat.Bmp);

在维基百科上查看支持索引颜色的图像文件格式表

4

这里是将位图转换为1bpp / 8bpp位图的代码。 C#中的1bpp / 8bpp。

在您的changePixelFormat方法中,您可以检查需要将其转换为的像素格式,然后如果它是1bpp或8bpp,则使用链接中的代码,对于所有其他格式,请使用您的代码。

Graphics.FromImage 文档有备注:

如果图像具有索引的像素格式,则此方法会引发异常,并显示消息“无法从具有索引的像素格式的图像创建Graphics对象。”索引的像素格式如下列表所示。

Format1bppIndexed

Format4bppIndexed

Format8bppIndexed

新部分:

这是我在简短的谷歌搜索后找到的内容:

使用gdiplus版本1.0不支持8bpp灰度图像和8bpp jpg。在Windows 7中,有一个新版本的gdiplus支持灰度图像和更加增强的编解码器支持。

Microsoft的WIC API支持8bpp索引jpeg图像。

你可以从微软的下载站点下载WIC浏览器,并自行尝试。

GDI+ 8 bit load/save bug

标准JPEG仅支持24位图像。


代码更改了bpp,但是Bitmap.Save仍然以24bpp保存 - xZ6a33YaYEfmv
也许我不是一个好的谷歌搜索者,但我找不到任何关于这个的信息。 - xZ6a33YaYEfmv
请查看http://en.wikipedia.org/wiki/Comparison_of_graphics_file_formats,查看技术细节,了解哪些格式支持索引颜色。 - HABJAN

0
如果您正在寻找真正的8位灰度位图像,那么我已经写了一篇详细的StackOverflow帖子。它适用于任何操作系统(Windows/Mac/Linux),而不仅仅是Windows 7。希望能对您有所帮助。

0

对于非索引图像,请使用Graphics类。 在处理索引图像时,请使用Bitmap.LockBits和Bitmap.UnlockBits。


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