简体   繁体   English

将8bpp索引位图转换为24bpp,然后使用相同的自定义调色板再次返回

[英]Converting 8bpp Indexed Bitmap to 24bpp and back again with the same custom color palette

I'm making a tool that does some graphical editing to some bitmaps. 我正在制作一个可以对某些位图进行图形编辑的工具。 I have some 8bppIndexed bitmaps with an existing color palette that I have to convert to 24bppRgb to allow me to draw on it and edit colors of pixels based on some options the user selected. 我有一些带有现有调色板的8bppIndexed位图,必须将其转换为24bppRgb,以便我可以在其上绘画并根据用户选择的某些选项编辑像素的颜色。 Bitmap graphic is the original 8bpp .bmp file: 位图图形是原始的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);

After drawing and editing Bitmap datagraphic, I'm trying to convert it back to 8bppIndexed with the same color palette as Bitmap graphic. 在绘制和编辑Bitmap数据图形后,我试图将其转换回8bppIndexed,使用与Bitmap图形相同的调色板。 I can do that like this: 我可以这样:

//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;

However, after cloning datagraphic with the same pixel format as graphic, it creates an entirely new color palette. 但是,在克隆与图形具有相同像素格式的数据图形后,它将创建一个全新的调色板。 The colors in datagraphic are then all incorrect after applying ColorPalette pal. 应用ColorPalette pal后,数据图形中的颜色全部不正确。 They only match by their index number between the two palettes. 它们仅通过两个调色板之间的索引号匹配。 Is there another way of doing this that preserves the colors? 还有另一种方法可以保留颜色吗?

And yes, the bitmaps need to be 8bppIndexed with the custom palette. 是的,位图需要使用自定义调色板进行8bppIndexed处理。 I'm trying to avoid the need to go through Photoshop to change the color index of all the end result data graphics with the correct palette. 我试图避免需要通过Photoshop来使用正确的调色板更改所有最终结果数据图形的颜色索引。

I should say that I'm still fairly new to C#. 我应该说我还是C#的新手。 I hope I was clear as to what I'm trying to do. 我希望我清楚自己想做什么。 I appreciate any help here. 感谢您的帮助。 Thanks in advance. 提前致谢。

Converting an 8-bit image to 24bpp is trivial: you just paint it on a new image of the same dimensions and the preferred pixel format. 将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;
}

This works with any source image no matter its pixel format, though for images containing transparency you may want to preprocess them to fill any transparent areas, because I don't know if painting with transparency taken into account will work if the image you're drawing on doesn't support alpha. 这适用于任何源图像,无论其像素格式如何,但是对于包含透明性的图像,您可能需要对其进行预处理以填充任何透明区域,因为我不知道考虑透明性的绘画是否可以用于您所使用的图像绘图不支持Alpha。

The reverse, to convert a high-colour image to indexed, is a lot trickier, but if you have the palette, it is certainly possible. 反之,将高彩色图像转换为索引图像,要复杂得多,但是如果您拥有调色板,那肯定是可能的。 The main problem in this case is that using Graphics doesn't work, since indexed graphics don't have coloured pixels; 在这种情况下,主要问题是使用Graphics不起作用,因为索引的图形没有彩色像素。 they have a coloured palette, and pixels that just reference those colours. 它们有一个调色板,而像素只是引用这些颜色。

Editing 8-bit data generally boils down to building a byte array containing the image data, and converting that to an image with the palette slapped onto it. 编辑8位数据通常可以归结为建立一个包含图像数据的字节数组,然后将其转换为带有调色板的图像。 The actual conversion is done by making a new 8bpp Bitmap, opening its backing byte array with the LockBits function, and copying your new data into it with Marshal.Copy . 通过创建一个新的8bpp位图,使用LockBits函数打开其后备字节数组,然后使用Marshal.Copy将新数据复制到其中,来完成实际的转换。

After that, the final missing link is a method to match your image's coloured pixels to their closest palette match, so you can then take the array of resulting matches and bake it into an 8bpp image. 之后,最后缺少的链接是一种将图像的彩色像素与最接近的调色板匹配相匹配的方法,因此,您可以将结果匹配的阵列作为一个8bpp图像进行烘烤。 This is generally done by calculating the Pythagorean distance (in 3D RGB colour space) of your colour to each of the palette colours, and then taking the index of the colour for which that distance is the smallest. 通常,这是通过计算颜色到每种调色板颜色的勾股距离(在3D RGB颜色空间中),然后获取该距离最小的颜色的索引来完成的。

The whole process, from start to end, is explained in detail in this answer: 此答案详细说明了从头到尾的整个过程:

A: How to convert a colored image to a image that has only two predefined colors? 答:如何将彩色图像转换为只有两种预定义颜色的图像?

This deals with 2 colours, but the method for dealing with 2 or with 256 colours is completely identical, since the end result in both cases was an 8bpp image. 这处理2种颜色,但是处理2种或256种颜色的方法完全相同,因为两种情况下的最终结果都是8bpp图像。

It could be optimised for dealing with 24bpp images directly instead of converting the input to 32bpp, but that's probably not worth the effort, especially since the method posted there works with absolutely any input. 可以对其进行优化,以直接处理24bpp图像,而不是将输入转换为32bpp,但这可能不值得付出努力,尤其是因为此处发布的方法几乎可以处理任何输入。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM