如何将GDI 8位索引位图转换为RGB位图?

4

我试图将一张8位深度的索引位图转换为RGB位图,但是我一直没有成功。

首先问题在于GetPalette()返回的调色板并不包含256个唯一的数字。

以下是我的代码:

BitmapData bitmapData;
int paletteSize =b->GetPaletteSize();
ColorPalette colorPalette;
b->GetPalette(&colorPalette,paletteSize/4);
b->LockBits(new Gdiplus::Rect(0,0,b->GetWidth(),b->GetHeight()),0,b->GetPixelFormat(),&bitmapData);
char* scan0 = (char*)bitmapData.Scan0; 
width = b->GetWidth();              
height = b->GetHeight();                
stride =  bitmapData.Width*4;               
pBitmapData = new char[stride*height];          
DWORD B = 0x00FF0000;                               
DWORD G =0x0000FF00;                                    
DWORD R = 0x000000FF;                                       
int currentIndex=0;                                             
for(int i = 0 ; i < height; i++)                                            
{                                                                                   
    for(int j =0 ; j < width; j++)                                                                  
    {                                                                                                           
        std::stringstream ss;                                                                                               
        currentIndex = i*stride+j*3;                                                                                                    
        pBitmapData[currentIndex+1]= (colorPalette.Entries[scan0[i*width+j]]&&B)>>16;
        pBitmapData[currentIndex+2]= (colorPalette.Entries[scan0[i*width+j]]&&G)>>8;                                                                
        pBitmapData[currentIndex+3]= (colorPalette.Entries[scan0[i*width+j]]&&R);
    }                                                                                                                                                       
}                                                                                                                                                               
b->UnlockBits(&bitmapData); 

我该如何修复这个问题?

那么你能描述一下出了什么问题吗? - Mats Petersson
只返回翻译文本:除了结果位图不正确之外,没有其他问题。 - Yamen Ajjour
好的,那么什么是不正确的?这些程序员真是太过于追求细节了... ;) - Mats Petersson
抱歉,返回的位图结果是黑色的且失真 :) - Yamen Ajjour
3个回答

1
为什么要用榛树?当你使用LockBits时,可以将PixelFormat24bppRGB作为LockBits的第三个参数,因为系统会复制数据(在GDI+中你永远无法直接访问图像数据)。以下是我发现的一些错误(至今为止):
int paletteSize =b->GetPaletteSize();
ColorPalette colorPalette;
b->GetPalette(&colorPalette,paletteSize/4);

为什么要除以四?GetPaletteSize返回的是字节大小,而GetPalette需要的是字节大小。
ColorPalette是一个占位符定义,是Microsoft开发者对我们做过的最黑暗的事情之一。它只定义了第一个颜色条目!
使用像byte指针这样的东西:
void *palette=new char[paletteSize];
b->GetPalette((ColorPalette *)palette,paletteSize);

使用

((ColorPalette *)palette)->Entries[i]

当您需要访问颜色时。

很抱歉,如果直接使用调色板,它看起来真的很丑。 不要忘记释放调色板并且... ...祝你好运。


使用PixelFormant24bppRGb锁定8bbp索引时,返回垃圾扫描0。 - Yamen Ajjour
这很奇怪。但这就是我使用调色板编写下面解决方案的原因。我检查了你的其余代码,第一眼没有发现更多的 bug。嗯,你的步长计算看起来有点奇怪,但应该可以工作。 - Martin Schlott
你的意思是 ((ColorPalette *)palette)->Entries 而不是 ((ColorPalette *)palette)->ARGB[i] 吗? - Yamen Ajjour

1

Shouldn't this:

currentIndex = i*stride+j*3;

be:

currentIndex = i*stride+j*4;

给定以下内容:
stride =  bitmapData.Width*4;

也就是说:
(colorPalette.Entries[scan0[i*width+j]]&&B)>>16;

应该是:

应该是:

(colorPalette.Entries[scan0[i*width+j]] & B)>>16;

&& 表示 "如果左右两边都为真",单个 & 表示 "按位与"。

现在位图变成了纯蓝色,这样更加美丽! - Yamen Ajjour
哦,天啊!我做了什么!实际上它已经非常接近了,但蓝色仍然是主要颜色,我想现在调色板有问题,我欠你一瓶啤酒 :) - Yamen Ajjour
你期望它是什么颜色?红色?有时候微软的图像会以相反的顺序存储RGB(BGR)... - Mats Petersson
是的,但背景完全是黑色的,但它看起来也是黑色的。 - Yamen Ajjour
1
嗯,黑色在所有颜色中都是零,所以将零蓝色与零红色交换仍然得到零。我不确定,但如果你需要“用红色代替蓝色”,那么我认为你需要交换处理红色和蓝色的行。 - Mats Petersson

1
很重要的是正确填写和对齐BITMAP RIFF格式的部分。 调色板类型位图的调色板不必包含256个条目:http://msdn.microsoft.com/en-us/library/windows/desktop/dd183376%28v=vs.85%29.aspx “8位图最多具有256种颜色,并且BITMAPINFO的bmiColors成员包含高达256个条目。在这种情况下,数组中的每个字节表示单个像素。”
然而,如果调色板中的条目少于256个,则位图不应超出调色板结构进行索引。否则,源格式不正确。
您想转换24 bpp位图。 这与8bpp略有不同。 我建议您在十六进制编辑器中打开现有的24bpp和8bpp位图文件,查看结构如何对齐以及其中的内容,并将其与您的内存布局进行比较。

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