Coverage Report

Created: 2023-12-08 06:53

/src/freeimage-svn/FreeImage/trunk/Source/FreeImage/PluginBMP.cpp
Line
Count
Source (jump to first uncovered line)
1
// ==========================================================
2
// BMP Loader and Writer
3
//
4
// Design and implementation by
5
// - Floris van den Berg (flvdberg@wxs.nl)
6
// - Markus Loibl (markus.loibl@epost.de)
7
// - Martin Weber (martweb@gmx.net)
8
// - Hervé Drolon (drolon@infonie.fr)
9
// - Michal Novotny (michal@etc.cz)
10
// - Mihail Naydenov (mnaydenov@users.sourceforge.net)
11
//
12
// This file is part of FreeImage 3
13
//
14
// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
15
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
16
// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
17
// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
18
// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
19
// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
20
// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
21
// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
22
// THIS DISCLAIMER.
23
//
24
// Use at your own risk!
25
// ==========================================================
26
27
#include "FreeImage.h"
28
#include "Utilities.h"
29
30
// ----------------------------------------------------------
31
//   Constants + headers
32
// ----------------------------------------------------------
33
34
static const BYTE RLE_COMMAND     = 0;
35
static const BYTE RLE_ENDOFLINE   = 0;
36
static const BYTE RLE_ENDOFBITMAP = 1;
37
static const BYTE RLE_DELTA       = 2;
38
39
static const BYTE BI_RGB            = 0;  // compression: none
40
static const BYTE BI_RLE8           = 1;  // compression: RLE 8-bit/pixel
41
static const BYTE BI_RLE4           = 2;  // compression: RLE 4-bit/pixel
42
static const BYTE BI_BITFIELDS      = 3;  // compression: Bit field or Huffman 1D compression for BITMAPCOREHEADER2
43
static const BYTE BI_JPEG           = 4;  // compression: JPEG or RLE-24 compression for BITMAPCOREHEADER2
44
static const BYTE BI_PNG            = 5;  // compression: PNG
45
static const BYTE BI_ALPHABITFIELDS = 6;  // compression: Bit field (this value is valid in Windows CE .NET 4.0 and later)
46
47
// ----------------------------------------------------------
48
49
#ifdef _WIN32
50
#pragma pack(push, 1)
51
#else
52
#pragma pack(1)
53
#endif
54
55
typedef struct tagBITMAPCOREHEADER {
56
  DWORD   bcSize;
57
  WORD    bcWidth;
58
  WORD    bcHeight;
59
  WORD    bcPlanes;
60
  WORD    bcBitCnt;
61
} BITMAPCOREHEADER, *PBITMAPCOREHEADER; 
62
63
typedef struct tagBITMAPINFOOS2_1X_HEADER {
64
  DWORD  biSize;
65
  WORD   biWidth;
66
  WORD   biHeight; 
67
  WORD   biPlanes; 
68
  WORD   biBitCount;
69
} BITMAPINFOOS2_1X_HEADER, *PBITMAPINFOOS2_1X_HEADER; 
70
71
typedef struct tagBITMAPFILEHEADER {
72
  WORD    bfType;   //! The file type
73
  DWORD   bfSize;   //! The size, in bytes, of the bitmap file
74
  WORD    bfReserved1;  //! Reserved; must be zero
75
  WORD    bfReserved2;  //! Reserved; must be zero
76
  DWORD   bfOffBits;  //! The offset, in bytes, from the beginning of the BITMAPFILEHEADER structure to the bitmap bits
77
} BITMAPFILEHEADER, *PBITMAPFILEHEADER;
78
79
#ifdef _WIN32
80
#pragma pack(pop)
81
#else
82
#pragma pack()
83
#endif
84
85
// ==========================================================
86
// Plugin Interface
87
// ==========================================================
88
89
static int s_format_id;
90
91
// ==========================================================
92
// Internal functions
93
// ==========================================================
94
95
#ifdef FREEIMAGE_BIGENDIAN
96
static void
97
SwapInfoHeader(BITMAPINFOHEADER *header) {
98
  SwapLong(&header->biSize);
99
  SwapLong((DWORD *)&header->biWidth);
100
  SwapLong((DWORD *)&header->biHeight);
101
  SwapShort(&header->biPlanes);
102
  SwapShort(&header->biBitCount);
103
  SwapLong(&header->biCompression);
104
  SwapLong(&header->biSizeImage);
105
  SwapLong((DWORD *)&header->biXPelsPerMeter);
106
  SwapLong((DWORD *)&header->biYPelsPerMeter);
107
  SwapLong(&header->biClrUsed);
108
  SwapLong(&header->biClrImportant);
109
}
110
111
static void
112
SwapCoreHeader(BITMAPCOREHEADER *header) {
113
  SwapLong(&header->bcSize);
114
  SwapShort(&header->bcWidth);
115
  SwapShort(&header->bcHeight);
116
  SwapShort(&header->bcPlanes);
117
  SwapShort(&header->bcBitCnt);
118
}
119
120
static void
121
SwapOS21XHeader(BITMAPINFOOS2_1X_HEADER *header) {
122
  SwapLong(&header->biSize);
123
  SwapShort(&header->biWidth);
124
  SwapShort(&header->biHeight);
125
  SwapShort(&header->biPlanes);
126
  SwapShort(&header->biBitCount);
127
}
128
129
static void
130
SwapFileHeader(BITMAPFILEHEADER *header) {
131
  SwapShort(&header->bfType);
132
    SwapLong(&header->bfSize);
133
    SwapShort(&header->bfReserved1);
134
    SwapShort(&header->bfReserved2);
135
  SwapLong(&header->bfOffBits);
136
}
137
#endif
138
139
// --------------------------------------------------------------------------
140
141
/**
142
Check if a BITMAPINFOHEADER is valid
143
@return Returns TRUE if successful, returns FALSE otherwise
144
*/
145
static BOOL
146
57
CheckBitmapInfoHeader(BITMAPINFOHEADER *bih) {
147
57
  if (bih->biSize != sizeof(BITMAPINFOHEADER)) {
148
    // The size, in bytes, of the image.This may be set to zero for BI_RGB bitmaps.
149
    // If biCompression is BI_JPEG or BI_PNG, biSizeImage indicates the size of the JPEG or PNG image buffer, respectively.
150
3
    if ((bih->biSize == 0) && (bih->biCompression != BI_RGB)) {
151
0
      return FALSE;
152
0
    }
153
3
    else if ((bih->biCompression == BI_JPEG) || (bih->biCompression == BI_PNG)) {
154
      // JPEG or PNG is not yet supported
155
0
      return FALSE;
156
0
    }
157
3
    else {
158
3
      return FALSE;
159
3
    }
160
3
  }
161
54
  if (bih->biWidth < 0) {
162
0
    return FALSE;
163
0
  }
164
54
  if (bih->biHeight < 0) {
165
    // If biHeight is negative, indicating a top-down DIB, biCompression must be either BI_RGB or BI_BITFIELDS. 
166
    // Top-down DIBs cannot be compressed.
167
    // If biCompression is BI_JPEG or BI_PNG, the biHeight member specifies the height of the decompressed JPEG or PNG image file, respectively.
168
8
    if ((bih->biCompression != BI_RGB) && (bih->biCompression != BI_BITFIELDS)) {
169
0
      return FALSE;
170
0
    }
171
8
  }
172
54
  if (bih->biPlanes != 1) {
173
    //  The number of planes for the target device. This value must be set to 1.
174
0
    return FALSE;
175
0
  }
176
54
  switch (bih->biBitCount) {
177
0
    case 0:
178
      // The number of bits-per-pixel is specified or is implied by the JPEG or PNG format.
179
      // JPEG or PNG is not yet supported     
180
0
      return FALSE;
181
0
      break;
182
2
    case 1:
183
24
    case 4:
184
47
    case 8:
185
49
    case 16:
186
52
    case 24:
187
54
    case 32:
188
54
      break;
189
0
    default:
190
      // Unsupported bitdepth
191
0
      return FALSE;
192
54
  }
193
54
  switch (bih->biCompression) {
194
7
    case BI_RGB:
195
30
    case BI_RLE8:
196
51
    case BI_RLE4:
197
53
    case BI_BITFIELDS:
198
53
      break;
199
0
    case BI_JPEG:
200
0
    case BI_PNG:
201
1
    default:
202
1
      return FALSE;
203
54
  }
204
205
53
  return TRUE;
206
54
}
207
208
// --------------------------------------------------------------------------
209
210
/**
211
Load uncompressed image pixels for 1-, 4-, 8-, 16-, 24- and 32-bit dib
212
@param io FreeImage IO
213
@param handle FreeImage IO handle
214
@param dib Image to be loaded 
215
@param height Image height
216
@param pitch Image pitch
217
@param bit_count Image bit-depth (1-, 4-, 8-, 16-, 24- or 32-bit)
218
@return Returns TRUE if successful, returns FALSE otherwise
219
*/
220
static BOOL 
221
11
LoadPixelData(FreeImageIO *io, fi_handle handle, FIBITMAP *dib, int height, unsigned pitch, unsigned bit_count) {
222
11
  unsigned count = 0;
223
224
  // Load pixel data
225
  // NB: height can be < 0 for BMP data
226
11
  if (height > 0) {
227
3
    count = io->read_proc((void *)FreeImage_GetBits(dib), height * pitch, 1, handle);
228
3
    if(count != 1) {
229
3
      return FALSE;
230
3
    }
231
8
  } else {
232
8
    int positiveHeight = abs(height);
233
827
    for (int c = 0; c < positiveHeight; ++c) {
234
826
      count = io->read_proc((void *)FreeImage_GetScanLine(dib, positiveHeight - c - 1), pitch, 1, handle);
235
826
      if(count != 1) {
236
7
        return FALSE;
237
7
      }
238
826
    }
239
8
  }
240
241
  // swap as needed
242
#ifdef FREEIMAGE_BIGENDIAN
243
  if (bit_count == 16) {
244
    for(unsigned y = 0; y < FreeImage_GetHeight(dib); y++) {
245
      WORD *pixel = (WORD *)FreeImage_GetScanLine(dib, y);
246
      for(unsigned x = 0; x < FreeImage_GetWidth(dib); x++) {
247
        SwapShort(pixel);
248
        pixel++;
249
      }
250
    }
251
  }
252
#endif
253
254
#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB
255
  if (bit_count == 24 || bit_count == 32) {
256
    for(unsigned y = 0; y < FreeImage_GetHeight(dib); y++) {
257
      BYTE *pixel = FreeImage_GetScanLine(dib, y);
258
      for(unsigned x = 0; x < FreeImage_GetWidth(dib); x++) {
259
        INPLACESWAP(pixel[0], pixel[2]);
260
        pixel += (bit_count >> 3);
261
      }
262
    }
263
  }
264
#endif
265
266
1
  return TRUE;
267
11
}
268
269
/**
270
Load image pixels for 4-bit RLE compressed dib
271
@param io FreeImage IO
272
@param handle FreeImage IO handle
273
@param width Image width
274
@param height Image height
275
@param dib 4-bit image to be loaded 
276
@return Returns TRUE if successful, returns FALSE otherwise
277
*/
278
static BOOL 
279
20
LoadPixelDataRLE4(FreeImageIO *io, fi_handle handle, int width, int height, FIBITMAP *dib) {
280
20
  int status_byte = 0;
281
20
  BYTE second_byte = 0;
282
20
  int bits = 0;
283
284
20
  BYTE *pixels = NULL;  // temporary 8-bit buffer
285
286
20
  try {
287
20
    height = abs(height);
288
289
20
    pixels = (BYTE*)malloc(width * height * sizeof(BYTE));
290
20
    if (!pixels) {
291
0
      throw(1);
292
0
    }
293
20
    memset(pixels, 0, width * height * sizeof(BYTE));
294
295
20
    BYTE *q = pixels;
296
20
    BYTE *end = pixels + height * width;
297
298
5.12k
    for (int scanline = 0; scanline < height; ) {
299
5.12k
      if (q < pixels || q  >= end) {
300
4
        break;
301
4
      }
302
5.12k
      if(io->read_proc(&status_byte, sizeof(BYTE), 1, handle) != 1) {
303
8
        throw(1);
304
8
      }
305
5.11k
      if (status_byte != 0)  {
306
3.17k
        status_byte = (int)MIN((size_t)status_byte, (size_t)(end - q));
307
        // Encoded mode
308
3.17k
        if(io->read_proc(&second_byte, sizeof(BYTE), 1, handle) != 1) {
309
2
          throw(1);
310
2
        }
311
284k
        for (int i = 0; i < status_byte; i++)  {
312
281k
          *q++ = (BYTE)((i & 0x01) ? (second_byte & 0x0f) : ((second_byte >> 4) & 0x0f));
313
281k
        }
314
3.16k
        bits += status_byte;
315
3.16k
      }
316
1.94k
      else {
317
        // Escape mode
318
1.94k
        if(io->read_proc(&status_byte, sizeof(BYTE), 1, handle) != 1) {
319
0
          throw(1);
320
0
        }
321
1.94k
        switch (status_byte) {
322
808
          case RLE_ENDOFLINE:
323
808
          {
324
            // End of line
325
808
            bits = 0;
326
808
            scanline++;
327
808
            q = pixels + scanline * width;
328
808
          }
329
808
          break;
330
331
4
          case RLE_ENDOFBITMAP:
332
            // End of bitmap
333
4
            q = end;
334
4
            break;
335
336
277
          case RLE_DELTA:
337
277
          {
338
            // read the delta values
339
277
            BYTE delta_x = 0;
340
277
            BYTE delta_y = 0;
341
342
277
            if(io->read_proc(&delta_x, sizeof(BYTE), 1, handle) != 1) {
343
0
              throw(1);
344
0
            }
345
277
            if(io->read_proc(&delta_y, sizeof(BYTE), 1, handle) != 1) {
346
0
              throw(1);
347
0
            }
348
349
            // apply them
350
277
            bits += delta_x;
351
277
            scanline += delta_y;
352
277
            q = pixels + scanline*width+bits;
353
277
          }
354
0
          break;
355
356
853
          default:
357
853
          {
358
            // Absolute mode
359
853
            status_byte = (int)MIN((size_t)status_byte, (size_t)(end - q));
360
22.8k
            for (int i = 0; i < status_byte; i++) {
361
22.0k
              if ((i & 0x01) == 0) {
362
11.2k
                if(io->read_proc(&second_byte, sizeof(BYTE), 1, handle) != 1) {
363
4
                  throw(1);
364
4
                }
365
11.2k
              }
366
22.0k
              *q++ = (BYTE)((i & 0x01) ? (second_byte & 0x0f) : ((second_byte >> 4) & 0x0f));
367
22.0k
            }
368
849
            bits += status_byte;
369
            // Read pad byte
370
849
            if (((status_byte & 0x03) == 1) || ((status_byte & 0x03) == 2)) {
371
471
              BYTE padding = 0;
372
471
              if(io->read_proc(&padding, sizeof(BYTE), 1, handle) != 1) {
373
1
                throw(1);
374
1
              }
375
471
            }
376
849
          }
377
848
          break;
378
1.94k
        }
379
1.94k
      }
380
5.11k
    }
381
    
382
5
    {
383
      // Convert to 4-bit
384
6.09M
      for(int y = 0; y < height; y++) {
385
6.09M
        const BYTE *src = (BYTE*)pixels + y * width;
386
6.09M
        BYTE *dst = FreeImage_GetScanLine(dib, y);
387
388
6.09M
        BOOL hinibble = TRUE;
389
390
853M
        for (int cols = 0; cols < width; cols++){
391
847M
          if (hinibble) {
392
423M
            dst[cols >> 1] = (src[cols] << 4);
393
423M
          } else {
394
423M
            dst[cols >> 1] |= src[cols];
395
423M
          }
396
397
847M
          hinibble = !hinibble;
398
847M
        }
399
6.09M
      }
400
5
    }
401
402
5
    free(pixels);
403
404
5
    return TRUE;
405
406
20
  } catch(int) {
407
15
    if (pixels) {
408
15
      free(pixels);
409
15
    }
410
15
    return FALSE;
411
15
  }
412
20
}
413
414
/**
415
Load image pixels for 8-bit RLE compressed dib
416
@param io FreeImage IO
417
@param handle FreeImage IO handle
418
@param width Image width
419
@param height Image height
420
@param dib 8-bit image to be loaded 
421
@return Returns TRUE if successful, returns FALSE otherwise
422
*/
423
static BOOL 
424
23
LoadPixelDataRLE8(FreeImageIO *io, fi_handle handle, int width, int height, FIBITMAP *dib) {
425
23
  BYTE status_byte = 0;
426
23
  BYTE second_byte = 0;
427
23
  int scanline = 0;
428
23
  int bits = 0;
429
23
  int count = 0;
430
23
  BYTE delta_x = 0;
431
23
  BYTE delta_y = 0;
432
433
23
  height = abs(height);
434
  
435
7.12k
  while(scanline < height) {
436
437
7.12k
    if (io->read_proc(&status_byte, sizeof(BYTE), 1, handle) != 1) {
438
3
      return FALSE;
439
3
    }
440
441
7.12k
    if (status_byte == RLE_COMMAND) {
442
3.52k
      if (io->read_proc(&status_byte, sizeof(BYTE), 1, handle) != 1) {
443
0
        return FALSE;
444
0
      }
445
446
3.52k
      switch (status_byte) {
447
1.77k
        case RLE_ENDOFLINE:
448
1.77k
          bits = 0;
449
1.77k
          scanline++;
450
1.77k
          break;
451
452
3
        case RLE_ENDOFBITMAP:
453
3
          return TRUE;
454
455
104
        case RLE_DELTA:
456
          // read the delta values
457
104
          delta_x = 0;
458
104
          delta_y = 0;
459
104
          if (io->read_proc(&delta_x, sizeof(BYTE), 1, handle) != 1) {
460
1
            return FALSE;
461
1
          }
462
103
          if (io->read_proc(&delta_y, sizeof(BYTE), 1, handle) != 1) {
463
0
            return FALSE;
464
0
          }
465
          // apply them
466
103
          bits += delta_x;
467
103
          scanline += delta_y;
468
103
          break;
469
470
1.65k
        default:
471
          // absolute mode
472
1.65k
          count = MIN((int)status_byte, width - bits);
473
1.65k
          if (count < 0) {
474
1
            return FALSE;
475
1
          }
476
1.65k
          BYTE *sline = FreeImage_GetScanLine(dib, scanline);
477
1.65k
          if (io->read_proc((void *)(sline + bits), sizeof(BYTE) * count, 1, handle) != 1) {
478
6
            return FALSE;
479
6
          }
480
          // align run length to even number of bytes
481
1.64k
          if ((status_byte & 1) == 1) {
482
799
            if (io->read_proc(&second_byte, sizeof(BYTE), 1, handle) != 1) {
483
0
              return FALSE;
484
0
            }
485
799
          }
486
1.64k
          bits += status_byte;        
487
1.64k
          break;
488
489
3.52k
      } // switch (status_byte)
490
3.52k
    }
491
3.59k
    else {
492
3.59k
      count = MIN((int)status_byte, width - bits);
493
3.59k
      if (count < 0) {
494
1
        return FALSE;
495
1
      }
496
3.59k
      BYTE *sline = FreeImage_GetScanLine(dib, scanline);
497
3.59k
      if (io->read_proc(&second_byte, sizeof(BYTE), 1, handle) != 1) {
498
6
        return FALSE;
499
6
      }
500
383k
      for (int i = 0; i < count; i++) {
501
380k
        *(sline + bits) = second_byte;
502
380k
        bits++;
503
380k
      }
504
3.58k
    }
505
7.12k
  }
506
  
507
2
  return FALSE;
508
23
}
509
510
// --------------------------------------------------------------------------
511
512
static FIBITMAP *
513
56
LoadWindowsBMP(FreeImageIO *io, fi_handle handle, int flags, unsigned bitmap_bits_offset, int type) {
514
56
  FIBITMAP *dib = NULL;
515
516
56
  try {
517
56
    BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;
518
519
    // load the info header
520
56
    BITMAPINFOHEADER bih;
521
56
    memset(&bih, 0, sizeof(BITMAPINFOHEADER));
522
56
    if (io->read_proc(&bih, sizeof(BITMAPINFOHEADER), 1, handle) != 1) {
523
0
      throw FI_MSG_ERROR_INVALID_FORMAT;
524
0
    }
525
526
#ifdef FREEIMAGE_BIGENDIAN
527
    SwapInfoHeader(&bih);
528
#endif
529
530
56
    if (CheckBitmapInfoHeader(&bih) == FALSE) {
531
3
      throw FI_MSG_ERROR_INVALID_FORMAT;
532
3
    }
533
534
    // keep some general information about the bitmap
535
536
53
    unsigned used_colors  = bih.biClrUsed;
537
53
    int width       = bih.biWidth;
538
53
    int height        = bih.biHeight;   // WARNING: height can be < 0 => check each call using 'height' as a parameter
539
53
    unsigned bit_count    = bih.biBitCount;
540
53
    unsigned compression  = bih.biCompression;
541
53
    unsigned pitch      = CalculatePitch(CalculateLine(width, bit_count));
542
543
53
    switch (bit_count) {
544
2
      case 1 :
545
23
      case 4 :
546
46
      case 8 :
547
46
      {
548
46
        if ((used_colors == 0) || (used_colors > CalculateUsedPaletteEntries(bit_count))) {
549
41
          used_colors = CalculateUsedPaletteEntries(bit_count);
550
41
        }
551
        
552
        // allocate enough memory to hold the bitmap (header, palette, pixels) and read the palette
553
554
46
        dib = FreeImage_AllocateHeader(header_only, width, height, bit_count);
555
46
        if (dib == NULL) {
556
1
          throw FI_MSG_ERROR_DIB_MEMORY;
557
1
        }
558
559
        // set resolution information
560
45
        FreeImage_SetDotsPerMeterX(dib, bih.biXPelsPerMeter);
561
45
        FreeImage_SetDotsPerMeterY(dib, bih.biYPelsPerMeter);
562
563
        // seek to the end of the header (depending on the BMP header version)
564
        // type == sizeof(BITMAPVxINFOHEADER)
565
45
        switch(type) {
566
45
          case 40:  // sizeof(BITMAPINFOHEADER) - all Windows versions since Windows 3.0
567
45
            break;
568
0
          case 52:  // sizeof(BITMAPV2INFOHEADER) (undocumented)
569
0
          case 56:  // sizeof(BITMAPV3INFOHEADER) (undocumented)
570
0
          case 108: // sizeof(BITMAPV4HEADER) - all Windows versions since Windows 95/NT4 (not supported)
571
0
          case 124: // sizeof(BITMAPV5HEADER) - Windows 98/2000 and newer (not supported)
572
0
            io->seek_proc(handle, (long)(type - sizeof(BITMAPINFOHEADER)), SEEK_CUR);
573
0
            break;
574
45
        }
575
        
576
        // load the palette
577
45
        io->read_proc(FreeImage_GetPalette(dib), used_colors * sizeof(RGBQUAD), 1, handle);
578
579
#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB
580
        RGBQUAD *pal = FreeImage_GetPalette(dib);
581
        for(unsigned i = 0; i < used_colors; i++) {
582
          INPLACESWAP(pal[i].rgbRed, pal[i].rgbBlue);
583
        }
584
#endif
585
586
45
        if(header_only) {
587
          // header only mode
588
0
          return dib;
589
0
        }
590
591
        // seek to the actual pixel data.
592
        // this is needed because sometimes the palette is larger than the entries it contains predicts
593
45
        io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);
594
595
        // read the pixel data
596
597
45
        switch (compression) {
598
2
          case BI_RGB :
599
2
            if( LoadPixelData(io, handle, dib, height, pitch, bit_count) ) {
600
0
              return dib;
601
2
            } else {
602
2
              throw "Error encountered while decoding BMP data";
603
2
            }
604
0
            break;
605
606
20
          case BI_RLE4 :
607
20
            if( (bit_count == 4) && LoadPixelDataRLE4(io, handle, width, height, dib) ) {
608
5
              return dib;
609
15
            } else {
610
15
              throw "Error encountered while decoding RLE4 BMP data";
611
15
            }
612
0
            break;
613
614
23
          case BI_RLE8 :
615
23
            if( (bit_count == 8) && LoadPixelDataRLE8(io, handle, width, height, dib) ) {
616
3
              return dib;
617
20
            } else {
618
20
              throw "Error encountered while decoding RLE8 BMP data";
619
20
            }
620
0
            break;
621
622
0
          default :
623
0
            throw FI_MSG_ERROR_UNSUPPORTED_COMPRESSION;
624
45
        }
625
45
      }
626
0
      break; // 1-, 4-, 8-bit
627
628
2
      case 16 :
629
2
      {
630
2
        int use_bitfields = 0;
631
2
        if (bih.biCompression == BI_BITFIELDS) {
632
0
          use_bitfields = 3;
633
0
        }
634
2
        else if (bih.biCompression == BI_ALPHABITFIELDS) {
635
0
          use_bitfields = 4;
636
0
        }
637
2
        else if (type == 52) {
638
0
          use_bitfields = 3;
639
0
        }
640
2
        else if (type >= 56) {
641
0
          use_bitfields = 4;
642
0
        }
643
        
644
2
        if (use_bitfields > 0) {
645
0
          DWORD bitfields[4];
646
0
          io->read_proc(bitfields, use_bitfields * sizeof(DWORD), 1, handle);
647
0
          dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, bitfields[0], bitfields[1], bitfields[2]);
648
2
        } else {
649
2
          dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI16_555_RED_MASK, FI16_555_GREEN_MASK, FI16_555_BLUE_MASK);
650
2
        }
651
652
2
        if (dib == NULL) {
653
0
          throw FI_MSG_ERROR_DIB_MEMORY;            
654
0
        }
655
656
        // set resolution information
657
2
        FreeImage_SetDotsPerMeterX(dib, bih.biXPelsPerMeter);
658
2
        FreeImage_SetDotsPerMeterY(dib, bih.biYPelsPerMeter);
659
660
2
        if(header_only) {
661
          // header only mode
662
0
          return dib;
663
0
        }
664
        
665
        // seek to the actual pixel data
666
2
        io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);
667
668
        // load pixel data and swap as needed if OS is Big Endian
669
2
        LoadPixelData(io, handle, dib, height, pitch, bit_count);
670
671
2
        return dib;
672
2
      }
673
0
      break; // 16-bit RGB
674
675
3
      case 24 :
676
5
      case 32 :
677
5
      {
678
5
        int use_bitfields = 0;
679
5
        if (bih.biCompression == BI_BITFIELDS) {
680
2
          use_bitfields = 3;
681
2
        }
682
3
        else if (bih.biCompression == BI_ALPHABITFIELDS) {
683
0
          use_bitfields = 4;
684
0
        }
685
3
        else if (type == 52) {
686
0
          use_bitfields = 3;
687
0
        }
688
3
        else if (type >= 56) {
689
0
          use_bitfields = 4;
690
0
        }
691
692
5
        if (use_bitfields > 0) {
693
2
          DWORD bitfields[4];
694
2
          io->read_proc(bitfields, use_bitfields * sizeof(DWORD), 1, handle);
695
2
          dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, bitfields[0], bitfields[1], bitfields[2]);
696
3
        } else {
697
3
          if( bit_count == 32 ) {
698
2
            dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
699
2
          } else {
700
1
            dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
701
1
          }
702
3
        }
703
704
5
        if (dib == NULL) {
705
0
          throw FI_MSG_ERROR_DIB_MEMORY;
706
0
        }
