2024-06-23 17:36:53 +08:00

538 lines
19 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Dib.cpp: implementation of the CDib class.
//////////////////////////////////////////////////////////////////////
//
//用途IconSnap所需调用的类
//功能DIB设备无关位图基础操作类
//作者:徐景周
//日期2001年9月
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Dib.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CDib::CDib()
{
}
CDib::~CDib()
{
}
/****************************************************************************
*
* FUNCTION: FindDIBits
*
* PURPOSE: Locate the image bits in a CF_DIB format DIB.
*
* PARAMS: LPSTR lpbi - pointer to the CF_DIB memory block
*
* RETURNS: LPSTR - pointer to the image bits
*
*
\****************************************************************************/
LPSTR CDib::FindDIBBits( LPSTR lpbi )
{
return ( lpbi + *(LPDWORD)lpbi + PaletteSize( lpbi ) );
}
/* End FindDIBits() *********************************************************/
/****************************************************************************
*
* FUNCTION: DIBNumColors
*
* PURPOSE: Calculates the number of entries in the color table.
*
* PARAMS: LPSTR lpbi - pointer to the CF_DIB memory block
*
* RETURNS: WORD - Number of entries in the color table.
*
*
\****************************************************************************/
WORD CDib::DIBNumColors( LPSTR lpbi )
{
WORD wBitCount;
DWORD dwClrUsed;
dwClrUsed = ((LPBITMAPINFOHEADER) lpbi)->biClrUsed;
if (dwClrUsed)
return (WORD) dwClrUsed;
wBitCount = ((LPBITMAPINFOHEADER) lpbi)->biBitCount;
switch (wBitCount)
{
case 1: return 2;
case 4: return 16;
case 8: return 256;
default:return 0;
}
return 0;
}
/* End DIBNumColors() ******************************************************/
/****************************************************************************
*
* FUNCTION: PaletteSize
*
* PURPOSE: Calculates the number of bytes in the color table.
*
* PARAMS: LPSTR lpbi - pointer to the CF_DIB memory block
*
* RETURNS: WORD - number of bytes in the color table
*
*
\****************************************************************************/
WORD CDib::PaletteSize( LPSTR lpbi )
{
return ( DIBNumColors( lpbi ) * sizeof( RGBQUAD ) );
}
/* End PaletteSize() ********************************************************/
/****************************************************************************
*
* FUNCTION: BytesPerLine
*
* PURPOSE: Calculates the number of bytes in one scan line.
*
* PARAMS: LPBITMAPINFOHEADER lpBMIH - pointer to the BITMAPINFOHEADER
* that begins the CF_DIB block
*
* RETURNS: DWORD - number of bytes in one scan line (DWORD aligned)
*
*
\****************************************************************************/
DWORD CDib::BytesPerLine( LPBITMAPINFOHEADER lpBMIH )
{
return WIDTHBYTES(lpBMIH->biWidth * lpBMIH->biPlanes * lpBMIH->biBitCount);
}
/* End BytesPerLine() ********************************************************/
/****************************************************************************
*
* FUNCTION: ConvertDIBFormat
*
* PURPOSE: Creates a new DIB of the requested format, copies the source
* image to the new DIB.
*
* PARAMS: LPBITMAPINFO lpSrcDIB - the source CF_DIB
* UINT nWidth - width for new DIB
* UINT nHeight - height for new DIB
* UINT nbpp - bpp for new DIB
* BOOL bStretch - TRUE to stretch source to dest
* FALSE to take upper left of image
*
* RETURNS: LPBYTE - pointer to new CF_DIB memory block with new image
* NULL on failure
*
*
\****************************************************************************/
LPBYTE CDib::ConvertDIBFormat( LPBITMAPINFO lpSrcDIB, UINT nWidth, UINT nHeight, UINT nbpp, BOOL bStretch )
{
LPBITMAPINFO lpbmi = NULL;
LPBYTE lpSourceBits, lpTargetBits, lpResult;
HDC hDC = NULL, hSourceDC, hTargetDC;
HBITMAP hSourceBitmap, hTargetBitmap, hOldTargetBitmap, hOldSourceBitmap;
DWORD dwSourceBitsSize, dwTargetBitsSize, dwTargetHeaderSize;
// Allocate and fill out a BITMAPINFO struct for the new DIB
// Allow enough room for a 256-entry color table, just in case
dwTargetHeaderSize = sizeof( BITMAPINFO ) + ( 256 * sizeof( RGBQUAD ) );
lpbmi = (LPBITMAPINFO)malloc( dwTargetHeaderSize );
lpbmi->bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
lpbmi->bmiHeader.biWidth = nWidth;
lpbmi->bmiHeader.biHeight = nHeight;
lpbmi->bmiHeader.biPlanes = 1;
lpbmi->bmiHeader.biBitCount = nbpp;
lpbmi->bmiHeader.biCompression = BI_RGB;
lpbmi->bmiHeader.biSizeImage = 0;
lpbmi->bmiHeader.biXPelsPerMeter = 0;
lpbmi->bmiHeader.biYPelsPerMeter = 0;
lpbmi->bmiHeader.biClrUsed = 0;
lpbmi->bmiHeader.biClrImportant = 0;
// Fill in the color table
if( ! CopyColorTable( lpbmi, (LPBITMAPINFO)lpSrcDIB ) )
{
free( lpbmi );
return NULL;
}
// Gonna use DIBSections and BitBlt() to do the conversion, so make 'em
hDC = GetDC( NULL );
hTargetBitmap = CreateDIBSection( hDC, lpbmi, DIB_RGB_COLORS, (void ** )&lpTargetBits, NULL, 0 );
hSourceBitmap = CreateDIBSection( hDC, lpSrcDIB, DIB_RGB_COLORS,(void ** ) &lpSourceBits, NULL, 0 );
hSourceDC = CreateCompatibleDC( hDC );
hTargetDC = CreateCompatibleDC( hDC );
// Flip the bits on the source DIBSection to match the source DIB
dwSourceBitsSize = lpSrcDIB->bmiHeader.biHeight * BytesPerLine(&(lpSrcDIB->bmiHeader));
dwTargetBitsSize = lpbmi->bmiHeader.biHeight * BytesPerLine(&(lpbmi->bmiHeader));
memcpy( lpSourceBits, FindDIBBits((LPSTR)lpSrcDIB), dwSourceBitsSize );
// Select DIBSections into DCs
hOldSourceBitmap =(HBITMAP ) SelectObject( hSourceDC, hSourceBitmap );
hOldTargetBitmap = (HBITMAP )SelectObject( hTargetDC, hTargetBitmap );
// Set the color tables for the DIBSections
if( lpSrcDIB->bmiHeader.biBitCount <= 8 )
SetDIBColorTable( hSourceDC, 0, 1 << lpSrcDIB->bmiHeader.biBitCount, lpSrcDIB->bmiColors );
if( lpbmi->bmiHeader.biBitCount <= 8 )
SetDIBColorTable( hTargetDC, 0, 1 << lpbmi->bmiHeader.biBitCount, lpbmi->bmiColors );
// If we are asking for a straight copy, do it
if( (lpSrcDIB->bmiHeader.biWidth==lpbmi->bmiHeader.biWidth) && (lpSrcDIB->bmiHeader.biHeight==lpbmi->bmiHeader.biHeight) )
{
BitBlt( hTargetDC, 0, 0, lpbmi->bmiHeader.biWidth, lpbmi->bmiHeader.biHeight, hSourceDC, 0, 0, SRCCOPY );
}
else
{
// else, should we stretch it?
if( bStretch )
{
SetStretchBltMode( hTargetDC, COLORONCOLOR );
StretchBlt( hTargetDC, 0, 0, lpbmi->bmiHeader.biWidth, lpbmi->bmiHeader.biHeight, hSourceDC, 0, 0, lpSrcDIB->bmiHeader.biWidth, lpSrcDIB->bmiHeader.biHeight, SRCCOPY );
}
else
{
// or just take the upper left corner of the source
BitBlt( hTargetDC, 0, 0, lpbmi->bmiHeader.biWidth, lpbmi->bmiHeader.biHeight, hSourceDC, 0, 0, SRCCOPY );
}
}
// Clean up and delete the DCs
SelectObject( hSourceDC, hOldSourceBitmap );
SelectObject( hSourceDC, hOldTargetBitmap );
DeleteDC( hSourceDC );
DeleteDC( hTargetDC );
ReleaseDC( NULL, hDC );
// Flush the GDI batch, so we can play with the bits
GdiFlush();
// Allocate enough memory for the new CF_DIB, and copy bits
lpResult =(LPBYTE ) malloc( dwTargetHeaderSize + dwTargetBitsSize );
memcpy( lpResult, lpbmi, dwTargetHeaderSize );
memcpy( FindDIBBits( (LPSTR)lpResult ), lpTargetBits, dwTargetBitsSize );
// final cleanup
DeleteObject( hTargetBitmap );
DeleteObject( hSourceBitmap );
free( lpbmi );
return lpResult;
}
/* End ConvertDIBFormat() ***************************************************/
/****************************************************************************
*
* FUNCTION: CopyColorTable
*
* PURPOSE: Copies the color table from one CF_DIB to another.
*
* PARAMS: LPBITMAPINFO lpTarget - pointer to target DIB
* LPBITMAPINFO lpSource - pointer to source DIB
*
* RETURNS: BOOL - TRUE for success, FALSE for failure
*
*
\****************************************************************************/
BOOL CDib::CopyColorTable( LPBITMAPINFO lpTarget, LPBITMAPINFO lpSource )
{
// What we do depends on the target's color depth
switch( lpTarget->bmiHeader.biBitCount )
{
// 8bpp - need 256 entry color table
case 8:
if( lpSource->bmiHeader.biBitCount == 8 )
{ // Source is 8bpp too, copy color table
memcpy( lpTarget->bmiColors, lpSource->bmiColors, 256*sizeof(RGBQUAD) );
return TRUE;
}
else
{ // Source is != 8bpp, use halftone palette
HPALETTE hPal;
HDC hDC = GetDC( NULL );
PALETTEENTRY pe[256];
UINT i;
hPal = CreateHalftonePalette( hDC );
ReleaseDC( NULL, hDC );
GetPaletteEntries( hPal, 0, 256, pe );
DeleteObject( hPal );
for(i=0;i<256;i++)
{
lpTarget->bmiColors[i].rgbRed = pe[i].peRed;
lpTarget->bmiColors[i].rgbGreen = pe[i].peGreen;
lpTarget->bmiColors[i].rgbBlue = pe[i].peBlue;
lpTarget->bmiColors[i].rgbReserved = pe[i].peFlags;
}
return TRUE;
}
break; // end 8bpp
// 4bpp - need 16 entry color table
case 4:
if( lpSource->bmiHeader.biBitCount == 4 )
{ // Source is 4bpp too, copy color table
memcpy( lpTarget->bmiColors, lpSource->bmiColors, 16*sizeof(RGBQUAD) );
return TRUE;
}
else
{ // Source is != 4bpp, use system palette
HPALETTE hPal;
PALETTEENTRY pe[256];
UINT i;
hPal = (HPALETTE)GetStockObject( DEFAULT_PALETTE );
GetPaletteEntries( hPal, 0, 16, pe );
for(i=0;i<16;i++)
{
lpTarget->bmiColors[i].rgbRed = pe[i].peRed;
lpTarget->bmiColors[i].rgbGreen = pe[i].peGreen;
lpTarget->bmiColors[i].rgbBlue = pe[i].peBlue;
lpTarget->bmiColors[i].rgbReserved = pe[i].peFlags;
}
return TRUE;
}
break; // end 4bpp
// 1bpp - need 2 entry mono color table
case 1:
lpTarget->bmiColors[0].rgbRed = 0;
lpTarget->bmiColors[0].rgbGreen = 0;
lpTarget->bmiColors[0].rgbBlue = 0;
lpTarget->bmiColors[0].rgbReserved = 0;
lpTarget->bmiColors[1].rgbRed = 255;
lpTarget->bmiColors[1].rgbGreen = 255;
lpTarget->bmiColors[1].rgbBlue = 255;
lpTarget->bmiColors[1].rgbReserved = 0;
break; // end 1bpp
// no color table for the > 8bpp modes
case 32:
case 24:
case 16:
default:
return TRUE;
break;
}
return TRUE;
}
/* End CopyColorTable() *****************************************************/
/****************************************************************************
*
* FUNCTION: SetMonoDIBPixel
*
* PURPOSE: Sets/Clears a pixel in a 1bpp DIB by directly poking the bits.
*
* PARAMS: LPBYTE pANDBits - pointer to the 1bpp image bits
* DWORD dwWidth - width of the DIB
* DWORD dwHeight - height of the DIB
* DWORD x - x location of pixel to set/clear
* DWORD y - y location of pixel to set/clear
* BOOL bWhite - TRUE to set pixel, FALSE to clear it
*
* RETURNS: void
*
*
\****************************************************************************/
void CDib::SetMonoDIBPixel( LPBYTE pANDBits, DWORD dwWidth, DWORD dwHeight, DWORD x, DWORD y, BOOL bWhite )
{
DWORD ByteIndex;
BYTE BitNumber;
// Find the byte on which this scanline begins
ByteIndex = (dwHeight - y - 1) * WIDTHBYTES(dwWidth);
// Find the byte containing this pixel
ByteIndex += (x >> 3);
// Which bit is it?
BitNumber = (BYTE)( 7 - (x % 8) );
if( bWhite )
// Turn it on
pANDBits[ByteIndex] |= (1<<BitNumber);
else
// Turn it off
pANDBits[ByteIndex] &= ~(1<<BitNumber);
}
/* End SetMonoDIBPixel() *****************************************************/
/****************************************************************************
*
* FUNCTION: ReadBMPFile
*
* PURPOSE: Reads a BMP file into CF_DIB format
*
* PARAMS: LPCTSTR szFileName - the name of the file to read
*
* RETURNS: LPBYTE - pointer to the CF_DIB, NULL for failure
*
*
\****************************************************************************/
LPBYTE CDib::ReadBMPFile( LPCTSTR szFileName )
{
HANDLE hFile;
BITMAPFILEHEADER bfh;
DWORD dwBytes;
LPBYTE lpDIB = NULL, lpTemp = NULL;
WORD wPaletteSize = 0;
DWORD dwBitsSize = 0;
// Open the file
if( (hFile=CreateFile( szFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE )
{
MessageBox( NULL, "打开位图文件出错!", szFileName, MB_OK );
return NULL;
}
// Read the header
if( ( ! ReadFile( hFile, &bfh, sizeof(BITMAPFILEHEADER), &dwBytes, NULL ) ) || ( dwBytes != sizeof( BITMAPFILEHEADER ) ) )
{
CloseHandle( hFile );
MessageBox( NULL, "读位图文件头出错!", szFileName, MB_OK );
return NULL;
}
// Does it look like a BMP file?
if( ( bfh.bfType != 0x4d42 ) || (bfh.bfReserved1!=0) || (bfh.bfReserved2!=0) )
{
CloseHandle( hFile );
MessageBox( NULL, "未知的位图格式文件!", szFileName, MB_OK );
return NULL;
}
// Allocate some memory
if( (lpDIB =(LPBYTE) malloc( sizeof( BITMAPINFO ) )) == NULL )
{
CloseHandle( hFile );
MessageBox( NULL, "位图内存重新分配出错!", szFileName, MB_OK );
return NULL;
}
// Read in the BITMAPINFOHEADER
if( (!ReadFile( hFile, lpDIB, sizeof(BITMAPINFOHEADER), &dwBytes, NULL )) || (dwBytes!=sizeof(BITMAPINFOHEADER)) )
{
CloseHandle( hFile );
free( lpDIB );
MessageBox( NULL, "读位图文件信息头出错!", szFileName, MB_OK );
return NULL;
}
if( ((LPBITMAPINFOHEADER)lpDIB)->biSize != sizeof( BITMAPINFOHEADER ) )
{
CloseHandle( hFile );
free( lpDIB );
MessageBox( NULL, "OS/2风格的位图不支持!", szFileName, MB_OK );
return NULL;
}
// How big are the elements?
wPaletteSize = PaletteSize((LPSTR)lpDIB);
dwBitsSize = ((LPBITMAPINFOHEADER)lpDIB)->biHeight * BytesPerLine((LPBITMAPINFOHEADER)lpDIB);
// realloc to account for the total size of the DIB
if( (lpTemp = (LPBYTE)realloc( lpDIB, sizeof( BITMAPINFOHEADER ) + wPaletteSize + dwBitsSize )) == NULL )
{
CloseHandle( hFile );
MessageBox( NULL, "重新分配位图信息头所需内存失败!", szFileName, MB_OK );
free( lpDIB );
return NULL;
}
lpDIB = lpTemp;
// If there is a color table, read it
if( wPaletteSize != 0 )
{
if( (!ReadFile( hFile, ((LPBITMAPINFO)lpDIB)->bmiColors, wPaletteSize, &dwBytes, NULL )) || (dwBytes!=wPaletteSize) )
{
CloseHandle( hFile );
free( lpDIB );
MessageBox( NULL, "读位图颜色表出错!", szFileName, MB_OK );
return NULL;
}
}
// Seek to the bits
// checking against 0 in case some bogus app didn't set this element
if( bfh.bfOffBits != 0 )
{
if( SetFilePointer( hFile, bfh.bfOffBits, NULL, FILE_BEGIN ) == 0xffffffff )
{
CloseHandle( hFile );
free( lpDIB );
MessageBox( NULL, "位图文件大小定位出错!", szFileName, MB_OK );
return NULL;
}
}
// Read the image bits
if( (!ReadFile( hFile, FindDIBBits((LPSTR)lpDIB), dwBitsSize, &dwBytes, NULL )) || (dwBytes!=dwBitsSize) )
{
CloseHandle( hFile );
free( lpDIB );
MessageBox( NULL, "读位图文件出错!", szFileName, MB_OK );
return NULL;
}
// clean up
CloseHandle( hFile );
return lpDIB;
}
/* End ReadBMPFile() ********************************************************/
/****************************************************************************
*
* FUNCTION: WriteBMPFile
*
* PURPOSE: Writes a BMP file from CF_DIB format
*
* PARAMS: LPCTSTR szFileName - the name of the file to read
* LPBYTE - pointer to the CF_DIB, NULL for failure
*
* RETURNS: BOOL - TRUE for success, FALSE for Failure
*
*
\****************************************************************************/
BOOL CDib::WriteBMPFile( LPCTSTR szFileName, LPBYTE lpDIB )
{
HANDLE hFile;
BITMAPFILEHEADER bfh;
DWORD dwBytes, dwBytesToWrite;
LPBITMAPINFOHEADER lpbmih;
// Open the file
if( (hFile=CreateFile( szFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE )
{
MessageBox( NULL, "位图文件建立失败!", szFileName, MB_OK );
return FALSE;
}
bfh.bfType = 0x4d42;
bfh.bfReserved1 = 0;
bfh.bfReserved2 = 0;
bfh.bfOffBits = sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER ) + PaletteSize((LPSTR) lpDIB );
bfh.bfSize = (bfh.bfOffBits + ((LPBITMAPINFOHEADER)lpDIB)->biHeight * BytesPerLine((LPBITMAPINFOHEADER)lpDIB))/4;
// Write the header
if( ( ! WriteFile( hFile, &bfh, sizeof(BITMAPFILEHEADER), &dwBytes, NULL ) ) || ( dwBytes != sizeof( BITMAPFILEHEADER ) ) )
{
CloseHandle( hFile );
MessageBox( NULL, "写位图文件头出错!", szFileName, MB_OK );
return FALSE;
}
lpbmih = (LPBITMAPINFOHEADER)lpDIB;
// lpbmih->biHeight /= 2;
dwBytesToWrite = bfh.bfOffBits + (lpbmih->biHeight * BytesPerLine(lpbmih));
if( ( ! WriteFile( hFile, lpDIB, dwBytesToWrite, &dwBytes, NULL ) ) || ( dwBytes != dwBytesToWrite ) )
{
CloseHandle( hFile );
MessageBox( NULL, "写位图文件出错!", szFileName, MB_OK );
return FALSE;
}
lpbmih->biHeight *= 2;
CloseHandle( hFile );
return TRUE;
}
/* End WriteBMPFile() *******************************************************/