📄 dibapi.cpp
字号:
*
* 参数:
* HDC hDC - 输出设备DC
* LPRECT lpDCRect - 绘制矩形区域
* HDIB hDIB - 指向DIB对象的指针
* LPRECT lpDIBRect - 要输出的DIB区域
* CPalette* pPal - 指向DIB对象调色板的指针
*
* 返回值:
* BOOL - 绘制成功返回TRUE,否则返回FALSE。
*
* 说明:
* 该函数主要用来绘制DIB对象。其中调用了StretchDIBits()或者
* SetDIBitsToDevice()来绘制DIB对象。输出的设备由由参数hDC指
* 定;绘制的矩形区域由参数lpDCRect指定;输出DIB的区域由参数
* lpDIBRect指定。
*
************************************************************************/
BOOL PaintDIB(HDC hDC,
LPRECT lpDCRect,
HDIB hDIB,
LPRECT lpDIBRect,
CPalette* pPal)
{
LPSTR lpDIBHdr; // BITMAPINFOHEADER指针
LPSTR lpDIBBits; // DIB象素指针
BOOL bSuccess=FALSE; // 成功标志
HPALETTE hPal=NULL; // DIB调色板
HPALETTE hOldPal=NULL; // 以前的调色板
// 判断DIB对象是否为空
if (hDIB == NULL)
{
// 返回
return FALSE;
}
// 锁定DIB
lpDIBHdr = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);
// 找到DIB图像象素起始位置
lpDIBBits = ::FindDIBBits(lpDIBHdr);
// 获取DIB调色板,并选中它
if (pPal != NULL)
{
hPal = (HPALETTE) pPal->m_hObject;
// 选中调色板
hOldPal = ::SelectPalette(hDC, hPal, TRUE);
}
// 设置显示模式
::SetStretchBltMode(hDC, COLORONCOLOR);
// 判断是调用StretchDIBits()还是SetDIBitsToDevice()来绘制DIB对象
if ((RECTWIDTH(lpDCRect) == RECTWIDTH(lpDIBRect)) &&
(RECTHEIGHT(lpDCRect) == RECTHEIGHT(lpDIBRect)))
{
// 原始大小,不用拉伸。
bSuccess = ::SetDIBitsToDevice(hDC, // hDC
lpDCRect->left, // DestX
lpDCRect->top, // DestY
RECTWIDTH(lpDCRect), // nDestWidth
RECTHEIGHT(lpDCRect), // nDestHeight
lpDIBRect->left, // SrcX
(int)DIBHeight(lpDIBHdr) -
lpDIBRect->top -
RECTHEIGHT(lpDIBRect), // SrcY
0, // nStartScan
(WORD)DIBHeight(lpDIBHdr), // nNumScans
lpDIBBits, // lpBits
(LPBITMAPINFO)lpDIBHdr, // lpBitsInfo
DIB_RGB_COLORS); // wUsage
}
else
{
// 非原始大小,拉伸。
bSuccess = ::StretchDIBits(hDC, // hDC
lpDCRect->left, // DestX
lpDCRect->top, // DestY
RECTWIDTH(lpDCRect), // nDestWidth
RECTHEIGHT(lpDCRect), // nDestHeight
lpDIBRect->left, // SrcX
lpDIBRect->top, // SrcY
RECTWIDTH(lpDIBRect), // wSrcWidth
RECTHEIGHT(lpDIBRect), // wSrcHeight
lpDIBBits, // lpBits
(LPBITMAPINFO)lpDIBHdr, // lpBitsInfo
DIB_RGB_COLORS, // wUsage
SRCCOPY); // dwROP
}
// 解除锁定
::GlobalUnlock((HGLOBAL) hDIB);
// 恢复以前的调色板
if (hOldPal != NULL)
{
::SelectPalette(hDC, hOldPal, TRUE);
}
// 返回
return bSuccess;
}
/*************************************************************************
*
* DitherDisplayDIB()
*
* Parameters:
*
* HDC hDC - DC to do output to
*
* LPRECT lpDCRect - rectangle on DC to do output to
*
* HDIB hDIB - handle to global memory with a DIB spec
* in it followed by the DIB bits
*
* LPRECT lpDIBRect - rectangle of DIB to output into lpDCRect
*
* HPALETTE hPal - Palette used to diaplsy DIB, if is NULL,
* use DIB palette to display
*
* DWORD dwRop - ROP mode to display DIB
*
* Return Value:
*
* BOOL - TRUE if DIB was drawn, FALSE otherwise
*
* Description:
* Painting routine with dithering, can display accuraly a DIB with
* more colors than the display device can support.
*
************************************************************************/
BOOL DitherDisplayDIB(HDC hDC, LPRECT lpDCRect, HDIB hDIB, LPRECT lpDIBRect,
DWORD dwRop)
{
LPSTR lpDIBHdr; // Pointer to BITMAPINFOHEADER
LPSTR lpDIBBits; // Pointer to DIB bits
BOOL bSuccess=FALSE; // Success/fail flag
HPALETTE hPal=NULL; // used palette
HPALETTE hOldPal=NULL; // Previous palette
// Check for valid DIB handle
if (!hDIB)
return FALSE;
// create dithered DIB to display
HDIB hDIBDisplay = CreateDither8BppDIB(hDIB);
// Lock down the DIB, and get a pointer to the beginning of the bit
// buffer
lpDIBHdr = (LPSTR)GlobalLock(hDIBDisplay);
lpDIBBits = FindDIBBits(lpDIBHdr);
// create palette from DIB
hPal = CreateDIBPalette(lpDIBHdr);
// Select and realize our palette as background
if (hPal)
{
hOldPal = SelectPalette(hDC, hPal, TRUE);
RealizePalette(hDC);
}
// Make sure to use the stretching mode best for color pictures
SetStretchBltMode(hDC, COLORONCOLOR);
// call StretchDIBits() anyway with dwRop
bSuccess = StretchDIBits(hDC,
lpDCRect->left,
lpDCRect->top,
RECTWIDTH(lpDCRect),
RECTHEIGHT(lpDCRect),
lpDIBRect->left,
(int)DIBHeight(lpDIBHdr) - lpDIBRect->top - RECTHEIGHT(lpDIBRect),
RECTWIDTH(lpDIBRect),
RECTHEIGHT(lpDIBRect),
lpDIBBits,
(LPBITMAPINFO)lpDIBHdr,
DIB_RGB_COLORS,
SRCCOPY);
// Unlock and free the memory block
GlobalUnlock(hDIBDisplay);
GlobalFree(hDIBDisplay);
// Reselect old palette
if (hOldPal)
SelectPalette(hDC, hOldPal, FALSE);
// Return with success/fail flag
return bSuccess;
}
///////////////////// local used only !!! /////////////////////////////
// create a dithered 8bpp DIB for 24bpp DIB in not true color device
HDIB CreateDither8BppDIB(HDIB hDIB)
{
WaitCursorBegin();
if (DIBBitCount((LPSTR)hDIB) <= 8)
{
WaitCursorEnd();
return CopyHandle(hDIB);
}
// dithering DIB
LPSTR lpDIB = (LPSTR)GlobalLock(hDIB);
LPSTR lpBits = FindDIBBits(lpDIB);
WORD wWidth = (WORD)DIBWidth(lpDIB);
WORD wHeight = (WORD)DIBHeight(lpDIB);
HGLOBAL hDitheredBits = DitherImage(lpBits, wWidth, wHeight);
GlobalUnlock(hDIB);
if (! hDitheredBits)
{
WaitCursorEnd();
return NULL;
}
// create a new 8bpp DIB
HDIB hNewDib = ChangeDIBFormat(hDIB, 8, BI_RGB);;
LPBITMAPINFO lpBmi = (LPBITMAPINFO)GlobalLock(hNewDib);
lpBmi->bmiHeader.biClrUsed = 256;
// set the entries of dither palette to DIB color table
for (int Index=0; Index < 256; Index++)
{
lpBmi->bmiColors[Index].rgbRed = DitherPalette[Index].Red;
lpBmi->bmiColors[Index].rgbGreen = DitherPalette[Index].Green;
lpBmi->bmiColors[Index].rgbBlue = DitherPalette[Index].Blue;
lpBmi->bmiColors[Index].rgbReserved = 0;
}
// copy dithered image bits to hNewDib
DWORD dwSize = GlobalSize(hDitheredBits);
LPSTR lpDitheredBits = (LPSTR)GlobalLock(hDitheredBits);
LPSTR lpNewBits = FindDIBBits((LPSTR)lpBmi);
memcpy(lpNewBits, lpDitheredBits, dwSize);
// cleanup
GlobalUnlock(hDitheredBits);
GlobalFree(hDitheredBits);
GlobalUnlock(hNewDib);
// map dithered DIB to dither palette
HPALETTE hPal = CreateDitherPalette();
MapDIBColorsToPalette(hNewDib, hPal);
DeleteObject(hPal);
WaitCursorEnd();
return hNewDib;
}
// This function dithers the image contained in this object. It returns
// a handle to a global memory block containing the dithered data.
HGLOBAL DitherImage(LPSTR lpImageData, WORD Width, WORD Height)
{
// Calculate width in bytes of a row of RGB data
WORD BytesPerLine = ALIGN_DWORD(Width * 3); // Source 24 BPP image
// Calculate width in bytes of a row of palettized data
WORD BytesPerLineDest = ALIGN_DWORD(Width); // Dest 8 BPP image
// Allocate two lines of RGB buffer for dithering
HLOCAL hLine1Buffer = LocalAlloc(LMEM_MOVEABLE, BytesPerLine);
if (!hLine1Buffer)
return NULL;
HLOCAL hLine2Buffer = LocalAlloc(LMEM_MOVEABLE, BytesPerLine);
if (!hLine2Buffer)
{
LocalFree(hLine1Buffer);
return NULL;
}
// Allocate the destination dither buffer
HGLOBAL hMem = GlobalAlloc(GHND, (DWORD) BytesPerLineDest * Height);
if (!hMem)
{
LocalFree(hLine1Buffer);
LocalFree(hLine2Buffer);
return NULL;
}
// Now lock the pointers for access
LPSTR Line1Buffer = (LPSTR) LocalLock(hLine1Buffer);
LPSTR Line2Buffer = (LPSTR) LocalLock(hLine2Buffer);
LPSTR lpDitheredRasterData = (LPSTR) GlobalLock(hMem);
// Move the first two lines of the source image to dither buffers
memcpy(Line1Buffer, lpImageData, BytesPerLine);
memcpy(Line2Buffer, lpImageData + BytesPerLine, BytesPerLine);
for (register WORD Row = 2; Row < Height; Row++)
{
DitherLine(Width, Line1Buffer, Line2Buffer);
// Copy the dithered data in Line1Buffer to destination
memcpy(lpDitheredRasterData + ((Row-2) * (DWORD) BytesPerLineDest),
Line1Buffer, BytesPerLineDest);
// Copy Line2Buffer to Line1Buffer so it can be dithered
memcpy(Line1Buffer, Line2Buffer, BytesPerLine);
// Move new data to Line2Buffer
memcpy(Line2Buffer, lpImageData + (Row * (DWORD) BytesPerLine),
BytesPerLine);
}
// Must complete the two rows in the line buffers
DitherLine(Width, Line1Buffer, Line2Buffer);
// Copy the dithered data in Line1Buffer to destination
memcpy(lpDitheredRasterData + ((Height-2) * (DWORD) BytesPerLineDest),
Line1Buffer, BytesPerLineDest);
memcpy(Line1Buffer, Line2Buffer, BytesPerLine);
DitherLine(Width, Line1Buffer, Line2Buffer);
// Copy the dithered data in Line1Buffer to destination
memcpy(lpDitheredRasterData + ((Height-1) * (DWORD) BytesPerLineDest),
Line1Buffer, BytesPerLineDest);
// Free the local line buffers
LocalUnlock(hLine1Buffer);
LocalFree(hLine1Buffer);
LocalUnlock(hLine2Buffer);
LocalFree(hLine2Buffer);
// Signal all is well
GlobalUnlock(hMem); // Unlock the dithered raster data
return hMem; // Return the handle of the data
}
// Define temporary vars as global, try to speedup...
int TRed, TGreen, TBlue;
int RedError, GreenError, BlueError;
BYTE PaletteIndex;
int BlueOffset;
LPSTR PixelAddr;
LPSTR RPixelAddr;
LPSTR DPixelAddr;
// Dither a single row of image data
void DitherLine(WORD Width, LPSTR pLine1, LPSTR pLine2)
{
for (register WORD Pixel=0; Pixel < Width; Pixel++)
{
// Get the pixel of interest for the dither
PixelAddr = pLine1 + (Pixel * 3);
GetRGBPixel(PixelAddr, TRed, TGreen, TBlue);
// Determine which blue entry from palette to use
BlueOffset = (TBlue/85);
if ((TBlue - (BlueOffset * 85)) > 43)
BlueOffset += 1;
// Calculate palette entry address from color
// PaletteIndex = ((TRed/32)*32) + ((TGreen/32)*4) + BlueOffset;
// For speed we will calculate the color index as follows
PaletteIndex = (TRed & 0xE0) + ((TGreen >> 5) << 2) + BlueOffset;
// Store the palette back into the same buffer
*(pLine1 + Pixel) = PaletteIndex;
/*
Pixel is set, now distribute the error to adjacent pixels
using a modified version of the Floyd-Steinberg algorithm.
In this implementation the error is distributed as follows
Pixel
o 1/2->o
1/4 |
o
The algorithm is modified to increase performance.
*/
// Calculate errors between the desired color and color used
// for this pixel. Actual error / 4. Use pointers for speed.
BYTE *pColor = (BYTE *) &DitherPalette[PaletteIndex]; // Ptr to color
RedError = (TRed - *(pColor)) >> 2;
GreenError = (TGreen - *(pColor+1)) >> 2;
BlueError = (TBlue - *(pColor+2)) >> 2;
// Do the pixel directly below target pixel
DPixelAddr = pLine2 + (Pixel * 3);
GetRGBPixel(DPixelAddr, TRed, TGreen, TBlue);
TRed += RedError; // 1/4 error
TGreen += GreenError;
TBlue += BlueError;
PutRGBPixel(DPixelAddr, TRed, TGreen, TBlue);
// Do the pixel directly to the right
if (Pixel != Width - 1)
{
RPixelAddr = PixelAddr + 3;
GetRGBPixel(RPixelAddr, TRed, TGreen, TBlue);
TRed += RedError + RedError; // 1/2 error
TGreen += GreenError + GreenError;
TBlue += BlueError + BlueError;
PutRGBPixel(RPixelAddr, TRed, TGreen, TBlue);
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
//DIB operations//
///////////////////////////////////////////////////////////////////////////////////////////////
/****************************************************************************
*
* FUNCTION: DIBToDIBSection
*
* PURPOSE: Create DIBSECTION from DIB
*
* PARAMS: LPSTR lpDIB - pointer to DIB data buffer
*
* RETURNS: HBITMAP - handle of DIBSECTION, or NULL for failure
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -