~ubuntu-branches/ubuntu/gutsy/amsn/gutsy

« back to all changes in this revision

Viewing changes to utils/TkCximage/src/CxImage/ximabmp.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Theodore Karkoulis
  • Date: 2006-01-04 15:26:02 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20060104152602-ipe1yg00rl3nlklv
Tags: 0.95-1
New Upstream Release (closes: #345052, #278575).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 5.99c 17/Oct/2004
 
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
////////////////////////////////////////////////////////////////////////////////
 
17
bool 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
         //copy attributes
 
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);
 
35
        return true;
 
36
}
 
37
////////////////////////////////////////////////////////////////////////////////
 
38
#endif //CXIMAGE_SUPPORT_ENCODE
 
39
////////////////////////////////////////////////////////////////////////////////
 
40
#if CXIMAGE_SUPPORT_DECODE
 
41
////////////////////////////////////////////////////////////////////////////////
 
42
bool CxImageBMP::Decode(CxFile * hFile)
 
43
{
 
44
        if (hFile == NULL) return false;
 
45
 
 
46
        BITMAPFILEHEADER   bf;
 
47
        DWORD off = hFile->Tell(); //<CSC>
 
48
  try {
 
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?
 
51
        bf.bfOffBits = 0L;
 
52
        hFile->Seek(off,SEEK_SET);
 
53
    }
 
54
 
 
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);
 
60
 
 
61
        bool bTopDownDib = bmpHeader.biHeight<0; //<Flanders> check if it's a top-down bitmap
 
62
        if (bTopDownDib) bmpHeader.biHeight=-bmpHeader.biHeight;
 
63
 
 
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";
 
69
        }
 
70
 
 
71
        if (!Create(bmpHeader.biWidth,bmpHeader.biHeight,bmpHeader.biBitCount,CXIMAGE_FORMAT_BMP))
 
72
                throw "Can't allocate memory";
 
73
 
 
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);
 
78
 
 
79
        if (info.nEscape) throw "Cancelled"; // <vho> - cancel decoding
 
80
 
 
81
    RGBQUAD *pRgb = GetPalette();
 
82
    if (pRgb){
 
83
        if (bIsOldBmp){
 
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;
 
92
            }
 
93
        } else {
 
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;
 
97
        }
 
98
    }
 
99
 
 
100
        if (info.nEscape) throw "Cancelled"; // <vho> - cancel decoding
 
101
 
 
102
        switch (dwBitCount) {
 
103
                case 32 :
 
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);
 
108
                                if (buff32){
 
109
                                        hFile->Read(buff32, imagesize,1); // read in the pixels
 
110
                                        Bitfield2RGB(buff32,0,0,0,32);
 
111
                                        free(buff32);
 
112
                                } else throw "can't allocate memory";
 
113
                        } else throw "unknown compression";
 
114
                        break;
 
115
                case 24 :
 
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";
 
120
                        break;
 
121
                case 16 :
 
122
                {
 
123
                        DWORD bfmask[3];
 
124
                        if (dwCompression == BI_BITFIELDS)
 
125
                        {
 
126
                                hFile->Read(bfmask, 12, 1);
 
127
                        } else {
 
128
                                bfmask[0]=0x7C00; bfmask[1]=0x3E0; bfmask[2]=0x1F; //RGB555
 
129
                        }
 
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);
 
136
                        break;
 
137
                }
 
138
                case 8 :
 
139
                case 4 :
 
140
                case 1 :
 
141
                if (bf.bfOffBits != 0L) hFile->Seek(off + bf.bfOffBits,SEEK_SET);
 
