Na www.codeguru.com jsem narazil na komentovan² zdrojov² k≤d pro naΦtenφ souboru typu PCX (╚lßnek Viewing PCX Files). Tady je. Jen jsem p°elo₧il komentß°e a doplnil funkci pro smazßnφ, kterß tam chyb∞la.
Nejd°φv si do svΘ t°φdy pohledu p°idejte deklaraci dvou funkcφ a t°φ prom∞nn²ch. Hodnoty ukazatel∙ nezapome≥te v konstruktoru nastavit na NULL.
public:
void LoadPCX( LPCSTR lpcszFilename );
void DeletePCX();
protected:
CSize BitmapSize;
BITMAPINFO *psBmpInfo;
BYTE *pabRawBitmap;
A potΘ definici funkce pro naΦtenφ PCX. (Tento k≤d vy₧aduje vlo₧enφ hlaviΦkovΘho souboru io.h.) Zdrojov² k≤d ned∞lß nic jinΘho ne₧ ₧e p°evede obsah souboru PCX na standartnφ formßt DIBu.
void CMyView::LoadPCX( LPCSTR lpcszFilename )
{
// Standartnφ hlaviΦka PCX
struct PCXHead {
char ID;
char Version;
char Encoding;
char BitPerPixel;
short X1;
short Y1;
short X2;
short Y2;
short HRes;
short VRes;
char ClrMap[16*3];
char Reserved1;
char NumPlanes;
short BPL;
short Pal_t;
char Filler[58];
} sHeader;
// Otev°enφ souboru a jeho naΦtenφ do pam∞ti
FILE *pFile = fopen( lpcszFilename, "rb" );
if ( !pFile )
{
MessageBox("Unable to open the PCX file");
return;
}
const long clFileSize = _filelength(_fileno(pFile));
BYTE *pabFileData = (BYTE *)new BYTE[ clFileSize ];
fread( pabFileData, clFileSize, 1, pFile );
fclose( pFile );
// Zkopφrujeme si hlaviΦku
memcpy( &sHeader, pabFileData, sizeof(sHeader) );
// Ka₧d² Φten² °ßdek MUS═ mφt velikost, kterß jde d∞lit velikostφ datovΘho typu long
int iScanLineSize = sHeader.NumPlanes * sHeader.BPL;
ldiv_t sDivResult = ldiv( iScanLineSize, sizeof(long) );
if ( sDivResult.rem > 0 )
iScanLineSize = (iScanLineSize/sizeof(long)+1) * sizeof(long);
// Nastavφme velikost ΦlenskΘ prom∞nnΘ urΦujφcφ velikost bitmapy
BitmapSize = CSize( sHeader.X2-sHeader.X1+1, sHeader.Y2-sHeader.Y1+1 );
const long clImageSize = iScanLineSize * BitmapSize.cy;
// Nastavφme informace o bitmap∞
psBmpInfo = (BITMAPINFO *)new BYTE[ sizeof(BITMAPINFOHEADER) +
(sizeof(RGBQUAD)*256) ];
psBmpInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
psBmpInfo->bmiHeader.biWidth = BitmapSize.cx;
psBmpInfo->bmiHeader.biHeight = -BitmapSize.cy;
psBmpInfo->bmiHeader.biPlanes = sHeader.NumPlanes;
psBmpInfo->bmiHeader.biBitCount = sHeader.BitPerPixel;
psBmpInfo->bmiHeader.biCompression = BI_RGB;
psBmpInfo->bmiHeader.biSizeImage = 0;
psBmpInfo->bmiHeader.biXPelsPerMeter = 0;
psBmpInfo->bmiHeader.biYPelsPerMeter = 0;
psBmpInfo->bmiHeader.biClrUsed = 0;
psBmpInfo->bmiHeader.biClrImportant = 0;
// P°ipravφme buffer dostateΦn∞ velk² pro ulo₧enφ obrßzku
pabRawBitmap = (BYTE *)new BYTE[ clImageSize ];
if ( !pabRawBitmap )
{
MessageBox( "Nemohu alokovat p∞m∞¥ pro obrßzek" );
delete [] pabFileData;
return;
}
// NaΦteme komprimovan² obrßzek
long lDataPos = 0;
long lPos = 128; // Toto je kde data zaΦφnajφ
for ( int iY=0; iY < BitmapSize.cy; iY++ )
{
// Dekomprimujeme Φtenou °ßdku
for ( int iX=0; iX < sHeader.BPL; )
{
UINT uiValue = pabFileData[lPos++];
if ( uiValue > 192 ) // Dva vyÜÜφ bity jsou nastaveny = opakovat
{
uiValue -= 192; // Kolikrßt opakovat?
BYTE Color = pabFileData[lPos++]; // Jakß barva?
if ( iX <= BitmapSize.cx )
{ // Data obrßzku. Umφstit do bitmapy.
for ( BYTE bRepeat=0; bRepeat < uiValue; bRepeat++ )
{
pabRawBitmap[lDataPos++] = Color;
iX++;
}
}
else
iX += uiValue; // Mimo obrßzek. P°eskoΦit.
}
else
{
if ( iX <= BitmapSize.cx )
pabRawBitmap[lDataPos++] = uiValue;
iX++;
}
}
// Vyplnit zbytek nulami
if ( iX < iScanLineSize )
{
for ( ;iX < iScanLineSize; iX++ )
pabRawBitmap[lDataPos++] = 0;
}
}
if ( pabFileData[lPos++] == 12 ) // Jednoduchß kontrola
// NaΦφst paletu
for ( short Entry=0; Entry < 256; Entry++ )
{
psBmpInfo->bmiColors[Entry].rgbRed = pabFileData[lPos++];
psBmpInfo->bmiColors[Entry].rgbGreen = pabFileData[lPos++];
psBmpInfo->bmiColors[Entry].rgbBlue = pabFileData[lPos++];
psBmpInfo->bmiColors[Entry].rgbReserved = 0;
}
delete [] pabFileData;
}
Te∩ u₧ mßme obrßzek v pam∞ti a m∙₧eme jej zobrazit.
void CMyView::OnDraw(CDC* pDC)
{
if ( pabRawBitmap && psBmpInfo )
// Pokud byl obrßzek nahrßn (ukazatele nejsou NULL) zobrazφme jej pomocφ standartnφ API funkce
SetDIBitsToDevice( *pDC, 0, 0,
BitmapSize.cx, BitmapSize.cy, 0, 0,
0, BitmapSize.cy,
pabRawBitmap, psBmpInfo, DIB_RGB_COLORS);
}
A nakonec jeÜt∞ dopφÜeme funci pro smazßnφ obrßzku z pam∞ti.
void CMyView::DeletePCX()
{
// Smazßnφ obrßzku se provede jednoduch²m smazßnφm pam∞ti.
if (pabRawBitmap) delete[] pabRawBitmap;
if (psBmpInfo) delete[] psBmpInfo;
pabRawBitmap = NULL;
psBmpInfo = NULL;
}