七猫的藏经阁

其实只是垃圾箱

VC知识库BLOG 首页 新随笔 联系 聚合 登录
  194 Posts :: 0 Stories :: 622 Comments :: 4 Trackbacks

公告

其实我们每个人都是井底之蛙,最多在不同的井而已。

留言簿(3)

随笔分类

随笔档案

文章分类

文章档案

相册

收藏夹

好友

搜索

最新评论

阅读排行榜

评论排行榜

class CDib : public CObject
{
public:
CDib();
virtual ~CDib();

/**
* Clears all member variables and frees allocated memory.
*/
void DeleteObject();
/**
* Gets the number of bytes per horizontal line in the image.
* \param nWidth the width of the image
* \param nBitsPerPixel number of bits per pixel (color depth)
*/
static int BytesPerLine(int nWidth, int nBitsPerPixel);
/**
* Returns the height of the image in pixels
*/
int GetHeight() const { return m_BMinfo.bmiHeader.biHeight; }
/**
* Returns the width of the image in pixels
*/
int GetWidth() const { return m_BMinfo.bmiHeader.biWidth; }
/**
* Returns the size of the image in pixels
*/
CSize GetSize() const { return CSize(GetWidth(), GetHeight()); }
/**
* Returns the image byte field which can be used to work on.
*/
LPVOID GetDIBits() { return m_pBits; }
/**
* Creates a DIB from a CPictureHolder object with the specified width and height.
* \param pPicture the CPictureHolder object
* \param iWidth the width of the resulting picture
* \param iHeight the height of the resulting picture
*/
void Create32BitFromPicture (CPictureHolder* pPicture, int iWidth, int iHeight);

/**
* Returns a 32-bit RGB color
*/
static COLORREF FixColorRef (COLORREF clr);
/**
* Sets the created Bitmap-image (from Create32BitFromPicture) to the internal
* member variables and fills in all required values for this class.
* \param lpBitmapInfo a pointer to a BITMAPINFO structure
* \param lpBits pointer to the image byte field
*/
BOOL SetBitmap(const LPBITMAPINFO lpBitmapInfo, const LPVOID lpBits);

public:
/**
* Draws the image on the specified device context at the specified point.
* No stretching is done!
* \param pDC the device context to draw on
* \param ptDest the upper left corner to where the picture should be drawn to
*/
BOOL Draw(CDC* pDC, CPoint ptDest);

protected:
HBITMAP m_hBitmap;
BITMAPINFO m_BMinfo;
VOID *m_pBits;
};

CDib::CDib()
{
m_hBitmap = NULL;
DeleteObject();
}

CDib::~CDib()
{
DeleteObject();
}

int CDib::BytesPerLine(int nWidth, int nBitsPerPixel)
{
int nBytesPerLine = nWidth * nBitsPerPixel;
nBytesPerLine = ( (nBytesPerLine + 31) & (~31) ) / 8;
return nBytesPerLine;
}

void CDib::DeleteObject()
{
m_pBits = NULL;
if (m_hBitmap)
::DeleteObject(m_hBitmap);
m_hBitmap = NULL;

memset(&m_BMinfo, 0, sizeof(m_BMinfo));
}

