source: liacs/MIR2010/SourceCode/cximage/ximabmp.cpp@ 140

Last change on this file since 140 was 95, checked in by Rick van der Zwet, 15 years ago

Bad boy, improper move of directory

File size: 13.9 KB
Line 
1/*
2 * File: ximabmp.cpp
3 * Purpose: Platform Independent BMP Image Class Loader and Writer
4 * 07/Aug/2001 Davide Pizzolato - www.xdp.it
5 * CxImage version 6.0.0 02/Feb/2008
6 */
7
8#include "ximabmp.h"
9
10#if CXIMAGE_SUPPORT_BMP
11
12#include "ximaiter.h"
13
14////////////////////////////////////////////////////////////////////////////////
15#if CXIMAGE_SUPPORT_ENCODE
16////////////////////////////////////////////////////////////////////////////////
17bool CxImageBMP::Encode(CxFile * hFile)
18{
19
20 if (EncodeSafeCheck(hFile)) return false;
21
22 BITMAPFILEHEADER hdr;
23
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();
28
29 hdr.bfType = ntohs(hdr.bfType);
30 hdr.bfSize = ntohl(hdr.bfSize);
31 hdr.bfOffBits = ntohl(hdr.bfOffBits);
32
33#if CXIMAGE_SUPPORT_ALPHA
34 if (GetNumColors()==0 && AlphaIsValid()){
35
36 BITMAPINFOHEADER infohdr;
37 memcpy(&infohdr,&head,sizeof(BITMAPINFOHEADER));
38 infohdr.biCompression = BI_RGB;
39 infohdr.biBitCount = 32;
40 DWORD dwEffWidth = ((((infohdr.biBitCount * infohdr.biWidth) + 31) / 32) * 4);
41 infohdr.biSizeImage = dwEffWidth * infohdr.biHeight;
42
43 hdr.bfSize = infohdr.biSize + infohdr.biSizeImage + 14 /*sizeof(BITMAPFILEHEADER)*/;
44
45 hdr.bfSize = ntohl(hdr.bfSize);
46 bihtoh(&infohdr);
47
48 // Write the file header
49 hFile->Write(&hdr,min(14,sizeof(BITMAPFILEHEADER)),1);
50 hFile->Write(&infohdr,sizeof(BITMAPINFOHEADER),1);
51 //and DIB+ALPHA interlaced
52 BYTE *srcalpha = AlphaGetPointer();
53 for(long y = 0; y < infohdr.biHeight; ++y){
54 BYTE *srcdib = GetBits(y);
55 for(long x = 0; x < infohdr.biWidth; ++x){
56 hFile->Write(srcdib,3,1);
57 hFile->Write(srcalpha,1,1);
58 srcdib += 3;
59 ++srcalpha;
60 }
61 }
62
63 } else
64#endif //CXIMAGE_SUPPORT_ALPHA
65 {
66 // Write the file header
67 hFile->Write(&hdr,min(14,sizeof(BITMAPFILEHEADER)),1);
68 //copy attributes
69 memcpy(pDib,&head,sizeof(BITMAPINFOHEADER));
70 bihtoh((BITMAPINFOHEADER*)pDib);
71 // Write the DIB header and the pixels
72 hFile->Write(pDib,GetSize(),1);
73 bihtoh((BITMAPINFOHEADER*)pDib);
74 }
75 return true;
76}
77////////////////////////////////////////////////////////////////////////////////
78#endif //CXIMAGE_SUPPORT_ENCODE
79////////////////////////////////////////////////////////////////////////////////
80#if CXIMAGE_SUPPORT_DECODE
81////////////////////////////////////////////////////////////////////////////////
82bool CxImageBMP::Decode(CxFile * hFile)
83{
84 if (hFile == NULL) return false;
85
86 BITMAPFILEHEADER bf;
87 DWORD off = hFile->Tell(); //<CSC>
88 cx_try {
89 if (hFile->Read(&bf,min(14,sizeof(bf)),1)==0) cx_throw("Not a BMP");
90
91 bf.bfSize = ntohl(bf.bfSize);
92 bf.bfOffBits = ntohl(bf.bfOffBits);
93
94 if (bf.bfType != BFT_BITMAP) { //do we have a RC HEADER?
95 bf.bfOffBits = 0L;
96 hFile->Seek(off,SEEK_SET);
97 }
98
99 BITMAPINFOHEADER bmpHeader;
100 if (!DibReadBitmapInfo(hFile,&bmpHeader)) cx_throw("Error reading BMP info");
101 DWORD dwCompression=bmpHeader.biCompression;
102 DWORD dwBitCount=bmpHeader.biBitCount; //preserve for BI_BITFIELDS compression <Thomas Ernst>
103 bool bIsOldBmp = bmpHeader.biSize == sizeof(BITMAPCOREHEADER);
104
105 bool bTopDownDib = bmpHeader.biHeight<0; //<Flanders> check if it's a top-down bitmap
106 if (bTopDownDib) bmpHeader.biHeight=-bmpHeader.biHeight;
107
108 if (info.nEscape == -1) {
109 // Return output dimensions only
110 head.biWidth = bmpHeader.biWidth;
111 head.biHeight = bmpHeader.biHeight;
112 info.dwType = CXIMAGE_FORMAT_BMP;
113 cx_throw("output dimensions returned");
114 }
115
116 if (!Create(bmpHeader.biWidth,bmpHeader.biHeight,bmpHeader.biBitCount,CXIMAGE_FORMAT_BMP))
117 cx_throw("");
118
119 SetXDPI((long) floor(bmpHeader.biXPelsPerMeter * 254.0 / 10000.0 + 0.5));
120 SetYDPI((long) floor(bmpHeader.biYPelsPerMeter * 254.0 / 10000.0 + 0.5));
121
122 if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding
123
124 RGBQUAD *pRgb = GetPalette();
125 if (pRgb){
126 if (bIsOldBmp){
127 // convert a old color table (3 byte entries) to a new
128 // color table (4 byte entries)
129 hFile->Read((void*)pRgb,DibNumColors(&bmpHeader) * sizeof(RGBTRIPLE),1);
130 for (int i=DibNumColors(&head)-1; i>=0; i--){
131 pRgb[i].rgbRed = ((RGBTRIPLE *)pRgb)[i].rgbtRed;
132 pRgb[i].rgbBlue = ((RGBTRIPLE *)pRgb)[i].rgbtBlue;
133 pRgb[i].rgbGreen = ((RGBTRIPLE *)pRgb)[i].rgbtGreen;
134 pRgb[i].rgbReserved = (BYTE)0;
135 }
136 } else {
137 hFile->Read((void*)pRgb,DibNumColors(&bmpHeader) * sizeof(RGBQUAD),1);
138 //force rgbReserved=0, to avoid problems with some WinXp bitmaps
139 for (unsigned int i=0; i<head.biClrUsed; i++) pRgb[i].rgbReserved=0;
140 }
141 }
142
143 if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding
144
145 switch (dwBitCount) {
146 case 32 :
147 DWORD bfmask[3];
148 if (dwCompression == BI_BITFIELDS)
149 {
150 hFile->Read(bfmask, 12, 1);
151 } else {
152 bfmask[0]=0x00FF0000;
153 bfmask[1]=0x0000FF00;
154 bfmask[2]=0x000000FF;
155 }
156 if (bf.bfOffBits != 0L) hFile->Seek(off + bf.bfOffBits,SEEK_SET);
157 if (dwCompression == BI_BITFIELDS || dwCompression == BI_RGB){
158 long imagesize=4*head.biHeight*head.biWidth;
159 BYTE* buff32=(BYTE*)malloc(imagesize);
160 if (buff32){
161 hFile->Read(buff32, imagesize,1); // read in the pixels
162
163#if CXIMAGE_SUPPORT_ALPHA
164 if (dwCompression == BI_RGB){
165 AlphaCreate();
166 if (AlphaIsValid()){
167 bool bAlphaOk = false;
168 BYTE* p;
169 for (long y=0; y<head.biHeight; y++){
170 p = buff32 + 3 + head.biWidth * 4 * y;
171 for (long x=0; x<head.biWidth; x++){
172 if (*p) bAlphaOk = true;
173 AlphaSet(x,y,*p);
174 p+=4;
175 }
176 }
177 // fix if alpha pixels are all zero
178 if (!bAlphaOk) AlphaInvert();
179 }
180 }
181#endif //CXIMAGE_SUPPORT_ALPHA
182
183 Bitfield2RGB(buff32,bfmask[0],bfmask[1],bfmask[2],32);
184 free(buff32);
185 } else cx_throw("can't allocate memory");
186 } else cx_throw("unknown compression");
187 break;
188 case 24 :
189 if (bf.bfOffBits != 0L) hFile->Seek(off + bf.bfOffBits,SEEK_SET);
190 if (dwCompression == BI_RGB){
191 hFile->Read(info.pImage, head.biSizeImage,1); // read in the pixels
192 } else cx_throw("unknown compression");
193 break;
194 case 16 :
195 {
196 DWORD bfmask[3];
197 if (dwCompression == BI_BITFIELDS)
198 {
199 hFile->Read(bfmask, 12, 1);
200 } else {
201 bfmask[0]=0x7C00; bfmask[1]=0x3E0; bfmask[2]=0x1F; //RGB555
202 }
203 // bf.bfOffBits required after the bitfield mask <Cui Ying Jie>
204 if (bf.bfOffBits != 0L) hFile->Seek(off + bf.bfOffBits,SEEK_SET);
205 // read in the pixels
206 hFile->Read(info.pImage, head.biHeight*((head.biWidth+1)/2)*4,1);
207 // transform into RGB
208 Bitfield2RGB(info.pImage,bfmask[0],bfmask[1],bfmask[2],16);
209 break;
210 }
211 case 8 :
212 case 4 :
213 case 1 :
214 if (bf.bfOffBits != 0L) hFile->Seek(off + bf.bfOffBits,SEEK_SET);
215 switch (dwCompression) {
216 case BI_RGB :
217 hFile->Read(info.pImage, head.biSizeImage,1); // read in the pixels
218 break;
219 case BI_RLE4 :
220 {
221 BYTE status_byte = 0;
222 BYTE second_byte = 0;
223 int scanline = 0;
224 int bits = 0;
225 BOOL low_nibble = FALSE;
226 CImageIterator iter(this);
227
228 for (BOOL bContinue = TRUE; bContinue && hFile->Read(&status_byte, sizeof(BYTE), 1);) {
229
230 switch (status_byte) {
231 case RLE_COMMAND :
232 hFile->Read(&status_byte, sizeof(BYTE), 1);
233 switch (status_byte) {
234 case RLE_ENDOFLINE :
235 bits = 0;
236 scanline++;
237 low_nibble = FALSE;
238 break;
239 case RLE_ENDOFBITMAP :
240 bContinue=FALSE;
241 break;
242 case RLE_DELTA :
243 {
244 // read the delta values
245 BYTE delta_x;
246 BYTE delta_y;
247 hFile->Read(&delta_x, sizeof(BYTE), 1);
248 hFile->Read(&delta_y, sizeof(BYTE), 1);
249 // apply them
250 bits += delta_x / 2;
251 scanline += delta_y;
252 break;
253 }
254 default :
255 hFile->Read(&second_byte, sizeof(BYTE), 1);
256 BYTE *sline = iter.GetRow(scanline);
257 for (int i = 0; i < status_byte; i++) {
258 if ((BYTE*)(sline+bits) < (BYTE*)(info.pImage+head.biSizeImage)){
259 if (low_nibble) {
260 if (i&1)
261 *(sline + bits) |= (second_byte & 0x0f);
262 else
263 *(sline + bits) |= (second_byte & 0xf0)>>4;
264 bits++;
265 } else {
266 if (i&1)
267 *(sline + bits) = (BYTE)(second_byte & 0x0f)<<4;
268 else
269 *(sline + bits) = (BYTE)(second_byte & 0xf0);
270 }
271 }
272
273 if ((i & 1) && (i != (status_byte - 1)))
274 hFile->Read(&second_byte, sizeof(BYTE), 1);
275
276 low_nibble = !low_nibble;
277 }
278 if ((((status_byte+1) >> 1) & 1 ) == 1)
279 hFile->Read(&second_byte, sizeof(BYTE), 1);
280 break;
281 };
282 break;
283 default :
284 {
285 BYTE *sline = iter.GetRow(scanline);
286 hFile->Read(&second_byte, sizeof(BYTE), 1);
287 for (unsigned i = 0; i < status_byte; i++) {
288 if ((BYTE*)(sline+bits) < (BYTE*)(info.pImage+head.biSizeImage)){
289 if (low_nibble) {
290 if (i&1)
291 *(sline + bits) |= (second_byte & 0x0f);
292 else
293 *(sline + bits) |= (second_byte & 0xf0)>>4;
294 bits++;
295 } else {
296 if (i&1)
297 *(sline + bits) = (BYTE)(second_byte & 0x0f)<<4;
298 else
299 *(sline + bits) = (BYTE)(second_byte & 0xf0);
300 }
301 }
302 low_nibble = !low_nibble;
303 }
304 }
305 break;
306 };
307 }
308 break;
309 }
310 case BI_RLE8 :
311 {
312 BYTE status_byte = 0;
313 BYTE second_byte = 0;
314 int scanline = 0;
315 int bits = 0;
316 CImageIterator iter(this);
317
318 for (BOOL bContinue = TRUE; bContinue && hFile->Read(&status_byte, sizeof(BYTE), 1);) {
319 switch (status_byte) {
320 case RLE_COMMAND :
321 hFile->Read(&status_byte, sizeof(BYTE), 1);
322 switch (status_byte) {
323 case RLE_ENDOFLINE :
324 bits = 0;
325 scanline++;
326 break;
327 case RLE_ENDOFBITMAP :
328 bContinue=FALSE;
329 break;
330 case RLE_DELTA :
331 {
332 // read the delta values
333 BYTE delta_x;
334 BYTE delta_y;
335 hFile->Read(&delta_x, sizeof(BYTE), 1);
336 hFile->Read(&delta_y, sizeof(BYTE), 1);
337 // apply them
338 bits += delta_x;
339 scanline += delta_y;
340 break;
341 }
342 default :
343 hFile->Read((void *)(iter.GetRow(scanline) + bits), sizeof(BYTE) * status_byte, 1);
344 // align run length to even number of bytes
345 if ((status_byte & 1) == 1)
346 hFile->Read(&second_byte, sizeof(BYTE), 1);
347 bits += status_byte;
348 break;
349 };
350 break;
351 default :
352 BYTE *sline = iter.GetRow(scanline);
353 hFile->Read(&second_byte, sizeof(BYTE), 1);
354 for (unsigned i = 0; i < status_byte; i++) {
355 if ((DWORD)bits<info.dwEffWidth){
356 *(sline + bits) = second_byte;
357 bits++;
358 } else {
359 break;
360 }
361 }
362 break;
363 };
364 }
365 break;
366 }
367 default :
368 cx_throw("compression type not supported");
369 }
370 }
371
372 if (bTopDownDib) Flip(); //<Flanders>
373
374 } cx_catch {
375 if (strcmp(message,"")) strncpy(info.szLastError,message,255);
376 if (info.nEscape == -1 && info.dwType == CXIMAGE_FORMAT_BMP) return true;
377 return false;
378 }
379 return true;
380}
381////////////////////////////////////////////////////////////////////////////////
382/* ReadDibBitmapInfo()
383 *
384 * Will read a file in DIB format and return a global HANDLE to its
385 * BITMAPINFO. This function will work with both "old" and "new"
386 * bitmap formats, but will always return a "new" BITMAPINFO.
387 */
388bool CxImageBMP::DibReadBitmapInfo(CxFile* fh, BITMAPINFOHEADER *pdib)
389{
390 if ((fh==NULL)||(pdib==NULL)) return false;
391
392 if (fh->Read(pdib,sizeof(BITMAPINFOHEADER),1)==0) return false;
393
394 bihtoh(pdib);
395
396 switch (pdib->biSize) // what type of bitmap info is this?
397 {
398 case sizeof(BITMAPINFOHEADER):
399 break;
400
401 case 64: //sizeof(OS2_BMP_HEADER):
402 fh->Seek((long)(64 - sizeof(BITMAPINFOHEADER)),SEEK_CUR);
403 break;
404
405 case sizeof(BITMAPCOREHEADER):
406 {
407 BITMAPCOREHEADER bc = *(BITMAPCOREHEADER*)pdib;
408 pdib->biSize = bc.bcSize;
409 pdib->biWidth = (DWORD)bc.bcWidth;
410 pdib->biHeight = (DWORD)bc.bcHeight;
411 pdib->biPlanes = bc.bcPlanes;
412 pdib->biBitCount = bc.bcBitCount;
413 pdib->biCompression = BI_RGB;
414 pdib->biSizeImage = 0;
415 pdib->biXPelsPerMeter = 0;
416 pdib->biYPelsPerMeter = 0;
417 pdib->biClrUsed = 0;
418 pdib->biClrImportant = 0;
419
420 fh->Seek((long)(sizeof(BITMAPCOREHEADER)-sizeof(BITMAPINFOHEADER)), SEEK_CUR);
421 }
422 break;
423 default:
424 //give a last chance
425 if (pdib->biSize>(sizeof(BITMAPINFOHEADER))&&
426 (pdib->biSizeImage>=(unsigned long)(pdib->biHeight*((((pdib->biBitCount*pdib->biWidth)+31)/32)*4)))&&
427 (pdib->biPlanes==1)&&(pdib->biClrUsed==0))
428 {
429 if (pdib->biCompression==BI_RGB)
430 fh->Seek((long)(pdib->biSize - sizeof(BITMAPINFOHEADER)),SEEK_CUR);
431 break;
432 }
433 return false;
434 }
435
436 FixBitmapInfo(pdib);
437
438 return true;
439}
440////////////////////////////////////////////////////////////////////////////////
441#endif //CXIMAGE_SUPPORT_DECODE
442////////////////////////////////////////////////////////////////////////////////
443#endif // CXIMAGE_SUPPORT_BMP
444////////////////////////////////////////////////////////////////////////////////
Note: See TracBrowser for help on using the repository browser.