C#中转换位图像素格式

57

我需要将一个PixelFormat.Format32bppRgb格式的位图转换为PixelFormat.Format32bppArgb格式。

我原本希望使用Bitmap.Clone函数来完成,但似乎没有起作用。

Bitmap orig = new Bitmap("orig.bmp");
Bitmap clone = orig.Clone(new Rectangle(0,0,orig.Width,orig.Height), PixelFormat.Format24bppArgb);

如果我运行上面的代码并检查clone.PixelFormat,它将被设置为PixelFormat.Format32bppRgb。发生了什么事情/如何转换格式?


如果我运行上面的代码并检查clone.PixelFormat,它将被设置为PixelFormat.Format32bppRgb。发生了什么/如何转换格式?

2
这只发生在XP上吗?我在XP上发现了问题,但在Windows 7上似乎工作正常。Hans的解决方案为我解决了这个问题。 - Sugrue
1
有点好笑。我有一个在XP上运行良好但在Windows 7上出现此错误的解决方案... - Matt Klein
我可以确认只有XP受到影响。 - PMF
你应该注意那些不是XP系统的电脑。我没有测试过这个特定的代码,但在Windows 7上比较两张图片时,当我在像素级别工作时,遇到了一个类似的问题,这是由于这个bug/feature引起的。Dan7解释了正在发生的事情以及修复它的更一般方法。 - Eric
这个程序(免责声明:由我编写)适用于所有平台。可以从NuGet下载。 - György Kőszeg
3个回答

105

在 GDI+ 中不规范的操作很常见。以下代码可解决此问题:

Bitmap orig = new Bitmap(@"c:\temp\24bpp.bmp");
Bitmap clone = new Bitmap(orig.Width, orig.Height,
    System.Drawing.Imaging.PixelFormat.Format32bppPArgb);

using (Graphics gr = Graphics.FromImage(clone)) {
    gr.DrawImage(orig, new Rectangle(0, 0, clone.Width, clone.Height));
}

// Dispose orig as necessary...

我遇到了与OP类似的问题,只不过我在将48BppRgb TIFF保存为32BppArgb PNG时遇到了问题。GDI+无法正确转换,导致生成的图像非常暗。这个解决方案让我通过手动重新绘制图像为32BppRgb来解决了这个问题,所以点赞。 - Tom Lint

38

如果你通过文件路径创建一个Bitmap,比如Bitmap bmp = new Bitmap("myimage.jpg");,然后调用Clone()方法,返回的Bitmap将不会被转换。

但是,如果你从旧的Bitmap创建另一个BitmapClone()方法将按预期工作。

试试这样做:

using (Bitmap oldBmp = new Bitmap("myimage.jpg"))
using (Bitmap newBmp = new Bitmap(oldBmp))
using (Bitmap targetBmp = newBmp.Clone(new Rectangle(0, 0, newBmp.Width, newBmp.Height), PixelFormat.Format32bppArgb))
{
    // targetBmp is now in the desired format.
}

6
谢谢Dan7解释触发器是什么。我之前见过 new Bitmap(new Bitmap("image.jpg")) 的代码,但不知道为什么它能够工作。+1 - Matt Klein
有没有一种简单的方法可以克隆并转换位图的所有页面?我注意到targtBmp只有oldBmp中的活动帧。 - Ciprian Tomoiagă
这比标记为“解决方案”的更好 - 它适用于索引像素格式4bpp、8bpp。 - Geograph

8
using (var bmp = new Bitmap(width, height, PixelFormat.Format24bppArgb))
using (var g = Graphics.FromImage(bmp)) {
  g.DrawImage(..);
}

应该是这样工作的。也许您想在g上设置一些参数,以定义插值模式、质量等。


InterpolationMode 是用于缩放的,我不认为他真的想要缩放它。也许可以做一些像 bmp.SetResolution(old.HorizontalResolution, old.VerticalResolution) 这样的事情,并调用 g.DrawImageUnscaled(old, 0,0)。但这只是我的意见 :) - lauCosma
@Elmue - 你有任何证明支持你的说法吗?MSDN 上有不同的说明。 - ephraim

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