void CDib::Create32BitFromPicture (CPictureHolder* pPicture, int iWidth, int iHeight)
{
CRect r;
CBitmap newBMP;
CWindowDC dc(NULL);
CDC tempDC;

tempDC.CreateCompatibleDC(&dc);

newBMP.CreateDiscardableBitmap(&dc,iWidth,iHeight);

CBitmap* pOldBitmap = tempDC.SelectObject(&newBMP);

r.SetRect(0,0,iWidth,iHeight);
pPicture->Render(&tempDC,r,r);

// Create a 32 bit bitmap
stdex::vector pBits(iWidth * iHeight);

BITMAPINFO bi;
bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bi.bmiHeader.biWidth = iWidth;
bi.bmiHeader.biHeight = iHeight;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = 32;
bi.bmiHeader.biCompression = BI_RGB;
bi.bmiHeader.biSizeImage = 0;
bi.bmiHeader.biXPelsPerMeter = 0;
bi.bmiHeader.biYPelsPerMeter = 0;
bi.bmiHeader.biClrUsed = 0;
bi.bmiHeader.biClrImportant = 0;


SetBitmap(&bi, pBits);

DWORD* pAr = (DWORD*)GetDIBits();

// Copy data into the 32 bit dib..
for(int i=0;i {
for(int j=0;j {
pAr[(i*iWidth)+j] = FixColorRef(tempDC.GetPixel(j,i));
}
}

tempDC.SelectObject(pOldBitmap);
}

BOOL CDib::SetBitmap(const LPBITMAPINFO lpBitmapInfo, const LPVOID lpBits)
{
DeleteObject();

if (!lpBitmapInfo || !lpBits)
return FALSE;

HDC hDC = NULL;

DWORD dwBitmapInfoSize = sizeof(BITMAPINFO);

memcpy(&m_BMinfo, lpBitmapInfo, dwBitmapInfoSize);

hDC = ::GetDC(NULL);
if (!hDC)
{
DeleteObject();
return FALSE;
}

m_hBitmap = CreateDIBSection(hDC, &m_BMinfo,
DIB_RGB_COLORS, &m_pBits, NULL, 0);
::ReleaseDC(NULL, hDC);
if (!m_hBitmap)
{
DeleteObject();
return FALSE;
}

DWORD dwImageSize = m_BMinfo.bmiHeader.biSizeImage;
if (dwImageSize == 0)
{
int nBytesPerLine = BytesPerLine(lpBitmapInfo->bmiHeader.biWidth,
lpBitmapInfo->bmiHeader.biBitCount);
dwImageSize = nBytesPerLine * lpBitmapInfo->bmiHeader.biHeight;
}

GdiFlush();

memcpy(m_pBits, lpBits, dwImageSize);

return TRUE;
}

BOOL CDib::Draw(CDC* pDC, CPoint ptDest)
{
if (!m_hBitmap)
return FALSE;

CSize size = GetSize();
CPoint SrcOrigin = CPoint(0,0);

BOOL resVal = FALSE;

resVal = SetDIBitsToDevice(pDC->GetSafeHdc(),
ptDest.x, ptDest.y,
size.cx, size.cy,
SrcOrigin.x, SrcOrigin.y,
SrcOrigin.y, size.cy - SrcOrigin.y,
GetDIBits(), &m_BMinfo,
DIB_RGB_COLORS);

return resVal;
}

COLORREF CDib::FixColorRef(COLORREF clr)
{
int r = GetRValue(clr);
int g = GetGValue(clr);
int b = GetBValue(clr);

return RGB(b,g,r);
}

posted on 2008-08-22 11:01 Diviner 阅读(768) 评论(2)  编辑 收藏

Feedback

# re: dib段的一个简单例子 2008-08-22 11:02 Diviner
下面要画个水波
#define random( min, max ) (( rand() % (int)((( max ) + 1 ) - ( min ))) + ( min ))

/**
* \ingroup Utils
*
* Provides a water effect on a picture. To do that the class needs
* the picture as an array of pixels. See CDIB class for information
* of that format.
* The formulas used in this class I found on a website: http://freespace.virgin.net/hugo.elias/graphics/x_water.htm">http://freespace.virgin.net/hugo.elias/graphics/x_water.htm">http://freespace.virgin.net/hugo.elias/graphics/x_water.htm">http://freespace.virgin.net/hugo.elias/graphics/x_water.htm \n
* An example of how to use this class and produce a water effect:
* \code
* //in your initialization code (e.g. OnInitDialog() )
* CPictureHolder tmpPic;
* tmpPic.CreateFromBitmap(IDB_LOGOFLIPPED);
* m_renderSrc.Create32BitFromPicture(&tmpPic,301,167);
* m_renderDest.Create32BitFromPicture(&tmpPic,301,167);
* m_waterEffect.Create(301,167);
* \endcode
* In a timer function / method you need to render the picture:
* \code
* m_waterEffect.Render((DWORD*)m_renderSrc.GetDIBits(), (DWORD*)m_renderDest.GetDIBits());
* CClientDC dc(this);
* CPoint ptOrigin(15,20);
* m_renderDest.Draw(&dc,ptOrigin);
* \endcode
* To add blobs you can do that either in a timer too
* \code
* CRect r;
* r.left = 15;
* r.top = 20;
* r.right = r.left + m_renderSrc.GetWidth();
* r.bottom = r.top + m_renderSrc.GetHeight();
* m_waterEffect.Blob(random(r.left,r.right), random(r.top, r.bottom), 2, 200, m_waterEffect.m_iHpage);
* \endcode
* or/and in a mouse-event handler
* \code
* void CTestDlg::OnMouseMove(UINT nFlags, CPoint point)
* {
* CRect r;
* r.left = 15;
* r.top = 20;
* r.right = r.left + m_renderSrc.GetWidth();
* r.bottom = r.top + m_renderSrc.GetHeight();
*
* if(r.PtInRect(point) == TRUE)
* {
* // dibs are drawn upside down...
* point.y -= 20;
* point.y = 167-point.y;
*
* if (nFlags & MK_LBUTTON)
* m_waterEffect.Blob(point.x -15,point.y,5,80,m_waterEffect.m_iHpage);
* else
* m_waterEffect.Blob(point.x -15,point.y,2,30,m_waterEffect.m_iHpage);
* }
* CDialog::OnMouseMove(nFlags, point);
* }
* \endcode
*/
class CWaterEffect
{
public:
CWaterEffect();
virtual ~CWaterEffect();


/**
* Creates the CWaterEffect object used for a picture with a width of \a iWidth and a height of \a iHeight
* \param iWidth the width of the picture in pixels
* \param iHeight the height of the picture in pixels
*/
void Create(int iWidth,int iHeight);
/**
* Renders the picture, i.e. perform the required calculations on \a pSrcImage and store the result in
* \a pTargetImage
* \param pSrcImage the image to perform the rendering on
* \param pTargetImage the resulting image
*/
void Render(DWORD* pSrcImage,DWORD* pTargetImage);
/**
* Adds a 'Blob' to the picture, i.e. the effect of a drop falling in the water.
* \param x the x coordinate of the blob position
* \param y the y coordinate of the blob position
* \param radius the radius in pixels the blob (or drop) should have
* \param height the height of the blob, i.e. how deep it will enter the water
* \param page which of the two buffers to use.
* \remark since DIB's are drawn upside down the y coordinate has to be 'flipped', i.e. subtract the
* height of the picture from the real y coordinate first.
*/
void Blob(int x, int y, int radius, int height, int page);

int m_iDensity; ///< The water density, higher values lead to slower water motion
int m_iHpage; ///< the buffer which is in use
private:
/**
* Clears both buffers. The result is that all effects are cleared.
*/
void ClearWater();
/**
* performs the calculations.
* \param npage which buffer to use
* \param density the water density
*/
void CalcWater(int npage, int density);
/**
* Smooths the waves of the water so that they disappear after a while
* \param npage the buffer to use
*/
void SmoothWater(int npage);

/**
* Draws the water effect to the resulting image buffer
* \param page the internal buffer to use
* \param LightModifier how much light to use. Higher values give more 'contrast/shadows' of the waves.
* \param pSrcImage the image to use
* \param pTargetImage the resulting image
*/
void DrawWater(int page, int LightModifier,DWORD* pSrcImage,DWORD* pTargetImage);
/**
* Converts the colors of the source picture (perhaps with color tables) to true color values.
*/
COLORREF GetShiftedColor(COLORREF color,int shift);

int m_iLightModifier;
int m_iWidth;
int m_iHeight;

int* m_iBuffer1;
int* m_iBuffer2;

};
#include <math.h>


CWaterEffect::CWaterEffect()
{
m_iBuffer1 = NULL;
m_iBuffer2 = NULL;

m_iWidth = 0;
m_iHeight = 0;

m_iLightModifier = 10;
m_iHpage = 0;
m_iDensity = 2;
}

CWaterEffect::~CWaterEffect()
{
// free memory
if (m_iBuffer1 != NULL)
delete [] m_iBuffer1;
if (m_iBuffer2 != NULL)
delete [] m_iBuffer2;

m_iBuffer1 = NULL;
m_iBuffer2 = NULL;
}

void CWaterEffect::Create(int iWidth, int iHeight)
{
if (m_iBuffer1 != NULL)
delete [] m_iBuffer1;
if (m_iBuffer2 != NULL)
delete [] m_iBuffer2;

m_iBuffer1 = new int[(iWidth*iHeight)];
m_iBuffer2 = new int[(iWidth*iHeight)];

m_iWidth = iWidth;
m_iHeight = iHeight;

ClearWater();

m_iHpage = 0;

}

void CWaterEffect::Blob(int x, int y, int radius, int height, int page)
{
int rquad;
int cx, cy, cyq;
int left, top, right, bottom;

int *pNew;
int *pOld;

if (page == 0)
{
pNew = &m_iBuffer1[0];
pOld = &m_iBuffer2[0];
}
else
{
pNew = &m_iBuffer2[0];
pOld = &m_iBuffer1[0];
}

rquad = radius * radius;

if (x<0)
x = 1 + radius + rand() % (m_iWidth - 2 * radius - 1);
if (y<0)
y = 1 + radius + rand() % (m_iHeight - 2 * radius - 1);

left = -radius;
right = radius;
top = -radius;
bottom = radius;

// clip edges
if (x - radius < 1)
left -= (x-radius-1);
if (y - radius < 1)
top -= (y-radius-1);
if (x + radius > m_iWidth-1)
right -= (x+radius-m_iWidth+1);
if (y + radius > m_iHeight-1)
bottom-= (y+radius-m_iHeight+1);

for(cy = top; cy < bottom; cy++)
{
cyq = cy*cy;
for(cx = left; cx < right; cx++)
{
if (cx*cx + cyq < rquad)
{
pNew[m_iWidth*(cy+y) + (cx+x)] += height;
}
}
}
}

void CWaterEffect::ClearWater()
{
// clear height fields
memset(m_iBuffer1,0, (m_iWidth*m_iHeight)*sizeof(int));
memset(m_iBuffer2,0, (m_iWidth*m_iHeight)*sizeof(int));
}

void CWaterEffect::Render(DWORD* pSrcImage, DWORD* pTargetImage)
{
DrawWater(m_iHpage, m_iLightModifier, pSrcImage, pTargetImage);

CalcWater(m_iHpage, m_iDensity);

//change the field from 0 to 1 and vice versa
m_iHpage ^= 1;

}

void CWaterEffect::CalcWater(int npage, int density)
{
int newh;
int count = m_iWidth + 1;
int *pNew;
int *pOld;

if (npage == 0)
{
pNew = &m_iBuffer1[0];
pOld = &m_iBuffer2[0];
}
else
{
pNew = &m_iBuffer2[0];
pOld = &m_iBuffer1[0];
}

int x, y;

// a description of the algorithm and an implementation
// in 'pseudocode' can be found here:
// http://freespace.virgin.net/hugo.elias/graphics/x_water.htm">http://freespace.virgin.net/hugo.elias/graphics/x_water.htm">http://freespace.virgin.net/hugo.elias/graphics/x_water.htm">http://freespace.virgin.net/hugo.elias/graphics/x_water.htm
for (y = (m_iHeight-1)*m_iWidth; count < y; count += 2)
{
for (x = count+m_iWidth-2; count < x; count++)
{
// use eight pixels
newh = ((pOld[count + m_iWidth]
+ pOld[count - m_iWidth]
+ pOld[count + 1]
+ pOld[count - 1]
+ pOld[count - m_iWidth - 1]
+ pOld[count - m_iWidth + 1]
+ pOld[count + m_iWidth - 1]
+ pOld[count + m_iWidth + 1]
) >> 2 )
- pNew[count];

pNew[count] = newh - (newh >> density);
}
}
}

void CWaterEffect::SmoothWater(int npage)
{
//flatten and spread the waves
int newh;
int count = m_iWidth + 1;

int *pNew;
int *pOld;

if (npage == 0)
{
pNew = &m_iBuffer1[0];
pOld = &m_iBuffer2[0];
}
else
{
pNew = &m_iBuffer2[0];
pOld = &m_iBuffer1[0];
}

int x, y;

// a description of the algorithm and an implementation
// in 'pseudocode' can be found here:
// http://freespace.virgin.net/hugo.elias/graphics/x_water.htm">http://freespace.virgin.net/hugo.elias/graphics/x_water.htm">http://freespace.virgin.net/hugo.elias/graphics/x_water.htm">http://freespace.virgin.net/hugo.elias/graphics/x_water.htm
for(y=1; y<m_iHeight-1; y++)
{
for(x=1; x<m_iWidth-1; x++)
{
newh = ((pOld[count + m_iWidth]
+ pOld[count - m_iWidth]
+ pOld[count + 1]
+ pOld[count - 1]
+ pOld[count - m_iWidth - 1]
+ pOld[count - m_iWidth + 1]
+ pOld[count + m_iWidth - 1]
+ pOld[count + m_iWidth + 1]
) >> 3 )
+ pNew[count];

pNew[count] = newh>>1;
count++;
}
count += 2;
}
}

void CWaterEffect::DrawWater(int /*page*/, int /*LightModifier*/, DWORD* pSrcImage, DWORD* pTargetImage)
{
int dx, dy;
int x, y;
DWORD c;

int offset = m_iWidth + 1;
long lIndex;
long lBreak = m_iWidth*m_iHeight;

int *ptr = &m_iBuffer1[0];


for (y = (m_iHeight-1)*m_iWidth; offset < y; offset += 2)
{
for (x = offset + m_iWidth - 2; offset < x; offset++)
{
dx = ptr[offset] - ptr[offset+1];
dy = ptr[offset] - ptr[offset+m_iWidth];

lIndex = offset + m_iWidth*(dy>>3) + (dx>>3);
if (lIndex < lBreak && lIndex > 0)
{
c = pSrcImage[lIndex];
c = GetShiftedColor(c,dx);
pTargetImage[offset] = c;
}

offset++;
dx = ptr[offset] - ptr[offset+1];
dy = ptr[offset] - ptr[offset+m_iWidth];

lIndex = offset + m_iWidth*(dy>>3) + (dx>>3);
if (lIndex < lBreak && lIndex > 0)
{
c = pSrcImage[lIndex];
c = GetShiftedColor(c,dx);
pTargetImage[offset] = c;
}
}
}
}

COLORREF CWaterEffect::GetShiftedColor(COLORREF color, int shift)
{
long R;
long G;
long B;
int ir;
int ig;
int ib;

R = GetRValue(color)-shift;
G = GetGValue(color)-shift;
B = GetBValue(color)-shift;

ir = (R < 0) ? 0 : (R > 255) ? 255 : R;
ig = (G < 0) ? 0 : (G > 255) ? 255 : G;
ib = (B < 0) ? 0 : (B > 255) ? 255 : B;

return RGB(ir,ig,ib);
}




# re: dib段的一个简单例子 2008-08-22 11:03 Diviner
具体 使用方法
void CAboutDlg::OnTimer(UINT_PTR nIDEvent)
{
if (nIDEvent == ID_EFFECTTIMER)
{
m_waterEffect.Render((DWORD*)m_renderSrc.GetDIBits(), (DWORD*)m_renderDest.GetDIBits());
CClientDC dc(this);
CPoint ptOrigin(15,20);
m_renderDest.Draw(&dc,ptOrigin);
}
if (nIDEvent == ID_DROPTIMER)
{
CRect r;
r.left = 15;
r.top = 20;
r.right = r.left + m_renderSrc.GetWidth();
r.bottom = r.top + m_renderSrc.GetHeight();
m_waterEffect.Blob(random(r.left,r.right), random(r.top, r.bottom), 5, 800, m_waterEffect.m_iHpage);
}
CStandAloneDialog::OnTimer(nIDEvent);
}

void CAboutDlg::OnMouseMove(UINT nFlags, CPoint point)
{
CRect r;
r.left = 15;
r.top = 20;
r.right = r.left + m_renderSrc.GetWidth();
r.bottom = r.top + m_renderSrc.GetHeight();

if(r.PtInRect(point) == TRUE)
{
// dibs are drawn upside down...
point.y -= 20;
point.y = 64-point.y;

if (nFlags & MK_LBUTTON)
m_waterEffect.Blob(point.x -15,point.y,10,1600,m_waterEffect.m_iHpage);
else
m_waterEffect.Blob(point.x -15,point.y,5,50,m_waterEffect.m_iHpage);

}


CStandAloneDialog::OnMouseMove(nFlags, point);
}
CPictureHolder tmpPic;
tmpPic.CreateFromBitmap(IDB_LOGOFLIPPED);
m_renderSrc.Create32BitFromPicture(&tmpPic,468,64);
m_renderDest.Create32BitFromPicture(&tmpPic,468,64);

m_waterEffect.Create(468,64);
SetTimer(ID_EFFECTTIMER, 40, NULL);
SetTimer(ID_DROPTIMER, 300, NULL);

标题  
姓名  
主页
验证码 *
内容   
  登录  使用高级评论  Top
[使用Ctrl+Enter键可以直接提交]