707
708
        // set resolution information
709
5
        FreeImage_SetDotsPerMeterX(dib, bih.biXPelsPerMeter);
710
5
        FreeImage_SetDotsPerMeterY(dib, bih.biYPelsPerMeter);
711
712
5
        if(header_only) {
713
          // header only mode
714
0
          return dib;
715
0
        }
716
717
        // Skip over the optional palette 
718
        // A 24 or 32 bit DIB may contain a palette for faster color reduction
719
        // i.e. you can have (FreeImage_GetColorsUsed(dib) > 0)
720
721
        // seek to the actual pixel data
722
5
        io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);
723
724
        // read in the bitmap bits
725
        // load pixel data and swap as needed if OS is Big Endian
726
5
        LoadPixelData(io, handle, dib, height, pitch, bit_count);
727
728
        // check if the bitmap contains transparency, if so enable it in the header
729
730
5
        FreeImage_SetTransparent(dib, (FreeImage_GetColorType(dib) == FIC_RGBALPHA));
731
732
5
        return dib;
733
5
      }
734
0
      break; // 24-, 32-bit
735
53
    }
736
53
  } catch(const char *message) {
737
41
    if(dib) {
738
37
      FreeImage_Unload(dib);
739
37
    }
740
41
    if(message) {
741
41
      FreeImage_OutputMessageProc(s_format_id, message);
742
41
    }
743
41
  }
