碰到这个问题后,四处找资料,终于在codeproject上找到一个例子,http://www.codeproject.com/bitmap/RplColor.asp,但它的例子下不下来,且它的实现实在不好用,所有自己写了一个,可能不对,请大家修改:用法: 先在设备DC上画好图,再将设备DC传入pDC, 确定rc, rcOld, rcNew就可以了。
疑问:我先实现的思路是先在函数外部将图画在一个 memDC上,再传入 memDC处理好图,再用真正的DC画memDC.但这样不行,大家可以试一下,不知道为何,是不是memDC有什么局限。void CImageView::ReplaceColor(CDC *pDC, CRect rc, COLORREF crOld, COLORREF crNew)
{
CDC memDC;
memDC.CreateCompatibleDC(pDC);
CBitmap bmpMem, * pbmpMem; // 初始化BITMAPINFO信息,以便使用CreateDIBSection
BITMAPINFO RGB32BitsBITMAPINFO;
ZeroMemory(&RGB32BitsBITMAPINFO,sizeof(BITMAPINFO));
RGB32BitsBITMAPINFO.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
RGB32BitsBITMAPINFO.bmiHeader.biWidth= rc.Width();
RGB32BitsBITMAPINFO.bmiHeader.biHeight= rc.Height();
RGB32BitsBITMAPINFO.bmiHeader.biPlanes=1;
RGB32BitsBITMAPINFO.bmiHeader.biBitCount=32;
UINT * ptPixels; HBITMAP DirectBitmap = CreateDIBSection(memDC,
(BITMAPINFO *)&RGB32BitsBITMAPINFO,
DIB_RGB_COLORS,(void **)&ptPixels, NULL, 0);
if (DirectBitmap)
{
bmpMem.Attach(DirectBitmap);
pbmpMem = memDC.SelectObject(&bmpMem);
memDC.BitBlt(0, 0, rc.Width(), rc.Height(), pDC, rc.left, rc.top, SRCCOPY);
// 转换 COLORREF 为 RGB
COLORREF cOldColor=COLORREF2RGB(crOld);
COLORREF cNewColor=COLORREF2RGB(crNew); // 替换颜色
for (int i=((rc.Width() * rc.Height() ) -1 );i>=0;i--)
{
if (ptPixels[i]==cOldColor) ptPixels[i]=cNewColor;
}
pDC->BitBlt(rc.left, rc.top, rc.Width(), rc.Height(), &memDC, 0, 0, SRCCOPY);
} memDC.SelectObject(pbmpMem);
}
疑问:我先实现的思路是先在函数外部将图画在一个 memDC上,再传入 memDC处理好图,再用真正的DC画memDC.但这样不行,大家可以试一下,不知道为何,是不是memDC有什么局限。void CImageView::ReplaceColor(CDC *pDC, CRect rc, COLORREF crOld, COLORREF crNew)
{
CDC memDC;
memDC.CreateCompatibleDC(pDC);
CBitmap bmpMem, * pbmpMem; // 初始化BITMAPINFO信息,以便使用CreateDIBSection
BITMAPINFO RGB32BitsBITMAPINFO;
ZeroMemory(&RGB32BitsBITMAPINFO,sizeof(BITMAPINFO));
RGB32BitsBITMAPINFO.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
RGB32BitsBITMAPINFO.bmiHeader.biWidth= rc.Width();
RGB32BitsBITMAPINFO.bmiHeader.biHeight= rc.Height();
RGB32BitsBITMAPINFO.bmiHeader.biPlanes=1;
RGB32BitsBITMAPINFO.bmiHeader.biBitCount=32;
UINT * ptPixels; HBITMAP DirectBitmap = CreateDIBSection(memDC,
(BITMAPINFO *)&RGB32BitsBITMAPINFO,
DIB_RGB_COLORS,(void **)&ptPixels, NULL, 0);
if (DirectBitmap)
{
bmpMem.Attach(DirectBitmap);
pbmpMem = memDC.SelectObject(&bmpMem);
memDC.BitBlt(0, 0, rc.Width(), rc.Height(), pDC, rc.left, rc.top, SRCCOPY);
// 转换 COLORREF 为 RGB
COLORREF cOldColor=COLORREF2RGB(crOld);
COLORREF cNewColor=COLORREF2RGB(crNew); // 替换颜色
for (int i=((rc.Width() * rc.Height() ) -1 );i>=0;i--)
{
if (ptPixels[i]==cOldColor) ptPixels[i]=cNewColor;
}
pDC->BitBlt(rc.left, rc.top, rc.Width(), rc.Height(), &memDC, 0, 0, SRCCOPY);
} memDC.SelectObject(pbmpMem);
}
改个值不就行了
BYTE* pData = (BYTE*)lpDibBits + (m_nHeight-1-y)*m_nScanWidth + x*3;
// 后来发现不如Alpha 窗体快,这段代码就没用,
// 但其中计算像素点的算法可以参考 :-)
// Panr 2003-01-24 19:51
#define FULL_POINT_OF_TRANSPARENT (100)#define FULL_PRECENT_BINARY (256)
#define FULL_PRECENT_BINARY_DIGIT (8)
#define WIDTHBYTES(bits) (((bits) + 31) / 32 * 4)#include "math.h"
BOOL MixBitmap (BITMAP *pDC, CRect rcDC, BITMAP *pSc, CPoint ptLTSc, int nPrecent)
{
BYTE *lpDC, *lpSc;
int nDCX, nDCY;
int nScX, nScY; if (nPrecent<0 || nPrecent>FULL_POINT_OF_TRANSPARENT)
return false; if (!pDC->bmBits || !pSc->bmBits)
return false; CRect rcTemp;
rcTemp.SetRect (-1,-1, pDC->bmWidth+1, pDC->bmHeight+1);
if ( !rcTemp.PtInRect (rcDC.TopLeft ())
|| !rcTemp.PtInRect (rcDC.BottomRight ()))
{
return false;
} rcTemp.SetRect (-1,-1, pSc->bmWidth+1, pSc->bmHeight+1);
if ( !rcTemp.PtInRect (ptLTSc)
|| !rcTemp.PtInRect (ptLTSc + rcDC.Size ()))
{
return false;
} if (nPrecent == 0 || rcDC.IsRectEmpty ())
return true; if (nPrecent == FULL_POINT_OF_TRANSPARENT)
{
// BitBlt with more convenience.
// it's needn't to pruduct
// BITMAP struct from target dc.
ASSERT (false); // call some other routing.
return true;
} ASSERT (FULL_PRECENT_BINARY == pow(2, FULL_PRECENT_BINARY_DIGIT));
nPrecent = ::MulDiv (nPrecent, FULL_PRECENT_BINARY, 100); const int nBytePerPixelDC = pDC->bmBitsPixel / 8;
const int nBytePerPixelSc = pSc->bmBitsPixel / 8;
const int nBytePerScanDC = WIDTHBYTES (pDC->bmWidth * pDC->bmBitsPixel);
const int nBytePerScanSc = WIDTHBYTES (pSc->bmWidth * pSc->bmBitsPixel);
// the mix loop.
nDCY = rcDC.top;
nScY = ptLTSc.y;
for (; nDCY<rcDC.bottom; nDCY++, nScY++)
{
nDCX = rcDC.left;
nScX = ptLTSc.x; lpDC = ((BYTE*)pDC->bmBits) + nDCY * nBytePerScanDC + nDCX * nBytePerPixelDC;
lpSc = ((BYTE*)pSc->bmBits) + nScY * nBytePerScanSc + nScX * nBytePerPixelSc;
for (; nDCX<rcDC.right; nDCX++, nScX++)
{
{
// contents in *pDC and *pSc, besides the bit pointer, do not be verified.
lpDC[0] += ((lpSc[0]-lpDC[0]) * nPrecent) >> FULL_PRECENT_BINARY_DIGIT;
lpDC[1] += ((lpSc[1]-lpDC[2]) * nPrecent) >> FULL_PRECENT_BINARY_DIGIT;
lpDC[2] += ((lpSc[2]-lpDC[2]) * nPrecent) >> FULL_PRECENT_BINARY_DIGIT;
} lpDC += nBytePerPixelDC;
lpSc += nBytePerPixelSc;
}
} return true;
}
你的BITMAP结构怎么得到的。如果用GetBitmap()得到的话,好像bmBits指向空。所以不可能直接改写位图数据。只能再创建一个位图,用CreateDIBSection()创建,可以直接修改数据。
如果用CBitmap 加载进来的话,可以用CBitmap::GetBitmapBits 获得数据to gboy(★)(★):
BYTE* pData = (BYTE*)lpDibBits + (m_nHeight-1-y)*m_nScanWidth + x*3;
该算法是我在CodeProject 上的一处代码中发现的,我的确没看过专门的介绍BytePerPixel 算法的文章,你可以介绍个例子或文章么,先谢了
我们接触的程序都是RGB24bit 来处理像素的,我觉得不太有人会把bitmap 的image 做成32 bit对齐,那不是白白浪费1/3 的空间么,而图片的体积本来就是很大的
我是用内存DC 的,一加载后就把图片数据保持在那里,处理时也直接对数据操作
OnPaint 时只是copy 到窗体上用数据结构而不是CBitmap 保存数据,是为了避免多线程间传递时出问题
你可以先将源图画到一个24位的图上面,用我上面的方法就可以,我上面的方法是画到了一个32位上,所以计算时用UINT,
用GetBitmapBits()函数我也想过,使用它得先取得当前设备的位数,所以干脆就先将它画到一个32位上,这样处理更方便。
\\ // `\
\\ // 祝楼主:
.-'^'-.
.' a___a `. 春节愉快 合家欢乐!
== (___) ==
'. ._I_. .' 心想事成 红包拿来!
____/.`-----'.\____
[###(__)####
dib 图像的每行的所占的内存不一定是 width*BytesPerPixel。
行所占内存大小应该是一个 4 的倍数.比如一个 24bit 图像,宽度是 10 每行所占内存应该是 3*10+2=32, 而不是 3*10.
你可以看我的代码呀,我计算行时的大小时没有直接乘啊,是用WIDTHBYTES 的嘛