3
* Purpose: Platform Independent BMP Image Class Loader and Writer
4
* 07/Aug/2001 Davide Pizzolato - www.xdp.it
5
* CxImage version 5.99c 17/Oct/2004
10
#if CXIMAGE_SUPPORT_BMP
14
////////////////////////////////////////////////////////////////////////////////
15
#if CXIMAGE_SUPPORT_ENCODE
16
////////////////////////////////////////////////////////////////////////////////
17
bool CxImageBMP::Encode(CxFile * hFile)
20
if (EncodeSafeCheck(hFile)) return false;
24
hdr.bfType = 0x4d42; // 'BM' WINDOWS_BITMAP_SIGNATURE
25
hdr.bfSize = GetSize() + 14 /*sizeof(BITMAPFILEHEADER)*/;
26
hdr.bfReserved1 = hdr.bfReserved2 = 0;
27
hdr.bfOffBits = 14 /*sizeof(BITMAPFILEHEADER)*/ + head.biSize + GetPaletteSize();
30
memcpy(pDib,&head,sizeof(BITMAPINFOHEADER));
31
// Write the file header
32
hFile->Write(&hdr,min(14,sizeof(BITMAPFILEHEADER)),1);
33
// Write the DIB header and the pixels
34
hFile->Write(pDib,GetSize(),1);
37
////////////////////////////////////////////////////////////////////////////////
38
#endif //CXIMAGE_SUPPORT_ENCODE
39
////////////////////////////////////////////////////////////////////////////////
40
#if CXIMAGE_SUPPORT_DECODE
41
////////////////////////////////////////////////////////////////////////////////
42
bool CxImageBMP::Decode(CxFile * hFile)
44
if (hFile == NULL) return false;
47
DWORD off = hFile->Tell(); //<CSC>
49
if (hFile->Read(&bf,min(14,sizeof(bf)),1)==0) throw "Not a BMP";
50
if (bf.bfType != BFT_BITMAP) { //do we have a RC HEADER?
52
hFile->Seek(off,SEEK_SET);
55
BITMAPINFOHEADER bmpHeader;
56
if (!DibReadBitmapInfo(hFile,&bmpHeader)) throw "Error reading BMP info";
57
DWORD dwCompression=bmpHeader.biCompression;
58
DWORD dwBitCount=bmpHeader.biBitCount; //preserve for BI_BITFIELDS compression <Thomas Ernst>
59
bool bIsOldBmp = bmpHeader.biSize == sizeof(BITMAPCOREHEADER);
61
bool bTopDownDib = bmpHeader.biHeight<0; //<Flanders> check if it's a top-down bitmap
62
if (bTopDownDib) bmpHeader.biHeight=-bmpHeader.biHeight;
64
if (info.nEscape == -1) {
65
// Return output dimensions only
66
head.biWidth = bmpHeader.biWidth;
67
head.biHeight = bmpHeader.biHeight;
68
throw "output dimensions returned";
71
if (!Create(bmpHeader.biWidth,bmpHeader.biHeight,bmpHeader.biBitCount,CXIMAGE_FORMAT_BMP))
72
throw "Can't allocate memory";
74
head.biXPelsPerMeter = bmpHeader.biXPelsPerMeter;
75
head.biYPelsPerMeter = bmpHeader.biYPelsPerMeter;
76
info.xDPI = (long) floor(bmpHeader.biXPelsPerMeter * 254.0 / 10000.0 + 0.5);
77
info.yDPI = (long) floor(bmpHeader.biYPelsPerMeter * 254.0 / 10000.0 + 0.5);
79
if (info.nEscape) throw "Cancelled"; // <vho> - cancel decoding
81
RGBQUAD *pRgb = GetPalette();
84
// convert a old color table (3 byte entries) to a new
85
// color table (4 byte entries)
86
hFile->Read((void*)pRgb,DibNumColors(&bmpHeader) * sizeof(RGBTRIPLE),1);
87
for (int i=DibNumColors(&head)-1; i>=0; i--){
88
pRgb[i].rgbRed = ((RGBTRIPLE *)pRgb)[i].rgbtRed;
89
pRgb[i].rgbBlue = ((RGBTRIPLE *)pRgb)[i].rgbtBlue;
90
pRgb[i].rgbGreen = ((RGBTRIPLE *)pRgb)[i].rgbtGreen;
91
pRgb[i].rgbReserved = (BYTE)0;
94
hFile->Read((void*)pRgb,DibNumColors(&bmpHeader) * sizeof(RGBQUAD),1);
95
//force rgbReserved=0, to avoid problems with some WinXp bitmaps
96
for (unsigned int i=0; i<head.biClrUsed; i++) pRgb[i].rgbReserved=0;
100
if (info.nEscape) throw "Cancelled"; // <vho> - cancel decoding
102
switch (dwBitCount) {
104
if (bf.bfOffBits != 0L) hFile->Seek(off + bf.bfOffBits,SEEK_SET);
105
if (dwCompression == BI_BITFIELDS || dwCompression == BI_RGB){
106
long imagesize=4*head.biHeight*head.biWidth;
107
BYTE* buff32=(BYTE*)malloc(imagesize);
109
hFile->Read(buff32, imagesize,1); // read in the pixels
110
Bitfield2RGB(buff32,0,0,0,32);
112
} else throw "can't allocate memory";
113
} else throw "unknown compression";
116
if (bf.bfOffBits != 0L) hFile->Seek(off + bf.bfOffBits,SEEK_SET);
117
if (dwCompression == BI_RGB){
118
hFile->Read(info.pImage, head.biSizeImage,1); // read in the pixels
119
} else throw "unknown compression";
124
if (dwCompression == BI_BITFIELDS)
126
hFile->Read(bfmask, 12, 1);
128
bfmask[0]=0x7C00; bfmask[1]=0x3E0; bfmask[2]=0x1F; //RGB555
130
// bf.bfOffBits required after the bitfield mask <Cui Ying Jie>
131
if (bf.bfOffBits != 0L) hFile->Seek(off + bf.bfOffBits,SEEK_SET);
132
// read in the pixels
133
hFile->Read(info.pImage, head.biHeight*((head.biWidth+1)/2)*4,1);
134
// transform into RGB
135
Bitfield2RGB(info.pImage,(WORD)bfmask[0],(WORD)bfmask[1],(WORD)bfmask[2],16);
141
if (bf.bfOffBits != 0L) hFile->Seek(off + bf.bfOffBits,SEEK_SET);
142
switch (dwCompression) {
144
hFile->Read(info.pImage, head.biSizeImage,1); // read in the pixels
148
BYTE status_byte = 0;
149
BYTE second_byte = 0;
152
BOOL low_nibble = FALSE;
153
CImageIterator iter(this);
155
for (BOOL bContinue = TRUE; bContinue;) {
156
hFile->Read(&status_byte, sizeof(BYTE), 1);
157
switch (status_byte) {
159
hFile->Read(&status_byte, sizeof(BYTE), 1);
160
switch (status_byte) {
166
case RLE_ENDOFBITMAP :
171
// read the delta values
174
hFile->Read(&delta_x, sizeof(BYTE), 1);
175
hFile->Read(&delta_y, sizeof(BYTE), 1);
182
hFile->Read(&second_byte, sizeof(BYTE), 1);
183
BYTE *sline = iter.GetRow(scanline);
184
for (int i = 0; i < status_byte; i++) {
186
if ((DWORD)(sline+bits) < (DWORD)(info.pImage+head.biSizeImage)){
187
*(sline + bits) |= (second_byte & 0x0F);
189
if (i != status_byte - 1)
190
hFile->Read(&second_byte, sizeof(BYTE), 1);
193
if ((DWORD)(sline+bits) < (DWORD)(info.pImage+head.biSizeImage)){
194
*(sline + bits) = (BYTE)(second_byte & 0xF0);
197
low_nibble = !low_nibble;
199
if ((((status_byte+1) >> 1) & 1 )== 1)
200
hFile->Read(&second_byte, sizeof(BYTE), 1);
206
BYTE *sline = iter.GetRow(scanline);
207
hFile->Read(&second_byte, sizeof(BYTE), 1);
208
for (unsigned i = 0; i < status_byte; i++) {
210
if ((DWORD)(sline+bits) < (DWORD)(info.pImage+head.biSizeImage)){
211
*(sline + bits) |= (second_byte & 0x0F);
215
if ((DWORD)(sline+bits) < (DWORD)(info.pImage+head.biSizeImage)){
216
*(sline + bits) = (BYTE)(second_byte & 0xF0);
219
low_nibble = !low_nibble;
229
BYTE status_byte = 0;
230
BYTE second_byte = 0;
233
CImageIterator iter(this);
235
for (BOOL bContinue = TRUE; bContinue; ) {
236
hFile->Read(&status_byte, sizeof(BYTE), 1);
237
switch (status_byte) {
239
hFile->Read(&status_byte, sizeof(BYTE), 1);
240
switch (status_byte) {
245
case RLE_ENDOFBITMAP :
250
// read the delta values
253
hFile->Read(&delta_x, sizeof(BYTE), 1);
254
hFile->Read(&delta_y, sizeof(BYTE), 1);
261
hFile->Read((void *)(iter.GetRow(scanline) + bits), sizeof(BYTE) * status_byte, 1);
262
// align run length to even number of bytes
263
if ((status_byte & 1) == 1)
264
hFile->Read(&second_byte, sizeof(BYTE), 1);
270
BYTE *sline = iter.GetRow(scanline);
271
hFile->Read(&second_byte, sizeof(BYTE), 1);
272
for (unsigned i = 0; i < status_byte; i++) {
273
if ((DWORD)bits<info.dwEffWidth){
274
*(sline + bits) = second_byte;
287
throw "compression type not supported";
291
if (bTopDownDib) Flip(); //<Flanders>
293
} catch (const char *message) {
294
strncpy(info.szLastError,message,255);
295
if (info.nEscape==-1) return true;
300
////////////////////////////////////////////////////////////////////////////////
301
/* ReadDibBitmapInfo()
303
* Will read a file in DIB format and return a global HANDLE to its
304
* BITMAPINFO. This function will work with both "old" and "new"
305
* bitmap formats, but will always return a "new" BITMAPINFO.
307
bool CxImageBMP::DibReadBitmapInfo(CxFile* fh, BITMAPINFOHEADER *pdib)
309
if ((fh==NULL)||(pdib==NULL)) return false;
311
if (fh->Read(pdib,sizeof(BITMAPINFOHEADER),1)==0) return false;
315
switch (pdib->biSize) // what type of bitmap info is this?
317
case sizeof(BITMAPINFOHEADER):
320
case 64: //sizeof(OS2_BMP_HEADER):
321
fh->Seek((long)(64 - sizeof(BITMAPINFOHEADER)),SEEK_CUR);
324
case sizeof(BITMAPCOREHEADER):
325
bc = *(BITMAPCOREHEADER*)pdib;
326
pdib->biSize = bc.bcSize;
327
pdib->biWidth = (DWORD)bc.bcWidth;
328
pdib->biHeight = (DWORD)bc.bcHeight;
329
pdib->biPlanes = bc.bcPlanes;
330
pdib->biBitCount = bc.bcBitCount;
331
pdib->biCompression = BI_RGB;
332
pdib->biSizeImage = 0;
333
pdib->biXPelsPerMeter = 0;
334
pdib->biYPelsPerMeter = 0;
336
pdib->biClrImportant = 0;
338
fh->Seek((long)(sizeof(BITMAPCOREHEADER)-sizeof(BITMAPINFOHEADER)), SEEK_CUR);
343
if (pdib->biSize>(sizeof(BITMAPINFOHEADER))&&
344
(pdib->biSizeImage==(unsigned long)(pdib->biHeight*((((pdib->biBitCount*pdib->biWidth)+31)/32)*4)))&&
345
(pdib->biPlanes==1)&&(pdib->biCompression==BI_RGB)&&(pdib->biClrUsed==0))
347
fh->Seek((long)(pdib->biSize - sizeof(BITMAPINFOHEADER)),SEEK_CUR);
357
////////////////////////////////////////////////////////////////////////////////
358
#endif //CXIMAGE_SUPPORT_DECODE
359
////////////////////////////////////////////////////////////////////////////////
360
#endif // CXIMAGE_SUPPORT_BMP
361
////////////////////////////////////////////////////////////////////////////////