744
745
41
  return NULL;
746
56
}
747
748
// --------------------------------------------------------------------------
749
750
static FIBITMAP *
751
1
LoadOS22XBMP(FreeImageIO *io, fi_handle handle, int flags, unsigned bitmap_bits_offset) {
752
1
  FIBITMAP *dib = NULL;
753
754
1
  try {
755
1
    BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;
756
757
    // load the info header
758
1
    BITMAPINFOHEADER bih;
759
1
    memset(&bih, 0, sizeof(BITMAPINFOHEADER));
760
1
    if (io->read_proc(&bih, sizeof(BITMAPINFOHEADER), 1, handle) != 1) {
761
0
      throw FI_MSG_ERROR_INVALID_FORMAT;
762
0
    }
763
764
#ifdef FREEIMAGE_BIGENDIAN
765
    SwapInfoHeader(&bih);
766
#endif
767
768
1
    if (CheckBitmapInfoHeader(&bih) == FALSE) {
769
1
      throw FI_MSG_ERROR_INVALID_FORMAT;
770
1
    }
771
772
    // keep some general information about the bitmap
773
774
0
    unsigned used_colors  = bih.biClrUsed;
775
0
    int width       = bih.biWidth;
776
0
    int height        = bih.biHeight;   // WARNING: height can be < 0 => check each read_proc using 'height' as a parameter
777
0
    unsigned bit_count    = bih.biBitCount;
778
0
    unsigned compression  = bih.biCompression;
779
0
    unsigned pitch      = CalculatePitch(CalculateLine(width, bit_count));
780
    
781
0
    switch (bit_count) {
782
0
      case 1 :
783
0
      case 4 :
784
0
      case 8 :
785
0
      {
786
0
        if ((used_colors == 0) || (used_colors > CalculateUsedPaletteEntries(bit_count)))
787
0
          used_colors = CalculateUsedPaletteEntries(bit_count);
788
          
789
        // allocate enough memory to hold the bitmap (header, palette, pixels) and read the palette
790
791
0
        dib = FreeImage_AllocateHeader(header_only, width, height, bit_count);
792
793
0
        if (dib == NULL) {
794
0
          throw FI_MSG_ERROR_DIB_MEMORY;
795
0
        }
796
797
        // set resolution information
798
0
        FreeImage_SetDotsPerMeterX(dib, bih.biXPelsPerMeter);
799
0
        FreeImage_SetDotsPerMeterY(dib, bih.biYPelsPerMeter);
800
        
801
        // load the palette
802
        // note that it may contain RGB or RGBA values : we will calculate this
803
0
        unsigned pal_size = (bitmap_bits_offset - sizeof(BITMAPFILEHEADER) - bih.biSize) / used_colors; 
804
805
0
        io->seek_proc(handle, sizeof(BITMAPFILEHEADER) + bih.biSize, SEEK_SET);
806
807
0
        RGBQUAD *pal = FreeImage_GetPalette(dib);
808
809
0
        if(pal_size == 4) {
810
0
          for (unsigned count = 0; count < used_colors; count++) {
811
0
            FILE_BGRA bgra;
812
813
0
            io->read_proc(&bgra, sizeof(FILE_BGRA), 1, handle);
814
            
815
0
            pal[count].rgbRed = bgra.r;
816
0
            pal[count].rgbGreen = bgra.g;
817
0
            pal[count].rgbBlue  = bgra.b;
818
0
          } 
819
0
        } else if(pal_size == 3) {
820
0
          for (unsigned count = 0; count < used_colors; count++) {
821
0
            FILE_BGR bgr;
822
823
0
            io->read_proc(&bgr, sizeof(FILE_BGR), 1, handle);
824
            
825
0
            pal[count].rgbRed = bgr.r;
826
0
            pal[count].rgbGreen = bgr.g;
827
0
            pal[count].rgbBlue  = bgr.b;
828
0
          } 
829
0
        }
830
        
831
0
        if(header_only) {
832
          // header only mode
833
0
          return dib;
834
0
        }
835
836
        // seek to the actual pixel data.
837
        // this is needed because sometimes the palette is larger than the entries it contains predicts
838
839
0
        if (bitmap_bits_offset > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (used_colors * 3))) {
840
0
          io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);
841
0
        }
842
843
        // read the pixel data
844
845
0
        switch (compression) {
846
0
          case BI_RGB :
847
            // load pixel data 
848
0
            LoadPixelData(io, handle, dib, height, pitch, bit_count);           
849
0
            return dib;
850
851
0
          case BI_RLE4 :
852
0
            if ((bit_count == 4) && LoadPixelDataRLE4(io, handle, width, height, dib)) {
853
0
              return dib;
854
0
            }
855
0
            else {
856
0
              throw "Error encountered while decoding RLE4 BMP data";
857
0
            }
858
0
            break;
859
860
0
          case BI_RLE8 :
861
0
            if ((bit_count == 8) && LoadPixelDataRLE8(io, handle, width, height, dib)) {
862
0
              return dib;
863
0
            }
864
0
            else {
865
0
              throw "Error encountered while decoding RLE8 BMP data";
866
0
            }
867
0
            break;
868
869
0
          default :   
870
0
            throw FI_MSG_ERROR_UNSUPPORTED_COMPRESSION;
871
0
        } 
872
0
      }
873
874
0
      case 16 :
875
0
      {
876
0
        if (bih.biCompression == BI_BITFIELDS) {
877
0
          DWORD bitfields[3];
878
879
0
          io->read_proc(bitfields, 3 * sizeof(DWORD), 1, handle);
880
881
0
          dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, bitfields[0], bitfields[1], bitfields[2]);
882
0
        } else {
883
0
          dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI16_555_RED_MASK, FI16_555_GREEN_MASK, FI16_555_BLUE_MASK);
884
0
        }