142
                switch (dwCompression) {
 
143
                        case BI_RGB :
 
144
                                hFile->Read(info.pImage, head.biSizeImage,1); // read in the pixels
 
145
                                break;
 
146
                        case BI_RLE4 :
 
147
                        {
 
148
                                BYTE status_byte = 0;
 
149
                                BYTE second_byte = 0;
 
150
                                int scanline = 0;
 
151
                                int bits = 0;
 
152
                                BOOL low_nibble = FALSE;
 
153
                                CImageIterator iter(this);
 
154
 
 
155
                                for (BOOL bContinue = TRUE; bContinue;) {
 
156
                                        hFile->Read(&status_byte, sizeof(BYTE), 1);
 
157
                                        switch (status_byte) {
 
158
                                                case RLE_COMMAND :
 
159
                                                        hFile->Read(&status_byte, sizeof(BYTE), 1);
 
160
                                                        switch (status_byte) {
 
161
                                                                case RLE_ENDOFLINE :
 
162
                                                                        bits = 0;
 
163
                                                                        scanline++;
 
164
                                                                        low_nibble = FALSE;
 
165
                                                                        break;
 
166
                                                                case RLE_ENDOFBITMAP :
 
167
                                                                        bContinue=FALSE;
 
168
                                                                        break;
 
169
                                                                case RLE_DELTA :
 
170
                                                                {
 
171
                                                                        // read the delta values
 
172
                                                                        BYTE delta_x;
 
173
                                                                        BYTE delta_y;
 
174
                                                                        hFile->Read(&delta_x, sizeof(BYTE), 1);
 
175
                                                                        hFile->Read(&delta_y, sizeof(BYTE), 1);
 
176
                                                                        // apply them
 
177
                                                                        bits       += delta_x / 2;
 
178
                                                                        scanline   += delta_y;
 
179
                                                                        break;
 
180
                                                                }
 
181
                                                                default :
 
182
                                                                        hFile->Read(&second_byte, sizeof(BYTE), 1);
 
183
                                                                        BYTE *sline = iter.GetRow(scanline);
 
184
                                                                        for (int i = 0; i < status_byte; i++) {
 
185
                                                                                if (low_nibble) {
 
186
                                                                                        if ((DWORD)(sline+bits) < (DWORD)(info.pImage+head.biSizeImage)){
 
187
                                                                                                *(sline + bits) |=  (second_byte & 0x0F);
 
188
                                                                                        }
 
189
                                                                                        if (i != status_byte - 1)
 
190
                                                                                                hFile->Read(&second_byte, sizeof(BYTE), 1);
 
191
                                                                                        bits++;
 
192
                                                                                } else {
 
193
                                                                                        if ((DWORD)(sline+bits) < (DWORD)(info.pImage+head.biSizeImage)){
 
194
                                                                                                *(sline + bits) = (BYTE)(second_byte & 0xF0);
 
195
                                                                                        }
 
196
                                                                                }
 
197
                                                                                low_nibble = !low_nibble;
 
198
                                                                        }
 
199
                                                                        if ((((status_byte+1) >> 1) & 1 )== 1)
 
200
                                                                                hFile->Read(&second_byte, sizeof(BYTE), 1);                                                                                             
 
201
                                                                        break;
 
202
                                                        };
 
203
                                                        break;
 
204
                                                default :
 
205
                                                {
 
206
                                                        BYTE *sline = iter.GetRow(scanline);
 
207
                                                        hFile->Read(&second_byte, sizeof(BYTE), 1);
 
208
                                                        for (unsigned i = 0; i < status_byte; i++) {
 
209
                                                                if (low_nibble) {
 
210
                                                                        if ((DWORD)(sline+bits) < (DWORD)(info.pImage+head.biSizeImage)){
 
211
                                                                                *(sline + bits) |= (second_byte & 0x0F);
 
212
                                                                        }
 
213
                                                                        bits++;
 
214
                                                                } else {
 
215
                                                                        if ((DWORD)(sline+bits) < (DWORD)(info.pImage+head.biSizeImage)){
 
216
                                                                                *(sline + bits) = (BYTE)(second_byte & 0xF0);
 
217
                                                                        }
 
218
                                                                }                               
 
219
                                                                low_nibble = !low_nibble;
 
220
                                                        }
 
221
                                                }
 
222
                                                break;
 
223
                                        };
 
224
                                }
 
225
                                break;
 
226
                        }
 
227
                        case BI_RLE8 :
 
228
                        {
 
229
                                BYTE status_byte = 0;
 
230
                                BYTE second_byte = 0;
 
231
                                int scanline = 0;
 
232
                                int bits = 0;
 
233
                                CImageIterator iter(this);
 
234
 
 
235
                                for (BOOL bContinue = TRUE; bContinue; ) {
 
236
                                        hFile->Read(&status_byte, sizeof(BYTE), 1);
 
237
                                        switch (status_byte) {
 
238
                                                case RLE_COMMAND :
 
239
                                                        hFile->Read(&status_byte, sizeof(BYTE), 1);
 
240
                                                        switch (status_byte) {
 
241
                                                                case RLE_ENDOFLINE :
 
242
                                                                        bits = 0;
 
243
                                                                        scanline++;
 
244
                                                                        break;
 
245
                                                                case RLE_ENDOFBITMAP :
 
246
                                                                        bContinue=FALSE;
 
247
                                                                        break;
 
248
                                                                case RLE_DELTA :
 
249
                                                                {
 
250
                                                                        // read the delta values
 
251
                                                                        BYTE delta_x;
 
252
                                                                        BYTE delta_y;
 
253
                                                                        hFile->Read(&delta_x, sizeof(BYTE), 1);
 
254
                                                                        hFile->Read(&delta_y, sizeof(BYTE), 1);
 
255
                                                                        // apply them
 
256
                                                                        bits     += delta_x;
 
257
                                                                        scanline += delta_y;
 
258
                                                                        break;
 
259
                                                                }
 
260
                                                                default :
 
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);                                                                                             
 
265
                                                                        bits += status_byte;                                                                                                    
 
266
                                                                        break;                                                          
 
267
                                                        };
 
268
                                                        break;
 
269
                                                default :
 
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;
 
275
                                                                        bits++;                                 
 
276
                                                                } else {
 
277
                                                                        bContinue = FALSE;
 
278
                                                                        break;
 
279
                                                                }
 
280
                                                        }
 
281
                                                        break;
 
282
                                        };
 
