我正在制作一个对某些位图进行图形编辑的工具。我有一些带有现有调色板的8bppIndexed位图,我必须将其转换为24bppRgb,以便我可以根据用户选择的某些选项在其上绘制并编辑像素颜色。位图图形是原始的8bpp .bmp文件:
//Get Bitmap from file
Bitmap graphic = new Bitmap(source);
//Get palette and pixel format
ColorPalette pal = graphic.Palette;
PixelFormat pix = graphic.PixelFormat; //Format8bppIndexed
//Create datagraphic in 24bppRgb to allow for editing
PixelFormat datapix = PixelFormat.Format24bppRgb;
Bitmap datagraphic = graphic.Clone(new Rectangle(0, 0, graphic.Width, graphic.Height), datapix);
在绘制和编辑Bitmap datagraphic之后,我试图将其转换回8bppIndexed,其颜色调色板与Bitmap图形相同。我可以这样做:
//Convert back to graphic pixel format
datagraphic = datagraphic.Clone(new Rectangle(0, 0, datagraphic.Width, datagraphic.Height), pix); //Format8bppIndexed
//Apply color palette
datagraphic.Palette = pal;
然而,在使用与图形相同的像素格式克隆datagraphic后,它会创建一个全新的调色板。应用ColorPalette pal后,datagraphic中的颜色都是不正确的。它们仅匹配两个调色板之间的索引号。还有另一种方法可以保留颜色吗?
是的,位图需要使用自定义调色板进行8bppIndexed。我试图避免需要通过Photoshop来使用正确的调色板更改所有最终结果数据图形的颜色索引。
我应该说我还是C#的新手。我希望我能清楚自己要做什么。我感谢任何帮助。提前谢谢。
答案 0 :(得分:0)
将8位图像转换为24bpp是微不足道的:您只需将它绘制在具有相同尺寸和首选像素格式的新图像上。
public static Bitmap PaintOn24bpp(Image image)
{
Bitmap bp = new Bitmap(image.Width, image.Height, PixelFormat.Format24bppRgb);
using (Graphics gr = Graphics.FromImage(bp))
gr.DrawImage(image, new Rectangle(0, 0, bp.Width, bp.Height));
return bp;
}
这适用于任何源图像,无论其像素格式如何,但对于包含透明度的图像,您可能需要预处理它们以填充任何透明区域,因为我不知道如果考虑透明度的绘画将起作用您正在使用的图像并不支持alpha。
相反,要将高彩色图像转换为索引,要比较复杂,但如果你有调色板,那肯定是可能的。在这种情况下的主要问题是使用Graphics
不起作用,因为索引图形没有彩色像素;它们有一个彩色调色板,以及仅引用这些颜色的像素。
编辑8位数据通常归结为构建包含图像数据的字节数组,并将其转换为带有调色板的图像。实际转换是通过制作一个新的8bpp位图,使用LockBits
函数打开其后备字节数组,并使用Marshal.Copy
将新数据复制到其中来完成的。
之后,最终缺失的链接是一种将图像的彩色像素与其最接近的调色板匹配相匹配的方法,因此您可以获取生成的匹配数组并将其烘焙为8bpp图像。这通常通过计算颜色的毕达哥拉斯距离(在3D RGB颜色空间中)到每个调色板颜色,然后获取该距离最小的颜色的索引来完成。
在这个答案中详细解释了从开始到结束的整个过程:
A: How to convert a colored image to a image that has only two predefined colors?
这涉及2种颜色,但处理2种或256种颜色的方法完全相同,因为两种情况下的最终结果都是8bpp图像。
它可以优化直接处理24bpp图像而不是将输入转换为32bpp,但这可能不值得付出努力,特别是因为那里发布的方法绝对适用于任何输入。