885
886
0
        if (dib == NULL) {
887
0
          throw FI_MSG_ERROR_DIB_MEMORY;
888
0
        }
889
890
        // set resolution information
891
0
        FreeImage_SetDotsPerMeterX(dib, bih.biXPelsPerMeter);
892
0
        FreeImage_SetDotsPerMeterY(dib, bih.biYPelsPerMeter);
893
894
0
        if(header_only) {
895
          // header only mode
896
0
          return dib;
897
0
        }
898
899
0
        if (bitmap_bits_offset > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (used_colors * 3))) {
900
0
          io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);
901
0
        }
902
903
        // load pixel data and swap as needed if OS is Big Endian
904
0
        LoadPixelData(io, handle, dib, height, pitch, bit_count);
905
906
0
        return dib;
907
0
      }
908
909
0
      case 24 :
910
0
      case 32 :
911
0
      {
912
0
        if( bit_count == 32 ) {
913
0
          dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
914
0
        } else {
915
0
          dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
916
0
        }
917
918
0
        if (dib == NULL) {
919
0
          throw FI_MSG_ERROR_DIB_MEMORY;
920
0
        }
921
        
922
        // set resolution information
923
0
        FreeImage_SetDotsPerMeterX(dib, bih.biXPelsPerMeter);
924
0
        FreeImage_SetDotsPerMeterY(dib, bih.biYPelsPerMeter);
925
926
0
        if(header_only) {
927
          // header only mode
928
0
          return dib;
929
0
        }
930
931
        // Skip over the optional palette 
932
        // A 24 or 32 bit DIB may contain a palette for faster color reduction
933
934
0
        if (bitmap_bits_offset > (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (used_colors * 3))) {
935
0
          io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);
936
0
        }
937
        
938
        // read in the bitmap bits
939
        // load pixel data and swap as needed if OS is Big Endian
940
0
        LoadPixelData(io, handle, dib, height, pitch, bit_count);
941
942
        // check if the bitmap contains transparency, if so enable it in the header
943
944
0
        FreeImage_SetTransparent(dib, (FreeImage_GetColorType(dib) == FIC_RGBALPHA));
945
946
0
        return dib;
947
0
      }
948
0
    }
949
1
  } catch(const char *message) {
950
1
    if (dib) {
951
0
      FreeImage_Unload(dib);
952
0
    }
953
1
    FreeImage_OutputMessageProc(s_format_id, message);
954
1
  }
955
956
1
  return NULL;