283
                                }
 
284
                                break;
 
285
                        }
 
286
                        default :                                                               
 
287
                                throw "compression type not supported";
 
288
                }
 
289
        }
 
290
 
 
291
        if (bTopDownDib) Flip(); //<Flanders>
 
292
 
 
293
  } catch (const char *message) {
 
294
        strncpy(info.szLastError,message,255);
 
295
        if (info.nEscape==-1) return true;
 
296
        return false;
 
297
  }
 
298
    return true;
 
299
}
 
300
////////////////////////////////////////////////////////////////////////////////
 
301
/*  ReadDibBitmapInfo()
 
302
 *
 
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.
 
306
 */
 
307
bool CxImageBMP::DibReadBitmapInfo(CxFile* fh, BITMAPINFOHEADER *pdib)
 
308
{
 
309
        if ((fh==NULL)||(pdib==NULL)) return false;
 
310
 
 
311
    if (fh->Read(pdib,sizeof(BITMAPINFOHEADER),1)==0) return false;
 
312
 
 
313
    BITMAPCOREHEADER   bc;
 
314
 
 
315
    switch (pdib->biSize) // what type of bitmap info is this?
 
316
    {
 
317
        case sizeof(BITMAPINFOHEADER):
 
318
            break;
 
319
 
 
320
                case 64: //sizeof(OS2_BMP_HEADER):
 
321
            fh->Seek((long)(64 - sizeof(BITMAPINFOHEADER)),SEEK_CUR);
 
322
                        break;
 
323
 
 
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;
 
335
            pdib->biClrUsed            = 0;
 
336
            pdib->biClrImportant       = 0;
 
337
 
 
338
                        fh->Seek((long)(sizeof(BITMAPCOREHEADER)-sizeof(BITMAPINFOHEADER)), SEEK_CUR);
 
339
 
 
340
            break;
 
341
        default:
 
342
                        //give a last chance
 
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))
 
346
                         {
 
347
                     fh->Seek((long)(pdib->biSize - sizeof(BITMAPINFOHEADER)),SEEK_CUR);
 
348
                                 break;
 
349
                         }
 
350
                        return false;
 
351
    }
 
352
 
 
353
    FixBitmapInfo(pdib);
 
354
 
 
355
    return true;
 
356
}
 
357
////////////////////////////////////////////////////////////////////////////////
 
358
#endif //CXIMAGE_SUPPORT_DECODE
 
359
////////////////////////////////////////////////////////////////////////////////
 
360
#endif  // CXIMAGE_SUPPORT_BMP
 
361
////////////////////////////////////////////////////////////////////////////////