//////////////////////////////////////////////////////////////////////
//
// BitmapLib.cpp: Implementation of class CBitmapLib.
//
// Author:
// Gerd Esser
// Germany
// eMail: admin@gerdesser.de
// http://www.gerdesser.de
//
// History:
// 13.09.2000 - Creation
// 14.02.2002 - Error correction in GetRGB() case 16 (bit), expand ranges from 32 to 256
// Thanks for comment of "ForJest"
//
//////////////////////////////////////////////////////////////////////
#include "BitmapLib.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#define LINES_PER_BAND 100
//////////////////////////////////////////////////////////////////////
//
//
//////////////////////////////////////////////////////////////////////
CBitmapLib::CBitmapLib()
{
}
//////////////////////////////////////////////////////////////////////
//
//
//////////////////////////////////////////////////////////////////////
CBitmapLib::~CBitmapLib()
{
}
//////////////////////////////////////////////////////////////////////
//
//
//////////////////////////////////////////////////////////////////////
int CBitmapLib::GetUsedColors( CString const & stSrcBitmapFile,
RGBQUAD * pColorTable,
WORD const wMaxColorTableSize,
CProgressCtrl * pProgressCtrl )
{
ASSERT( pColorTable );
CFile SrcFile;
if ( !SrcFile.Open( stSrcBitmapFile, CFile::typeBinary | CFile::modeRead ) )
return FALSE;
// init progress control
if ( pProgressCtrl )
{
pProgressCtrl->SetRange32( 0, SrcFile.GetLength( ) );
pProgressCtrl->SetPos( 0 );
}
BITMAPFILEHEADER bmfhSrc;
// read bitmapfileheader of source bitmap
SrcFile.Read( &bmfhSrc, sizeof( bmfhSrc ) );
if ( pProgressCtrl )
pProgressCtrl->SetPos( SrcFile.GetPosition( ) );
BITMAPINFO * pBmiSrc = ( BITMAPINFO * ) new BYTE[ bmfhSrc.bfOffBits - sizeof( bmfhSrc ) ];
if ( !pBmiSrc )
{
SrcFile.Close( );
return blNotEnoughMemory;
}
// read bitmapinfo header of source bitmap, including the color palette
SrcFile.Read( pBmiSrc, bmfhSrc.bfOffBits - sizeof( bmfhSrc ) );
if ( pProgressCtrl )
pProgressCtrl->SetPos( SrcFile.GetPosition( ) );
// only uncompressed bitmaps are possible, because its a bitwise operation
if ( pBmiSrc->bmiHeader.biCompression != BI_RGB )
{
delete [] pBmiSrc;
SrcFile.Close( );
return blUnsupportedCompression;
}
WORD wUsedColors = 0;
UINT uSrcBytesPerLine = pBmiSrc->bmiHeader.biSizeImage / pBmiSrc->bmiHeader.biHeight;
// only reserve memory for small bitmap bands, thus working also on fat sized bitmaps
BYTE * pBitsSrc = new BYTE[ uSrcBytesPerLine * LINES_PER_BAND ];
// perform each band in a loop
for ( UINT i = 0; i < ( UINT ) pBmiSrc->bmiHeader.biHeight; i += LINES_PER_BAND )
{
// uCurLines may be smaller at the last loop
UINT uCurLines = min( LINES_PER_BAND, pBmiSrc->bmiHeader.biHeight - i );
// read source bitmap data
SrcFile.Read( pBitsSrc, uCurLines * uSrcBytesPerLine );
if ( pProgressCtrl )
pProgressCtrl->SetPos( SrcFile.GetPosition( ) );
int nReturn = GetUsedColors( pBmiSrc, pBitsSrc, 0, uCurLines,
pColorTable,
wMaxColorTableSize,
wUsedColors );
if ( nReturn < 0 )
{
delete [] pBitsSrc;
delete [] pBmiSrc;
SrcFile.Close( );
return nReturn;
}
}
delete [] pBitsSrc;
delete [] pBmiSrc;
SrcFile.Close( );
// reset progress control
if ( pProgressCtrl )
pProgressCtrl->SetPos( 0 );
return wUsedColors;
}
//////////////////////////////////////////////////////////////////////
//
//
//////////////////////////////////////////////////////////////////////
int CBitmapLib::GetUsedColors( BITMAPINFO const * pBmi,
BYTE const * pBits,
UINT const nStartScanLine,
UINT const nScanLines,
RGBQUAD * pColorTable,
WORD const wMaxColorTableSize,
WORD & wUsedColors )
{
ASSERT( pBmi );
ASSERT( pBits );
ASSERT( pColorTable );
BITMAPINFOHEADER const * pBmih = &pBmi->bmiHeader;
RGBQUAD rgb;
if ( pBmih->biCompression != BI_RGB )
return blUnsupportedCompression; // unsupported bitmap format, no compression
for ( UINT i = nStartScanLine; i < nStartScanLine + nScanLines; i++ )
{
for ( UINT j = 0; j < ( UINT ) pBmih->biWidth; j++ )
{
rgb = GetRGB( pBmi, i, j, pBits );
// search color table for current color
for ( WORD k = 0; k < wUsedColors; k++ )
if ( pColorTable[k].rgbBlue == rgb.rgbBlue
&& pColorTable[k].rgbGreen == rgb.rgbGreen
&& pColorTable[k].rgbRed == rgb.rgbRed )
break;
// if color could not be found
if ( k == wUsedColors )
{
// table full, no more entries and thus color count possible
if ( wUsedColors == wMaxColorTableSize )
return blColorOverflow; // error: color table overflow
else
{
// append new color at color table
pColorTable[wUsedColors] = rgb;
wUsedColors++;
}
}
}
}
return wUsedColors;
} // CBitmapLib::GetUsedColors( )
//////////////////////////////////////////////////////////////////////
//
//
//////////////////////////////////////////////////////////////////////
BOOL CBitmapLib::ChangeColorDepth( CString const & stSrcBitmapFile,
CString const & stDstBitmapFile,
WORD const wDstBitCount,
CProgressCtrl * pProgressCtrl )
{
ASSERT( stSrcBitmapFile != stDstBitmapFile );
CFile SrcFile;
CFile DstFile;
if ( !SrcFile.Open( stSrcBitmapFile, CFile::typeBinary | CFile::modeRead ) )
return FALSE;
// init progress control
if ( pProgressCtrl )
{
pProgressCtrl->SetRange32( 0, SrcFile.GetLength( ) );
pProgressCtrl->SetPos( 0 );
}
// if bitcount is greater than 8 bits, no device independent bitmap is requested
BOOL bDstIsDIB = TRUE;
if ( wDstBitCount > 8 )
bDstIsDIB = FALSE;
BITMAPFILEHEADER bmfhSrc;
// read bitmapfileheader of source bitmap
SrcFile.Read( &bmfhSrc, sizeof( bmfhSrc ) );
if ( pProgressCtrl )
pProgressCtrl->SetPos( SrcFile.GetPosition( ) );
BITMAPINFO * pBmiSrc = ( BITMAPINFO * ) new BYTE[ bmfhSrc.bfOffBits - sizeof( bmfhSrc ) ];
if ( !pBmiSrc )
{
SrcFile.Close( );
return FALSE;
}
// read bitmapinfo header of source bitmap, including the color palette
SrcFile.Read( pBmiSrc, bmfhSrc.bfOffBits - sizeof( bmfhSrc ) );
if ( pProgressCtrl )
pProgressCtrl->SetPos( SrcFile.GetPosition( ) );
// only uncompressed bitmaps are possible, because its a bitwise operation
if ( pBmiSrc->bmiHeader.biCompression != BI_RGB )
{
delete [] pBmiSrc;
SrcFile.Close( );
return FALSE;
}
if ( !DstFile.Open( stDstBitmapFile, CFile::typeBinary | CFile::modeCreate | CFile::modeWrite ) )
{
delete [] pBmiSrc;
SrcFile.Close( );
return FALSE;
}
BITMAPINFO * pBmiDst;
// create destination bitmapinfo header, due to wether it's a DIB or not (with or without color palette)
if ( bDstIsDIB )
{
pBmiDst = ( BITMAPINFO * ) new BYTE[ sizeof( BITMAPINFOHEADER )
+ ( 1 << wDstBitCount ) * sizeof( RGBQUAD ) ];
pBmiDst->bmiHeader = pBmiSrc->bm
- 1
- 2
前往页