957
1
}
958
959
// --------------------------------------------------------------------------
960
961
static FIBITMAP *
962
2
LoadOS21XBMP(FreeImageIO *io, fi_handle handle, int flags, unsigned bitmap_bits_offset) {
963
2
  FIBITMAP *dib = NULL;
964
965
2
  try {
966
2
    BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;
967
968
    // load the info header
969
2
    BITMAPINFOOS2_1X_HEADER bios2_1x;
970
2
    memset(&bios2_1x, 0, sizeof(BITMAPINFOOS2_1X_HEADER));
971
2
    if (io->read_proc(&bios2_1x, sizeof(BITMAPINFOOS2_1X_HEADER), 1, handle) != 1) {
972
0
      throw FI_MSG_ERROR_INVALID_FORMAT;
973
0
    }
974
975
#ifdef FREEIMAGE_BIGENDIAN
976
    SwapOS21XHeader(&bios2_1x);
977
#endif
978
    // keep some general information about the bitmap
979
980
2
    unsigned used_colors = 0;
981
2
    unsigned width    = bios2_1x.biWidth;
982
2
    unsigned height   = bios2_1x.biHeight;  // WARNING: height can be < 0 => check each read_proc using 'height' as a parameter
983
2
    unsigned bit_count  = bios2_1x.biBitCount;
984
2
    unsigned pitch    = CalculatePitch(CalculateLine(width, bit_count));
985
    
986
2
    switch (bit_count) {
987
0
      case 1 :
988
0
      case 4 :
989
0
      case 8 :
990
0
      {
991
0
        used_colors = CalculateUsedPaletteEntries(bit_count);
992
        
993
        // allocate enough memory to hold the bitmap (header, palette, pixels) and read the palette
994
995
0
        dib = FreeImage_AllocateHeader(header_only, width, height, bit_count);
996
997
0
        if (dib == NULL) {
998
0
          throw FI_MSG_ERROR_DIB_MEMORY;
999
0
        }
1000
1001
        // set resolution information to default values (72 dpi in english units)
1002
0
        FreeImage_SetDotsPerMeterX(dib, 2835);
1003
0
        FreeImage_SetDotsPerMeterY(dib, 2835);
1004
        
1005
        // load the palette
1006
1007
0
        RGBQUAD *pal = FreeImage_GetPalette(dib);
1008
1009
0
        for (unsigned count = 0; count < used_colors; count++) {
1010
0
          FILE_BGR bgr;
1011
1012
0
          io->read_proc(&bgr, sizeof(FILE_BGR), 1, handle);
1013
          
1014
0
          pal[count].rgbRed = bgr.r;
1015
0
          pal[count].rgbGreen = bgr.g;
1016
0
          pal[count].rgbBlue  = bgr.b;
1017
0
        }
1018
        
1019
0
        if(header_only) {
1020
          // header only mode
1021
0
          return dib;
1022
0
        }
1023
1024
        // Skip over the optional palette 
1025
        // A 24 or 32 bit DIB may contain a palette for faster color reduction
1026
1027
0
        io->seek_proc(handle, bitmap_bits_offset, SEEK_SET);
1028
        
1029
        // read the pixel data
1030
1031
        // load pixel data 
1032
0
        LoadPixelData(io, handle, dib, height, pitch, bit_count);
1033
            
1034
0
        return dib;
1035
0
      }
1036
1037
0
      case 16 :
1038
0
      {
1039
0
        dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI16_555_RED_MASK, FI16_555_GREEN_MASK, FI16_555_BLUE_MASK);
1040
1041
0
        if (dib == NULL) {
1042
0
          throw FI_MSG_ERROR_DIB_MEMORY;            
1043
0
        }
1044
1045
        // set resolution information to default values (72 dpi in english units)
1046
0
        FreeImage_SetDotsPerMeterX(dib, 2835);
1047
0
        FreeImage_SetDotsPerMeterY(dib, 2835);
1048
1049
0
        if(header_only) {
1050
          // header only mode
1051
0
          return dib;
1052
0
        }
1053
1054
        // load pixel data and swap as needed if OS is Big Endian
1055
0
        LoadPixelData(io, handle, dib, height, pitch, bit_count);
1056
1057
0
        return dib;
1058
0
      }
1059
1060
0
      case 24 :
1061
2
      case 32 :
1062
2
      {
1063
2
        if( bit_count == 32 ) {
1064
2
          dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
1065
2
        } else {
1066
0
          dib = FreeImage_AllocateHeader(header_only, width, height, bit_count, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
1067
0
        }
1068
1069
2
        if (dib == NULL) {
1070
0
          throw FI_MSG_ERROR_DIB_MEMORY;            
1071
0
        }
1072
1073
        // set resolution information to default values (72 dpi in english units)
1074
2
        FreeImage_SetDotsPerMeterX(dib, 2835);
1075
2
        FreeImage_SetDotsPerMeterY(dib, 2835);
1076
1077
2
        if(header_only) {
1078
          // header only mode
1079
0
          return dib;
1080
0
        }
1081
1082
        // Skip over the optional palette 
1083
        // A 24 or 32 bit DIB may contain a palette for faster color reduction
1084
1085
        // load pixel data and swap as needed if OS is Big Endian
1086
2
        LoadPixelData(io, handle, dib, height, pitch, bit_count);
1087
1088
        // check if the bitmap contains transparency, if so enable it in the header
1089
1090
2
        FreeImage_SetTransparent(dib, (FreeImage_GetColorType(dib) == FIC_RGBALPHA));
1091
1092
2
        return dib;
1093
2
      }
1094
2
    }
1095
2
  } catch(const char *message) { 
1096
0
    if (dib) {
1097
0
      FreeImage_Unload(dib);
1098
0
    }
1099
0
    FreeImage_OutputMessageProc(s_format_id, message);
1100
0
  }
1101
1102
0
  return NULL;
1103
2
}
1104
1105
// ==========================================================
1106
// Plugin Implementation
1107
// ==========================================================
1108
1109
static const char * DLL_CALLCONV
1110
2
Format() {
1111
2
  return "BMP";
1112
2
}
1113
1114
static const char * DLL_CALLCONV
1115
0
Description() {
1116
0
  return "Windows or OS/2 Bitmap";
1117
0
}
1118
1119
static const char * DLL_CALLCONV
1120
0
Extension() {
1121
0
  return "bmp";
1122
0
}
1123
1124
static const char * DLL_CALLCONV
1125
0
RegExpr() {
1126
0
  return "^BM";
1127
0
}
1128
1129
static const char * DLL_CALLCONV
1130
0
MimeType() {
1131
0
  return "image/bmp";
1132
0
}
1133
1134
static BOOL DLL_CALLCONV
1135
30.0k
Validate(FreeImageIO *io, fi_handle handle) {
1136
30.0k
  BYTE bmp_signature1[] = { 0x42, 0x4D };
1137
30.0k
  BYTE bmp_signature2[] = { 0x42, 0x41 };
1138
30.0k
  BYTE signature[2] = { 0, 0 };
1139
1140
30.0k
  io->read_proc(signature, 1, sizeof(bmp_signature1), handle);
1141
1142
30.0k
  if (memcmp(bmp_signature1, signature, sizeof(bmp_signature1)) == 0)
1143
57
    return TRUE;
1144
1145
29.9k
  if (memcmp(bmp_signature2, signature, sizeof(bmp_signature2)) == 0)
1146
2
    return TRUE;
1147
1148
29.9k
  return FALSE;
1149
29.9k
}
1150
1151
static BOOL DLL_CALLCONV
1152
0
SupportsExportDepth(int depth) {
1153
0
  return (
1154
0
      (depth == 1) ||
1155
0
      (depth == 4) ||
1156
0
      (depth == 8) ||
1157
0
      (depth == 16) ||
1158
0
      (depth == 24) ||
1159
0
      (depth == 32)
1160
0
    );
1161
0
}
1162
1163
static BOOL DLL_CALLCONV 
1164
0
SupportsExportType(FREE_IMAGE_TYPE type) {
1165
0
  return (type == FIT_BITMAP) ? TRUE : FALSE;
1166
0
}
1167
1168
static BOOL DLL_CALLCONV
1169
0
SupportsNoPixels() {
1170
0
  return TRUE;
1171
0
}
1172
1173
// ----------------------------------------------------------
1174
1175
static FIBITMAP * DLL_CALLCONV
1176
59
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
1177
59
  if (handle != NULL) {
1178
59
    BITMAPFILEHEADER bitmapfileheader;
1179
59
    DWORD type = 0;
1180
1181
    // we use this offset value to make seemingly absolute seeks relative in the file   
1182
59
    long offset_in_file = io->tell_proc(handle);
1183
1184
    // read the fileheader
1185
59
    memset(&bitmapfileheader, 0, sizeof(BITMAPFILEHEADER));
1186
59
    if (io->read_proc(&bitmapfileheader, sizeof(BITMAPFILEHEADER), 1, handle) != 1) {
1187
0
      return NULL;
1188
0
    }
1189
1190
#ifdef FREEIMAGE_BIGENDIAN
1191
    SwapFileHeader(&bitmapfileheader);
1192
#endif
1193
1194
    // check the signature
1195
59
    if((bitmapfileheader.bfType != 0x4D42) && (bitmapfileheader.bfType != 0x4142)) {
1196
0
      FreeImage_OutputMessageProc(s_format_id, FI_MSG_ERROR_MAGIC_NUMBER);
1197
0
      return NULL;
1198
0
    }
1199
1200
    // read the first byte of the infoheader
1201
59
    io->read_proc(&type, sizeof(DWORD), 1, handle);
1202
59
    io->seek_proc(handle, 0 - (long)sizeof(DWORD), SEEK_CUR);
1203
1204
#ifdef FREEIMAGE_BIGENDIAN
1205
    SwapLong(&type);
1206
#endif
1207
1208
    // call the appropriate load function for the found bitmap type
1209
1210
59
    switch(type) {
1211
2
      case 12:
1212
        // OS/2 and also all Windows versions since Windows 3.0
1213
2
        return LoadOS21XBMP(io, handle, flags, offset_in_file + bitmapfileheader.bfOffBits);
1214
1215
1
      case 64:
1216
        // OS/2
1217
1
        return LoadOS22XBMP(io, handle, flags, offset_in_file + bitmapfileheader.bfOffBits);
1218
1219
54
      case 40:  // BITMAPINFOHEADER - all Windows versions since Windows 3.0
1220
55
      case 52:  // BITMAPV2INFOHEADER (undocumented, partially supported)
1221
55
      case 56:  // BITMAPV3INFOHEADER (undocumented, partially supported)
1222
56
      case 108: // BITMAPV4HEADER - all Windows versions since Windows 95/NT4 (partially supported)
1223
56
      case 124: // BITMAPV5HEADER - Windows 98/2000 and newer (partially supported)
1224
56
        return LoadWindowsBMP(io, handle, flags, offset_in_file + bitmapfileheader.bfOffBits, type);
1225
1226
0
      default:
1227
0
        break;
1228
59
    }
1229
1230
0
    FreeImage_OutputMessageProc(s_format_id, "Unknown bmp subtype with id %d", type);
1231
0
  }
