怎样去除图片上的背景颜色实现透明贴图?
查了一些资料并参考一些帖子总结了一下有几种方法
由简单到复杂:
方法一:
使用TransparentBlt;
... {
if (IsIconic())
...{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使图标在工作矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
...{
CPaintDC dc(this);
CDC memDc;
memDc.CreateCompatibleDC(&dc);
BITMAP bm;
m_bitmap.GetBitmap(&bm);
memDc.SelectObject(&m_bitmap);
dc.TransparentBlt(10, 10, bm.bmWidth, bm.bmHeight, &memDc, 0, 0, bm.bmWidth, bm.bmHeight, RGB(255, 255, 255));
}
}
方法二:
使用MaskBlt;
......
CPaintDC dc(this);
CDC memDc;
memDc.CreateCompatibleDC(&dc);
//CBitmap memBitmap;
BITMAP bm;
m_bitmap.GetBitmap(&bm);
memDc.SelectObject(&m_bitmap);
CDC dcmask;
dcmask.CreateCompatibleDC(&dc);
CBitmap bmpmask;
bmpmask.CreateBitmap(bm.bmWidth, bm.bmHeight, 1, 1, NULL);
dcmask.SelectObject(&bmpmask);
dcmask.FillSolidRect(0, 0, bm.bmWidth, bm.bmHeight, RGB(255, 255, 255));
dc.MaskBlt(0, 0, bm.bmWidth, bm.bmHeight, &memDc, 0, 0, bmpmask, 0, 0, MAKEROP4(SRCAND, SRCINVERT));
......
}
方法三:
使用BitBlt的光栅操作
.....
CPaintDC dc(this);
CDC memDc;
memDc.CreateCompatibleDC(&dc);
BITMAP bm;
m_bitmap.GetBitmap(&bm);
memDc.SelectObject(&m_bitmap);
CDC dcmask;
dcmask.CreateCompatibleDC(&dc);
CBitmap bmpmask;
bmpmask.CreateBitmap(bm.bmWidth, bm.bmHeight, 1, 1, NULL);
dcmask.SelectObject(&bmpmask);
memDc.SetBkColor(RGB(255, 255, 255));
dcmask.BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &memDc, 0, 0, SRCCOPY);
dc.BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &memDc, 0, 0, SRCINVERT);
dc.BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &dcmask, 0, 0, SRCAND);
dc.BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &memDc, 0, 0, SRCINVERT);
.....
}
上述代码的原理,直观的说,目标就是,把memDc绘制到dc上的时候,
不绘制跟背景相同的颜色的部分。
1.用BitBlt API进行透明显示的步骤:
①处理dcmask为黑白DC,使memDc上颜色为背景的部分在dcmask显示为白色,其余地方显示为黑色。
②将memDc用BitBlt绘制到dc上,使用SRCINVERT方式
③将dcmask用BitBlt绘制到dc上,使用SRCAND方式
④再将memDc用BitBlt绘制到dc上,使用SRCINVERT方式
ROP中,SRCINVERT是图像间异或处理,SRCAND是图像间与处理。可以简单证明上述的
操作过程会得到我们想要的结果:
对于某一个位置,dc上颜色为B,memDc上颜色为A。
当A == 背景色的时候,dcmask上这个位置的颜色M为白色。则上面的②~④步可以表示为:
((B xor A) and M) xor A
⇔ (B xor A) xor A
⇔ B
当A != 背景色的时候,dcmask上这个位置的颜色M为黑色。则上面的②~④步可以表示为:
((B xor A) and M) xor A
⇔ 0 xor A
⇔ A
前两种方法TransparentBlt和MaskBlt API windows 95/98/me不支持,只支持NT/2000/XP及以后版本
可参考:
Transparent Blts in Windows NT Q89375
HOWTO: Drawing Transparent Bitmaps Q79212