1232
1233
0
  return NULL;
1234
59
}
1235
1236
// ----------------------------------------------------------
1237
1238
/**
1239
Encode a 8-bit source buffer into a 8-bit target buffer using a RLE compression algorithm. 
1240
The size of the target buffer must be equal to the size of the source buffer. 
1241
On return, the function will return the real size of the target buffer, which should be less that or equal to the source buffer size. 
1242
@param target 8-bit Target buffer
1243
@param source 8-bit Source buffer
1244
@param size Source/Target input buffer size
1245
@return Returns the target buffer size
1246
*/
1247
static int
1248
0
RLEEncodeLine(BYTE *target, BYTE *source, int size) {
1249
0
  BYTE buffer[256];
1250
0
  int buffer_size = 0;
1251
0
  int target_pos = 0;
1252
1253
0
  for (int i = 0; i < size; ++i) {
1254
0
    if ((i < size - 1) && (source[i] == source[i + 1])) {
1255
      // find a solid block of same bytes
1256
1257
0
      int j = i + 1;
1258
0
      int jmax = 254 + i;
1259
1260
0
      while ((j < size - 1) && (j < jmax) && (source[j] == source[j + 1]))
1261
0
        ++j;
1262
1263
      // if the block is larger than 3 bytes, use it
1264
      // else put the data into the larger pool
1265
1266
0
      if (((j - i) + 1) > 3) {
1267
        // don't forget to write what we already have in the buffer
1268
1269
0
        switch(buffer_size) {
1270
0
          case 0 :
1271
0
            break;
1272
1273
0
          case RLE_DELTA :
1274
0
            target[target_pos++] = 1;
1275
0
            target[target_pos++] = buffer[0];
1276
0
            target[target_pos++] = 1;
1277
0
            target[target_pos++] = buffer[1];
1278
0
            break;
1279
1280
0
          case RLE_ENDOFBITMAP :
1281
0
            target[target_pos++] = (BYTE)buffer_size;
1282
0
            target[target_pos++] = buffer[0];
1283
0
            break;
1284
1285
0
          default :
1286
0
            target[target_pos++] = RLE_COMMAND;
1287
0
            target[target_pos++] = (BYTE)buffer_size;
1288
0
            memcpy(target + target_pos, buffer, buffer_size);
1289
1290
            // prepare for next run
1291
            
1292
0
            target_pos += buffer_size;
1293
1294
0
            if ((buffer_size & 1) == 1)
1295
0
              target_pos++;
1296
1297
0
            break;
1298
0
        }
1299
1300
        // write the continuous data
1301
1302
0
        target[target_pos++] = (BYTE)((j - i) + 1);
1303
0
        target[target_pos++] = source[i];
1304
1305
0
        buffer_size = 0;
1306
0
      } else {
1307
0
        for (int k = 0; k < (j - i) + 1; ++k) {
1308
0
          buffer[buffer_size++] = source[i + k];
1309
1310
0
          if (buffer_size == 254) {
1311
            // write what we have
1312
1313
0
            target[target_pos++] = RLE_COMMAND;
1314
0
            target[target_pos++] = (BYTE)buffer_size;
1315
0
            memcpy(target + target_pos, buffer, buffer_size);
1316
1317
            // prepare for next run
1318
1319
0
            target_pos += buffer_size;
1320
0
            buffer_size = 0;
1321
0
          }
1322
0
        }
1323
0
      }
1324
1325
0
      i = j;
1326
0
    } else {
1327
0
      buffer[buffer_size++] = source[i];
1328
0
    }
1329
1330
    // write the buffer if it's full
1331
1332
0
    if (buffer_size == 254) {
1333
0
      target[target_pos++] = RLE_COMMAND;
1334
0
      target[target_pos++] = (BYTE)buffer_size;
1335
0
      memcpy(target + target_pos, buffer, buffer_size);
1336
1337
      // prepare for next run
1338
1339
0
      target_pos += buffer_size;
1340
0
      buffer_size = 0;
1341
0
    }
1342
0
  }
1343
1344
  // write the last bytes
1345
1346
0
  switch(buffer_size) {
1347
0
    case 0 :
1348
0
      break;
1349
1350
0
    case RLE_DELTA :
1351
0
      target[target_pos++] = 1;
1352
0
      target[target_pos++] = buffer[0];
1353
0
      target[target_pos++] = 1;
1354
0
      target[target_pos++] = buffer[1];
1355
0
      break;
1356
1357
0
    case RLE_ENDOFBITMAP :
1358
0
      target[target_pos++] = (BYTE)buffer_size;
1359
0
      target[target_pos++] = buffer[0];
1360
0
      break;
1361
1362
0
    default :
1363
0
      target[target_pos++] = RLE_COMMAND;
1364
0
      target[target_pos++] = (BYTE)buffer_size;
1365
0
      memcpy(target + target_pos, buffer, buffer_size);
1366
1367
      // prepare for next run
1368
      
1369
0
      target_pos += buffer_size;
1370
1371
0
      if ((buffer_size & 1) == 1)
1372
0
        target_pos++;
1373
1374
0
      break;      
1375
0
  }
1376
1377
  // write the END_OF_LINE marker
1378
1379
0
  target[target_pos++] = RLE_COMMAND;
1380
0
  target[target_pos++] = RLE_ENDOFLINE;
1381
1382
  // return the written size
1383
1384
0
  return target_pos;
1385
0
}
1386
1387
static BOOL DLL_CALLCONV
1388
0
Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
1389
0
  if ((dib != NULL) && (handle != NULL)) {
1390
    // write the file header
1391
1392
0
    const unsigned dst_width = FreeImage_GetWidth(dib);
1393
0
    const unsigned dst_height = FreeImage_GetHeight(dib);
1394
1395
    // note that the dib may have been created using FreeImage_CreateView
1396
    // we need to recalculate the dst pitch here
1397
0
    const unsigned dst_bpp = FreeImage_GetBPP(dib);
1398
0
    const unsigned dst_pitch = CalculatePitch(CalculateLine(dst_width, dst_bpp));
1399
1400
0
    BITMAPFILEHEADER bitmapfileheader;
1401
0
    bitmapfileheader.bfType = 0x4D42;
1402
0
    bitmapfileheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + FreeImage_GetColorsUsed(dib) * sizeof(RGBQUAD);
1403
0
    bitmapfileheader.bfSize = bitmapfileheader.bfOffBits + dst_height * dst_pitch;
1404
0
    bitmapfileheader.bfReserved1 = 0;
1405
0
    bitmapfileheader.bfReserved2 = 0;
1406
1407
    // take care of the bit fields data of any
1408
1409
0
    bool bit_fields = (dst_bpp == 16) ? true : false;
1410
1411
0
    if (bit_fields) {
1412
0
      bitmapfileheader.bfSize += 3 * sizeof(DWORD);
1413
0
      bitmapfileheader.bfOffBits += 3 * sizeof(DWORD);
1414
0
    }
1415
1416
#ifdef FREEIMAGE_BIGENDIAN
1417
    SwapFileHeader(&bitmapfileheader);
1418
#endif
1419
0
    if (io->write_proc(&bitmapfileheader, sizeof(BITMAPFILEHEADER), 1, handle) != 1) {
1420
0
      return FALSE;
1421
0
    }
1422
1423
    // update the bitmap info header
1424
1425
0
    BITMAPINFOHEADER bih;
1426
0
    memcpy(&bih, FreeImage_GetInfoHeader(dib), sizeof(BITMAPINFOHEADER));
1427
1428
0
    if (bit_fields) {
1429
0
      bih.biCompression = BI_BITFIELDS;
1430
0
    }
1431
0
    else if ((bih.biBitCount == 8) && ((flags & BMP_SAVE_RLE) == BMP_SAVE_RLE)) {
1432
0
      bih.biCompression = BI_RLE8;
1433
0
    }
1434
0
    else {
1435
0
      bih.biCompression = BI_RGB;
1436
0
    }
1437
1438
    // write the bitmap info header
1439
1440
#ifdef FREEIMAGE_BIGENDIAN
1441
    SwapInfoHeader(&bih);
1442
#endif
1443
0
    if (io->write_proc(&bih, sizeof(BITMAPINFOHEADER), 1, handle) != 1) {
1444
0
      return FALSE;
1445
0
    }
1446
1447
    // write the bit fields when we are dealing with a 16 bit BMP
1448
1449
0
    if (bit_fields) {
1450
0
      DWORD d;
1451
1452
0
      d = FreeImage_GetRedMask(dib);
1453
1454
0
      if (io->write_proc(&d, sizeof(DWORD), 1, handle) != 1) {
1455
0
        return FALSE;
1456
0
      }
1457
1458
0
      d = FreeImage_GetGreenMask(dib);
1459
1460
0
      if (io->write_proc(&d, sizeof(DWORD), 1, handle) != 1) {
1461
0
        return FALSE;
1462
0
      }
1463
1464
0
      d = FreeImage_GetBlueMask(dib);
1465
1466
0
      if (io->write_proc(&d, sizeof(DWORD), 1, handle) != 1) {
1467
0
        return FALSE;
1468
0
      }
1469
0
    }
1470
1471
    // write the palette
1472
1473
0
    if (FreeImage_GetPalette(dib) != NULL) {
1474
0
      RGBQUAD *pal = FreeImage_GetPalette(dib);
1475
0
      FILE_BGRA bgra;
1476
0
      for(unsigned i = 0; i < FreeImage_GetColorsUsed(dib); i++ ) {
1477
0
        bgra.b = pal[i].rgbBlue;
1478
0
        bgra.g = pal[i].rgbGreen;
1479
0
        bgra.r = pal[i].rgbRed;
1480
0
        bgra.a = pal[i].rgbReserved;
1481
0
        if (io->write_proc(&bgra, sizeof(FILE_BGRA), 1, handle) != 1) {
1482
0
          return FALSE;
1483
0
        }
1484
0
      }
1485
0
    }
1486
1487
    // write the bitmap data... if RLE compression is enable, use it
1488
1489
0
    if ((dst_bpp == 8) && ((flags & BMP_SAVE_RLE) == BMP_SAVE_RLE)) {
1490
0
      BYTE *buffer = (BYTE*)malloc(dst_pitch * 2 * sizeof(BYTE));
1491
1492
0
      for (unsigned i = 0; i < dst_height; ++i) {
1493
0
        int size = RLEEncodeLine(buffer, FreeImage_GetScanLine(dib, i), FreeImage_GetLine(dib));
1494
1495
0
        if (io->write_proc(buffer, size, 1, handle) != 1) {
1496
0
          free(buffer);
1497
0
          return FALSE;
1498
0
        }
1499
0
      }
1500
1501
0
      buffer[0] = RLE_COMMAND;
1502
0
      buffer[1] = RLE_ENDOFBITMAP;
1503
1504
0
      if (io->write_proc(buffer, 2, 1, handle) != 1) {
1505
0
        free(buffer);
1506
0
        return FALSE;
1507
0
      }
1508
1509
0
      free(buffer);
1510
1511
#ifdef FREEIMAGE_BIGENDIAN
1512
    } else if (dst_bpp == 16) {
1513
      int padding = dst_pitch - dst_width * sizeof(WORD);
1514
      WORD pad = 0;
1515
      WORD pixel;
1516
      for(unsigned y = 0; y < dst_height; y++) {
1517
        BYTE *line = FreeImage_GetScanLine(dib, y);
1518
        for(unsigned x = 0; x < dst_width; x++) {
1519
          pixel = ((WORD *)line)[x];
1520
          SwapShort(&pixel);
1521
          if (io->write_proc(&pixel, sizeof(WORD), 1, handle) != 1) {
1522
            return FALSE;
1523
          }
1524
        }
1525
        if(padding != 0) {
1526
          if(io->write_proc(&pad, padding, 1, handle) != 1) {
1527
            return FALSE;       
1528
          }
1529
        }
1530
      }
1531
#endif
1532
1533
#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB
1534
    } else if (dst_bpp == 24) {
1535
      int padding = dst_pitch - dst_width * sizeof(FILE_BGR);
1536
      DWORD pad = 0;
1537
      FILE_BGR bgr;
1538
      for(unsigned y = 0; y < dst_height; y++) {
1539
        BYTE *line = FreeImage_GetScanLine(dib, y);
1540
        for(unsigned x = 0; x < dst_width; x++) {
1541
          RGBTRIPLE *triple = ((RGBTRIPLE *)line)+x;
1542
          bgr.b = triple->rgbtBlue;
1543
          bgr.g = triple->rgbtGreen;
1544
          bgr.r = triple->rgbtRed;
1545
          if (io->write_proc(&bgr, sizeof(FILE_BGR), 1, handle) != 1) {
1546
            return FALSE;
1547
          }
1548
        }
1549
        if(padding != 0) {
1550
          if(io->write_proc(&pad, padding, 1, handle) != 1) {
1551
            return FALSE;         
1552
          }
1553
        }
1554
      }
1555
    } else if (dst_bpp == 32) {
1556
      FILE_BGRA bgra;
1557
      for(unsigned y = 0; y < dst_height; y++) {
1558
        BYTE *line = FreeImage_GetScanLine(dib, y);
1559
        for(unsigned x = 0; x < dst_width; x++) {
1560
          RGBQUAD *quad = ((RGBQUAD *)line)+x;
1561
          bgra.b = quad->rgbBlue;
1562
          bgra.g = quad->rgbGreen;
1563
          bgra.r = quad->rgbRed;
1564
          bgra.a = quad->rgbReserved;
1565
          if (io->write_proc(&bgra, sizeof(FILE_BGRA), 1, handle) != 1) {
1566
            return FALSE;
1567
          }
1568
        }
1569
      }
1570
#endif
1571
0
    } 
1572
0
    else if (FreeImage_GetPitch(dib) == dst_pitch) {
1573
0
      return (io->write_proc(FreeImage_GetBits(dib), dst_height * dst_pitch, 1, handle) != 1) ? FALSE : TRUE;
1574
0
    }
1575
0
    else {
1576
0
      for (unsigned y = 0; y < dst_height; y++) {
1577
0
        BYTE *line = (BYTE*)FreeImage_GetScanLine(dib, y);
1578
        
1579
0
        if (io->write_proc(line, dst_pitch, 1, handle) != 1) {
1580
0
          return FALSE;
1581
0
        }
1582
0
      }
1583
0
    }
1584
1585
0
    return TRUE;
1586
1587
0
  } else {
1588
0
    return FALSE;
1589
0
  }
1590
0
}
1591
1592
// ==========================================================
1593
//   Init
1594
// ==========================================================
1595
1596
void DLL_CALLCONV
1597
2
InitBMP(Plugin *plugin, int format_id) {
1598
2
  s_format_id = format_id;
1599
1600
2
  plugin->format_proc = Format;
1601
2
  plugin->description_proc = Description;
1602
2
  plugin->extension_proc = Extension;
1603
2
  plugin->regexpr_proc = RegExpr;
1604
2
  plugin->open_proc = NULL;
1605
2
  plugin->close_proc = NULL;
1606
2
  plugin->pagecount_proc = NULL;
1607
2
  plugin->pagecapability_proc = NULL;
1608
2
  plugin->load_proc = Load;
1609
2
  plugin->save_proc = Save;
1610
2
  plugin->validate_proc = Validate;
1611
2
  plugin->mime_proc = MimeType;
1612
2
  plugin->supports_export_bpp_proc = SupportsExportDepth;
1613
2
  plugin->supports_export_type_proc = SupportsExportType;
1614
2
  plugin->supports_icc_profiles_proc = NULL;  // not implemented yet;
1615
2
  plugin->supports_no_pixels_proc = SupportsNoPixels;
1616
2
}