Coverage Report

Created: 2025-07-23 08:18

/src/graphicsmagick/coders/bmp.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
% Copyright (C) 2003-2024 GraphicsMagick Group
3
% Copyright (C) 2002 ImageMagick Studio
4
% Copyright 1991-1999 E. I. du Pont de Nemours and Company
5
%
6
% This program is covered by multiple licenses, which are described in
7
% Copyright.txt. You should have received a copy of Copyright.txt with this
8
% package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
9
%
10
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11
%                                                                             %
12
%                                                                             %
13
%                                                                             %
14
%                            BBBB   M   M  PPPP                               %
15
%                            B   B  MM MM  P   P                              %
16
%                            BBBB   M M M  PPPP                               %
17
%                            B   B  M   M  P                                  %
18
%                            BBBB   M   M  P                                  %
19
%                                                                             %
20
%                                                                             %
21
%             Read/Write Microsoft Windows Bitmap Image Format.               %
22
%                                                                             %
23
%                                                                             %
24
%                              Software Design                                %
25
%                                John Cristy                                  %
26
%                            Glenn Randers-Pehrson                            %
27
%                               December 2001                                 %
28
%                                                                             %
29
%                                                                             %
30
%                                                                             %
31
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
32
%
33
%
34
*/
35

36
/*
37
  Include declarations.
38
*/
39
#include "magick/studio.h"
40
#include "magick/blob.h"
41
#include "magick/colormap.h"
42
#include "magick/constitute.h"
43
#include "magick/enum_strings.h"
44
#include "magick/log.h"
45
#include "magick/magick.h"
46
#include "magick/monitor.h"
47
#include "magick/pixel_cache.h"
48
#include "magick/profile.h"
49
#include "magick/transform.h"
50
#include "magick/utility.h"
51

52
/*
53
  Macro definitions (from Windows wingdi.h).
54
*/
55
56
#undef BI_JPEG
57
17.1k
#define BI_JPEG  4
58
#undef BI_PNG
59
5.35k
#define BI_PNG  5
60
#ifndef BI_ALPHABITFIELDS
61
2.05k
 #define BI_ALPHABITFIELDS 6
62
#endif
63
#if !defined(MSWINDOWS) || defined(__MINGW32__)
64
#undef BI_RGB
65
8.90k
#define BI_RGB  0
66
#undef BI_RLE8
67
522k
#define BI_RLE8  1
68
#undef BI_RLE4
69
3.15k
#define BI_RLE4  2
70
#undef BI_BITFIELDS
71
2.59k
#define BI_BITFIELDS  3
72
73
#undef LCS_CALIBRATED_RGB
74
2.03k
#define LCS_CALIBRATED_RGB  0
75
#undef LCS_sRGB
76
#define LCS_sRGB  1
77
#undef LCS_WINDOWS_COLOR_SPACE
78
#define LCS_WINDOWS_COLOR_SPACE  2
79
#undef PROFILE_LINKED
80
#define PROFILE_LINKED  3
81
#undef PROFILE_EMBEDDED
82
#define PROFILE_EMBEDDED  4
83
84
#undef LCS_GM_BUSINESS
85
9
#define LCS_GM_BUSINESS  1  /* Saturation */
86
#undef LCS_GM_GRAPHICS
87
3
#define LCS_GM_GRAPHICS  2  /* Relative */
88
#undef LCS_GM_IMAGES
89
3
#define LCS_GM_IMAGES  4  /* Perceptual */
90
#undef LCS_GM_ABS_COLORIMETRIC
91
71
#define LCS_GM_ABS_COLORIMETRIC  8  /* Absolute */
92
#endif /* !defined(MSWINDOWS) || defined(__MINGW32__) */
93
94
#if (QuantumDepth == 8)
95
  #define MS_VAL16_TO_QUANTUM(_value)   ((_value>=8192)?255:(_value>>5))
96
#elif (QuantumDepth == 16)
97
55.8k
  #define MS_VAL16_TO_QUANTUM(_value)   ((_value>=8192)?65535:(_value*8))
98
#elif (QuantumDepth == 32)
99
  #define MS_VAL16_TO_QUANTUM(_value)   ((_value>=8192)?4294443007:(_value*524288))
100
#else
101
# error Unsupported quantum depth.
102
#endif
103
104
105
#ifdef WORDS_BIGENDIAN
106
  #define LD_UINT16_LSB(_pixel, _ptr) _pixel=(magick_uint16_t)*_ptr++; _pixel|=(magick_uint16_t)*_ptr++ << 8
107
#else
108
55.8k
  #define LD_UINT16_LSB(_pixel, _ptr) _pixel=*(magick_uint16_t*)_ptr; _ptr+=2
109
#endif
110
111

112
/*
113
  Typedef declarations.
114
*/
115
typedef struct _BMPInfo
116
{
117
  size_t
118
    file_size,  /* 0 or size of file in bytes */
119
    image_size; /* bytes_per_line*image->rows or uint32_t from file */
120
121
  magick_uint32_t
122
    ba_offset,
123
    offset_bits,/* Starting position of image data in bytes */
124
    size;       /* Header size 12 = v2, 12-64 OS/2 v2, 40 = v3, 108 = v4, 124 = v5 */
125
126
  magick_int32_t
127
    width,      /* BMP width */
128
    height;     /* BMP height (negative means bottom-up) */
129
130
  magick_uint16_t
131
    planes,
132
    bits_per_pixel;
133
134
  magick_uint32_t
135
    compression,
136
    x_pixels,
137
    y_pixels,
138
    number_colors,
139
    colors_important;
140
141
  magick_uint32_t
142
    red_mask,
143
    green_mask,
144
    blue_mask,
145
    alpha_mask;
146
147
  magick_int32_t
148
    colorspace;
149
150
  PrimaryInfo
151
    red_primary,
152
    green_primary,
153
    blue_primary,
154
    gamma_scale;
155
} BMPInfo;
156

157
/*
158
  Forward declarations.
159
*/
160
static unsigned int
161
  WriteBMPImage(const ImageInfo *,Image *);
162

163
/*
164
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
165
%                                                                             %
166
%                                                                             %
167
%                                                                             %
168
%   D e c o d e I m a g e                                                     %
169
%                                                                             %
170
%                                                                             %
171
%                                                                             %
172
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
173
%
174
%  Method DecodeImage unpacks the packed image pixels into runlength-encoded
175
%  pixel packets.
176
%
177
%  The format of the DecodeImage method is:
178
%
179
%      MagickPassFail DecodeImage(Image *image,const unsigned long compression,
180
%        unsigned char *pixels)
181
%
182
%  A description of each parameter follows:
183
%
184
%    o status:  Method DecodeImage returns MagickPass if all the pixels are
185
%      uncompressed without error, otherwise MagickFail.
186
%
187
%    o image: The address of a structure of type Image.
188
%
189
%    o compression:  Zero means uncompressed.  A value of 1 means the
190
%      compressed pixels are runlength encoded for a 256-color bitmap.
191
%      A value of 2 means a 16-color bitmap.  A value of 3 means bitfields
192
%      encoding.
193
%
194
%    o pixels:  The address of a byte (8 bits) array of pixel data created by
195
%      the decoding process.
196
%
197
%    o pixels_size: The size of the allocated buffer array.
198
%
199
*/
200
static MagickPassFail DecodeImage(Image *image,const unsigned long compression,
201
                                  unsigned char *pixels, const size_t pixels_size)
202
419
{
203
419
  unsigned long
204
419
    x,
205
419
    y;
206
207
419
  unsigned int
208
419
    i;
209
210
419
  int
211
419
    byte,
212
419
    count;
213
214
419
  register unsigned char
215
419
    *q;
216
217
419
  unsigned char
218
419
    *end;
219
220
419
  assert(image != (Image *) NULL);
221
419
  assert(pixels != (unsigned char *) NULL);
222
419
  if (image->logging)
223
419
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
224
419
                          "  Decoding RLE compressed pixels to"
225
419
                          " %" MAGICK_SIZE_T_F "u bytes",
226
419
                          (MAGICK_SIZE_T ) image->rows*image->columns);
227
228
419
  (void) memset(pixels,0,pixels_size);
229
419
  byte=0;
230
419
  x=0;
231
419
  q=pixels;
232
419
  end=pixels + pixels_size;
233
  /*
234
    Decompress sufficient data to support the number of pixels (or
235
    rows) in the image and then return.
236
237
    Do not wait to read the final EOL and EOI markers (if not yet
238
    encountered) since we always read this marker just before we
239
    return.
240
  */
241
516k
  for (y=0; y < image->rows; )
242
516k
    {
243
516k
      if (q < pixels || q >= end)
244
139
        {
245
139
          if (image->logging)
246
139
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
247
139
                                  "  Decode buffer full (y=%lu, "
248
139
                                  "pixels_size=%" MAGICK_SIZE_T_F "u, "
249
139
                                  "pixels=%p, q=%p, end=%p)",
250
139
                                  y, (MAGICK_SIZE_T) pixels_size,
251
139
                                  pixels, q, end);
252
139
          break;
253
139
        }
254
516k
      count=ReadBlobByte(image);
255
516k
      if (count == EOF)
256
46
        return MagickFail;
257
516k
      if (count > 0)
258
487k
        {
259
487k
          count=Min(count, end - q);
260
          /*
261
            Encoded mode.
262
          */
263
487k
          byte=ReadBlobByte(image);
264
487k
          if (byte == EOF)
265
14
            return MagickFail;
266
487k
          if (compression == BI_RLE8)
267
15.7k
            {
268
2.60M
              for ( i=count; i != 0; --i )
269
2.58M
                {
270
2.58M
                  *q++=(unsigned char) byte;
271
2.58M
                }
272
15.7k
            }
273
471k
          else
274
471k
            {
275
52.6M
              for ( i=0; i < (unsigned int) count; i++ )
276
52.1M
                {
277
52.1M
                  *q++=(unsigned char)
278
52.1M
                    ((i & 0x01) ? (byte & 0x0f) : ((byte >> 4) & 0x0f));
279
52.1M
                }
280
471k
            }
281
487k
          x+=count;
282
487k
        }
283
28.9k
      else
284
28.9k
        {
285
          /*
286
            Escape mode.
287
          */
288
28.9k
          count=ReadBlobByte(image);
289
28.9k
          if (count == EOF)
290
5
            return MagickFail;
291
28.9k
          if (count == 0x01)
292
3
            {
293
3
              if (image->logging)
294
3
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
295
3
                                      "  RLE Escape code encountered");
296
3
              goto rle_decode_done;
297
3
            }
298
28.9k
          switch (count)
299
28.9k
            {
300
11.6k
            case 0x00:
301
11.6k
              {
302
                /*
303
                  End of line.
304
                */
305
11.6k
                x=0;
306
11.6k
                y++;
307
11.6k
                q=pixels+y*(size_t) image->columns;
308
11.6k
                break;
309
0
              }
310
421
            case 0x02:
311
421
              {
312
                /*
313
                  Delta mode.
314
                */
315
421
                byte=ReadBlobByte(image);
316
421
                if (byte == EOF)
317
1
                  return MagickFail;
318
420
                x+=byte;
319
420
                byte=ReadBlobByte(image);
320
420
                if (byte == EOF)
321
1
                  return MagickFail;
322
419
                y+=byte;
323
419
                q=pixels+y*(size_t) image->columns+x;
324
419
                break;
325
420
              }
326
16.8k
            default:
327
16.8k
              {
328
                /*
329
                  Absolute mode.
330
                */
331
16.8k
                count=Min(count, end - q);
332
16.8k
                if (count < 0)
333
0
                  return MagickFail;
334
16.8k
                if (compression == BI_RLE8)
335
48.6k
                  for (i=count; i != 0; --i)
336
47.7k
                    {
337
47.7k
                      byte=ReadBlobByte(image);
338
47.7k
                      if (byte == EOF)
339
107
                        return MagickFail;
340
47.6k
                      *q++=byte;
341
47.6k
                    }
342
15.8k
                else
343
1.04M
                  for (i=0; i < (unsigned int) count; i++)
344
1.02M
                    {
345
1.02M
                      if ((i & 0x01) == 0)
346
516k
                        {
347
516k
                          byte=ReadBlobByte(image);
348
516k
                          if (byte == EOF)
349
14
                            return MagickFail;
350
516k
                        }
351
1.02M
                      *q++=(unsigned char)
352
1.02M
                        ((i & 0x01) ? (byte & 0x0f) : ((byte >> 4) & 0x0f));
353
1.02M
                    }
354
16.7k
                x+=count;
355
                /*
356
                  Read pad byte.
357
                */
358
16.7k
                if (compression == BI_RLE8)
359
926
                  {
360
926
                    if (count & 0x01)
361
429
                      if (ReadBlobByte(image) == EOF)
362
2
                        return MagickFail;
363
926
                  }
364
15.8k
                else
365
15.8k
                  if (((count & 0x03) == 1) || ((count & 0x03) == 2))
366
1.09k
                    if (ReadBlobByte(image) == EOF)
367
5
                      return MagickFail;
368
16.7k
                break;
369
16.7k
              }
370
28.9k
            }
371
28.9k
        }
372
516k
      if (QuantumTick(y,image->rows))
373
19.7k
        if (!MagickMonitorFormatted(y,image->rows,&image->exception,
374
19.7k
                                    LoadImageText,image->filename,
375
19.7k
                                    image->columns,image->rows))
376
0
          break;
377
516k
    }
378
221
  (void) ReadBlobByte(image);  /* end of line */
379
221
  (void) ReadBlobByte(image);
380
224
 rle_decode_done:
381
224
  if (image->logging)
382
224
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
383
224
                          "  Decoded %" MAGICK_SIZE_T_F "u bytes",
384
224
                          (MAGICK_SIZE_T) (q-pixels));
385
224
  if ((MAGICK_SIZE_T) (q-pixels) < pixels_size)
386
3
    {
387
3
      if (image->logging)
388
3
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
389
3
                              "  RLE decoded output is truncated");
390
3
      return MagickFail;
391
3
    }
392
221
  return(MagickPass);
393
224
}
394

395
/*
396
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
397
%                                                                             %
398
%                                                                             %
399
%                                                                             %
400
%   E n c o d e I m a g e                                                     %
401
%                                                                             %
402
%                                                                             %
403
%                                                                             %
404
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
405
%
406
%  Method EncodeImage compresses pixels using a runlength encoded format.
407
%
408
%  The format of the EncodeImage method is:
409
%
410
%    static unsigned int EncodeImage(Image *image,
411
%      const unsigned long bytes_per_line,const unsigned char *pixels,
412
%      unsigned char *compressed_pixels)
413
%
414
%  A description of each parameter follows:
415
%
416
%    o status:  Method EncodeImage returns the number of bytes in the
417
%      runlength encoded compress_pixels array.
418
%
419
%    o image:  A pointer to an Image structure.
420
%
421
%    o bytes_per_line: The number of bytes in a scanline of compressed pixels
422
%
423
%    o pixels:  The address of a byte (8 bits) array of pixel data created by
424
%      the compression process.
425
%
426
%    o compressed_pixels:  The address of a byte (8 bits) array of compressed
427
%      pixel data.
428
%
429
%
430
*/
431
static size_t EncodeImage(Image *image,const size_t bytes_per_line,
432
  const unsigned char *pixels,unsigned char *compressed_pixels)
433
97
{
434
97
  unsigned long
435
97
    y;
436
437
97
  register const unsigned char
438
97
    *p;
439
440
97
  register unsigned long
441
97
    i,
442
97
    x;
443
444
97
  register unsigned char
445
97
    *q;
446
447
  /*
448
    Runlength encode pixels.
449
  */
450
97
  assert(image != (Image *) NULL);
451
97
  assert(pixels != (const unsigned char *) NULL);
452
97
  assert(compressed_pixels != (unsigned char *) NULL);
453
97
  p=pixels;
454
97
  q=compressed_pixels;
455
97
  i=0;
456
40.6k
  for (y=0; y < image->rows; y++)
457
40.5k
  {
458
20.6M
    for (x=0; x < bytes_per_line; x+=i)
459
20.6M
    {
460
      /*
461
        Determine runlength.
462
      */
463
47.8M
      for (i=1; (((size_t) x+i) < bytes_per_line); i++)
464
47.8M
        if ((i == 255) || (*(p+i) != *p))
465
20.5M
          break;
466
20.6M
      *q++=(unsigned char) i;
467
20.6M
      *q++=(*p);
468
20.6M
      p+=i;
469
20.6M
    }
470
    /*
471
      End of line.
472
    */
473
40.5k
    *q++=0x00;
474
40.5k
    *q++=0x00;
475
40.5k
    if (QuantumTick(y,image->rows))
476
8.38k
      if (!MagickMonitorFormatted(y,image->rows,&image->exception,
477
8.38k
                                  SaveImageText,image->filename,
478
8.38k
                                  image->columns,image->rows))
479
0
        break;
480
40.5k
  }
481
  /*
482
    End of bitmap.
483
  */
484
97
  *q++=0;
485
97
  *q++=0x01;
486
97
  return((size_t) (q-compressed_pixels));
487
97
}
488

489
/*
490
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
491
%                                                                             %
492
%                                                                             %
493
%                                                                             %
494
%   I s B M P                                                                 %
495
%                                                                             %
496
%                                                                             %
497
%                                                                             %
498
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
499
%
500
%  Method IsBMP returns MagickTrue if the image format type, identified by the
501
%  magick string, is BMP.
502
%
503
%  The format of the IsBMP method is:
504
%
505
%      unsigned int IsBMP(const unsigned char *magick,const size_t length)
506
%
507
%  A description of each parameter follows:
508
%
509
%    o status:  Method IsBMP returns MagickTrue if the image format type is BMP.
510
%
511
%    o magick: This string is generally the first few bytes of an image file
512
%      or blob.
513
%
514
%    o length: Specifies the length of the magick string.
515
%
516
%
517
*/
518
static unsigned int IsBMP(const unsigned char *magick,const size_t length)
519
0
{
520
0
  if (length < 2)
521
0
    return(MagickFalse);
522
0
  if ((LocaleNCompare((char *) magick,"BA",2) == 0) ||
523
0
      (LocaleNCompare((char *) magick,"BM",2) == 0) ||
524
0
      (LocaleNCompare((char *) magick,"IC",2) == 0) ||
525
0
      (LocaleNCompare((char *) magick,"PI",2) == 0) ||
526
0
      (LocaleNCompare((char *) magick,"CI",2) == 0) ||
527
0
      (LocaleNCompare((char *) magick,"CP",2) == 0))
528
0
    return(MagickTrue);
529
0
  return(MagickFalse);
530
0
}
531
532
533
static const char *DecodeBiCompression(const magick_uint32_t BiCompression, const magick_uint32_t BiSize)
534
0
{
535
0
  switch(BiCompression)
536
0
  {
537
0
    case BI_RGB:  return "BI_RGB";      /* uncompressed */
538
0
    case BI_RLE4: return "BI_RLE4";     /* 4 bit RLE */
539
0
    case BI_RLE8: return "BI_RLE8";     /* 8 bit RLE */
540
0
    case BI_BITFIELDS:
541
0
                  if(BiSize==64) return "OS/2 Huffman 1D";
542
0
                            else return "BI_BITFIELDS";
543
0
    case BI_JPEG: if(BiSize==64) return "OS/2 RLE-24";
544
0
                            else return "BI_JPEG";
545
0
    case BI_PNG: return  "BI_PNG";
546
0
    case BI_ALPHABITFIELDS: return "BI_ALPHABITFIELDS";
547
0
  }
548
0
  return "UNKNOWN";
549
0
}
550
551
552
static Image *ExtractNestedBlob(Image ** image, const ImageInfo * image_info, int ImgType, ExceptionInfo * exception)
553
7.07k
{
554
7.07k
  size_t
555
7.07k
    alloc_size;
556
557
7.07k
  unsigned char
558
7.07k
    *blob;
559
560
7.07k
  alloc_size = GetBlobSize(*image) - TellBlob(*image);
561
562
7.07k
  if (alloc_size > 0 &&
563
7.07k
      (blob = MagickAllocateResourceLimitedMemory(unsigned char *,alloc_size)) != NULL)
564
6.98k
    {
565
      /* Copy JPG to memory blob */
566
6.98k
      if (ReadBlob(*image,alloc_size,blob) == alloc_size)
567
6.98k
        {
568
6.98k
          Image *image2;
569
6.98k
          ImageInfo *clone_info;
570
571
6.98k
          clone_info = CloneImageInfo(image_info);
572
6.98k
          (void) strlcpy(clone_info->magick, (ImgType==BI_JPEG)?"JPEG":"PNG", sizeof(clone_info->magick));
573
574
          /* BlobToFile("/tmp/jnx-tile.jpg", blob,alloc_size,exception); */
575
576
          /* (void) strlcpy(clone_info->filename, (ImgType==BI_JPEG)?"JPEG:":"PNG:", sizeof(clone_info->filename)); */
577
6.98k
          FormatString(clone_info->filename,"%sblob-%px", ImgType==BI_JPEG?"JPEG:":"PNG:", blob);
578
6.98k
          if ((image2 = BlobToImage(clone_info,blob,alloc_size,exception))
579
6.98k
              != NULL)
580
1.26k
            {
581
1.26k
              if ((*image)->logging)
582
1.26k
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
583
1.26k
                                      "Read embedded %s blob with dimensions %lux%lu",
584
1.26k
                                      image2->magick, image2->rows, image2->columns);
585
              /*
586
                Replace current image with new image while copying
587
                base image attributes.
588
              */
589
1.26k
              (void) strlcpy(image2->filename, (*image)->filename,
590
1.26k
                             sizeof(image2->filename));
591
1.26k
            (void) strlcpy(image2->magick_filename, (*image)->magick_filename,
592
1.26k
                           sizeof(image2->magick_filename));
593
1.26k
            (void) strlcpy(image2->magick, (*image)->magick,
594
1.26k
                           sizeof(image2->magick));
595
1.26k
            DestroyBlob(image2);
596
1.26k
            image2->blob = ReferenceBlob((*image)->blob);
597
1.26k
            if(((*image)->rows == 0) || ((*image)->columns == 0))
598
1.26k
                DeleteImageFromList(image);
599
1.26k
            AppendImageToList(image, image2);
600
1.26k
         }
601
6.98k
          DestroyImageInfo(clone_info);
602
6.98k
          clone_info = (ImageInfo *) NULL;
603
6.98k
          MagickFreeResourceLimitedMemory(blob);
604
6.98k
        }
605
2
      else
606
2
        {
607
2
          MagickFreeResourceLimitedMemory(blob);
608
          /* Failed to read enough data from input */
609
2
          ThrowException(exception,CorruptImageError,UnexpectedEndOfFile, (*image)->filename);
610
2
        }
611
6.98k
    }
612
84
  else
613
84
    {
614
      /* Failed to allocate memory */
615
84
      ThrowException(exception,ResourceLimitError,MemoryAllocationFailed,
616
84
                     (*image)->filename);
617
84
    }
618
7.07k
  return(*image);
619
7.07k
}
620
621

622
/*
623
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
624
%                                                                             %
625
%                                                                             %
626
%                                                                             %
627
%   R e a d B M P I m a g e                                                   %
628
%                                                                             %
629
%                                                                             %
630
%                                                                             %
631
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
632
%
633
%  Method ReadBMPImage reads a Microsoft Windows bitmap image file, Version
634
%  2, 3 (for Windows or NT), or 4, and  returns it.  It allocates the memory
635
%  necessary for the new Image structure and returns a pointer to the new
636
%  image.
637
%
638
%  The format of the ReadBMPImage method is:
639
%
640
%      image=ReadBMPImage(image_info)
641
%
642
%  A description of each parameter follows:
643
%
644
%    o image:  Method ReadBMPImage returns a pointer to the image after
645
%      reading.  A null image is returned if there is a memory shortage or
646
%      if the image cannot be read.
647
%
648
%    o image_info: Specifies a pointer to a ImageInfo structure.
649
%
650
%    o exception: return any errors or warnings in this structure.
651
%
652
%
653
*/
654
11.7k
#define ThrowBMPReaderException(code_,reason_,image_) \
655
11.7k
do { \
656
11.7k
  MagickFreeResourceLimitedMemory(bmp_colormap); \
657
11.7k
  MagickFreeResourceLimitedMemory(pixels); \
658
11.7k
  ThrowReaderException(code_,reason_,image_); \
659
0
} while (0);
660
661
static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
662
14.0k
{
663
14.0k
  BMPInfo
664
14.0k
    bmp_info;
665
666
14.0k
  Image
667
14.0k
    *image;
668
669
14.0k
  int
670
14.0k
    logging;
671
672
14.0k
  long
673
14.0k
    y;
674
675
14.0k
  magick_uint32_t
676
14.0k
    blue,
677
14.0k
    green,
678
14.0k
    opacity,
679
14.0k
    red;
680
681
14.0k
  ExtendedSignedIntegralType
682
14.0k
    start_position;
683
684
14.0k
  register long
685
14.0k
    x;
686
687
14.0k
  register PixelPacket
688
14.0k
    *q;
689
690
14.0k
  register long
691
14.0k
    i;
692
693
14.0k
  register unsigned char
694
14.0k
    *p;
695
696
14.0k
  size_t
697
14.0k
    bytes_per_line,
698
14.0k
    count,
699
14.0k
    length,
700
14.0k
    pixels_size;
701
702
14.0k
  unsigned char
703
14.0k
    *bmp_colormap,
704
14.0k
    magick[12],
705
14.0k
    *pixels;
706
707
14.0k
  unsigned int
708
14.0k
    status;
709
710
14.0k
  magick_off_t
711
14.0k
    file_remaining,
712
14.0k
    file_size,
713
14.0k
    offset;
714
715
  /*
716
    Open image file.
717
  */
718
14.0k
  assert(image_info != (const ImageInfo *) NULL);
719
14.0k
  assert(image_info->signature == MagickSignature);
720
14.0k
  assert(exception != (ExceptionInfo *) NULL);
721
14.0k
  assert(exception->signature == MagickSignature);
722
14.0k
  bmp_colormap=(unsigned char *) NULL;
723
14.0k
  pixels=(unsigned char *) NULL;
724
14.0k
  logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter");
725
14.0k
  image=AllocateImage(image_info);
726
14.0k
  image->rows=0;
727
14.0k
  image->columns=0;
728
14.0k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
729
14.0k
  if (status == MagickFalse)
730
14.0k
    ThrowBMPReaderException(FileOpenError,UnableToOpenFile,image);
731
14.0k
  file_size=GetBlobSize(image);
732
  /*
733
    Determine if this is a BMP file.
734
  */
735
14.0k
  (void) memset(&bmp_info,0,sizeof(BMPInfo));
736
14.0k
  bmp_info.ba_offset=0;
737
14.0k
  start_position=0;
738
14.0k
  magick[0]=magick[1]=0;
739
14.0k
  count=ReadBlob(image,2,(char *) magick);
740
14.0k
  do
741
14.0k
    {
742
14.0k
      PixelPacket
743
14.0k
        quantum_bits,
744
14.0k
        shift;
745
746
14.0k
      magick_uint32_t
747
14.0k
        profile_data,
748
14.0k
        profile_size;
749
750
      /*
751
        Verify BMP identifier.
752
      */
753
      /* if (bmp_info.ba_offset == 0) */ /* FIXME: Investigate. Start position needs to always advance! */
754
14.0k
      start_position=TellBlob(image)-2;
755
14.0k
      bmp_info.ba_offset=0;
756
      /* "BA" is OS/2 bitmap array file */
757
180k
      while (LocaleNCompare((char *) magick,"BA",2) == 0)
758
166k
        {
759
166k
          bmp_info.file_size=ReadBlobLSBLong(image);
760
166k
          bmp_info.ba_offset=ReadBlobLSBLong(image);
761
166k
          bmp_info.offset_bits=ReadBlobLSBLong(image);
762
166k
          if ((count=ReadBlob(image,2,(char *) magick)) != 2)
763
27
            break;
764
166k
        }
765
766
14.0k
      if (count != 2)           /* Found "BA" header from above above */
767
14.0k
        ThrowBMPReaderException(CorruptImageError,ImproperImageHeader,image);
768
769
14.0k
      if (logging )
770
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  Magick: %c%c",
771
0
                              magick[0],magick[1]);
772
773
14.0k
      bmp_info.file_size=ReadBlobLSBLong(image); /* File size in bytes */
774
14.0k
      if (logging)
775
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
776
0
                              "  File size: Claimed=%" MAGICK_SIZE_T_F "u, Actual=%"
777
0
                              MAGICK_OFF_F "d",
778
0
                              (MAGICK_SIZE_T) bmp_info.file_size, file_size);
779
14.0k
      (void) ReadBlobLSBLong(image); /* Reserved */
780
14.0k
      bmp_info.offset_bits=ReadBlobLSBLong(image); /* Bit map offset from start of file */
781
14.0k
      bmp_info.size=ReadBlobLSBLong(image);  /* BMP Header size */
782
14.0k
      if (logging)
783
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
784
0
                              "  Header size: %u\n"
785
0
                              "    Offset bits: %u\n"
786
0
                              "    Image data offset: %u",
787
0
                              bmp_info.size,
788
0
                              bmp_info.offset_bits,
789
0
                              bmp_info.ba_offset);
790
791
14.0k
      if (LocaleNCompare((char *) magick,"BM",2) != 0)  /* "BM" is Windows or OS/2 file. */
792
9.14k
        {
793
9.14k
          if ((LocaleNCompare((char *) magick,"CI",2) != 0) ||  /* "CI" is OS/2 Color Icon */
794
9.14k
              (bmp_info.size!=12 && bmp_info.size!=40 && bmp_info.size!=64)) /* CI chunk must have biSize only 12 or 40 or 64 */
795
7.78k
            ThrowBMPReaderException(CorruptImageError,ImproperImageHeader,image);
796
7.78k
        }
797
798
12.6k
      if ((bmp_info.file_size != 0) && ((magick_off_t) bmp_info.file_size > file_size))
799
12.2k
        ThrowBMPReaderException(CorruptImageError,ImproperImageHeader,image);
800
12.2k
      if (bmp_info.offset_bits < bmp_info.size)
801
11.8k
        ThrowBMPReaderException(CorruptImageError,ImproperImageHeader,image);
802
803
11.8k
      if(bmp_info.size == 12)
804
584
        {
805
          /*
806
            Windows 2.X or OS/2 BMP image file.
807
          */
808
584
          bmp_info.width=(magick_int16_t) ReadBlobLSBShort(image); /* Width */
809
584
          bmp_info.height=(magick_int16_t) ReadBlobLSBShort(image); /* Height */
810
584
          bmp_info.planes=ReadBlobLSBShort(image); /* # of color planes */
811
584
          bmp_info.bits_per_pixel=ReadBlobLSBShort(image); /* Bits per pixel */
812
584
          bmp_info.x_pixels=0;
813
584
          bmp_info.y_pixels=0;
814
584
          bmp_info.number_colors=0;
815
584
          bmp_info.compression=BI_RGB;
816
584
          bmp_info.image_size=0;
817
584
          bmp_info.alpha_mask=0;
818
584
          if (logging)
819
0
            {
820
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
821
0
                                    "  Format: Windows 2.X or OS/2 Bitmap");
822
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
823
0
                                    "  Geometry: %dx%d",bmp_info.width,bmp_info.height);
824
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
825
0
                                    "  Planes: %u",bmp_info.planes);
826
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
827
0
                                    "  Bits per pixel: %u",bmp_info.bits_per_pixel);
828
0
            }
829
584
        }
830
11.2k
      else
831
11.2k
        {
832
          /*
833
            Microsoft Windows 3.X or later BMP image file.
834
          */
835
11.2k
          switch(bmp_info.size)
836
11.2k
            {
837
7.35k
            case 40: if(logging)
838
0
                         (void) LogMagickEvent(CoderEvent, GetMagickModule(), "Format: MS Windows bitmap 3.X");
839
7.35k
                     break;
840
6
            case 52: if(logging)
841
0
                         (void) LogMagickEvent(CoderEvent, GetMagickModule(), "Format: MS Windows bitmap 3.X V2");
842
6
                     break;
843
2
            case 56:if(logging)
844
0
                         (void) LogMagickEvent(CoderEvent, GetMagickModule(), "Format: MS Windows bitmap 3.X V3");
845
2
                     break;
846
1.08k
            case 64: if(logging)
847
0
                         (void) LogMagickEvent(CoderEvent, GetMagickModule(), "Format: OS22XBITMAPHEADER");
848
1.08k
                     break;
849
11
            case 78:
850
13
            case 108: if (logging)
851
0
                         (void) LogMagickEvent(CoderEvent, GetMagickModule(), "Format: MS Windows bitmap 3.X V4");
852
13
                     break;
853
774
            case 124: if(logging)
854
0
                         (void) LogMagickEvent(CoderEvent, GetMagickModule(), "Format: MS Windows bitmap 3.X V5");
855
774
                     break;
856
1.99k
            default: if (bmp_info.size < 64)
857
1.53k
                ThrowBMPReaderException(CorruptImageError, NonOS2HeaderSizeError, image);
858
              /* A value larger than 64 indicates a later version of the OS/2 BMP format.
859
                 .... as far as OS/2 development caesed we could consider to
860
                 close this Trojan's horse window in future. */
861
1.53k
                     if(logging)
862
0
                         (void) LogMagickEvent(CoderEvent, GetMagickModule(), "Format: MS Windows bitmap 3.X ?");
863
1.53k
              break;
864
11.2k
            }
865
866
          /*
867
            BMP v3 defines width and height as signed LONG (32 bit) values.  If
868
            height is a positive number, then the image is a "bottom-up"
869
            bitmap with origin in the lower-left corner.  If height is a
870
            negative number, then the image is a "top-down" bitmap with the
871
            origin in the upper-left corner.  The meaning of negative values
872
            is not defined for width.
873
          */
874
10.7k
          bmp_info.width=(magick_int32_t) ReadBlobLSBLong(image); /* Width */
875
10.7k
          bmp_info.height=(magick_int32_t) ReadBlobLSBLong(image); /* Height */
876
10.7k
          bmp_info.planes=ReadBlobLSBShort(image); /* # of color planes */
877
10.7k
          bmp_info.bits_per_pixel=ReadBlobLSBShort(image); /* Bits per pixel (1/4/8/16/24/32) */
878
10.7k
          bmp_info.compression=ReadBlobLSBLong(image); /* Compression method */
879
10.7k
          bmp_info.image_size=ReadBlobLSBLong(image); /* Bitmap size (bytes) */
880
10.7k
          bmp_info.x_pixels=ReadBlobLSBLong(image); /* Horizontal resolution (pixels/meter) */
881
10.7k
          bmp_info.y_pixels=ReadBlobLSBLong(image); /* Vertical resolution (pixels/meter) */
882
10.7k
          bmp_info.number_colors=ReadBlobLSBLong(image); /* Number of colors */
883
10.7k
          bmp_info.colors_important=ReadBlobLSBLong(image); /* Minimum important colors */
884
10.7k
          profile_data=0;
885
10.7k
          profile_size=0;
886
10.7k
          if (logging)
887
0
            {
888
0
              (void) LogMagickEvent(CoderEvent, GetMagickModule(),
889
0
                                    "    Geometry: %dx%d\n"
890
0
                                    "    Planes: %u\n"
891
0
                                    "    Bits per pixel: %u",
892
0
                                      bmp_info.width, bmp_info.height,
893
0
                                      bmp_info.planes,
894
0
                                      bmp_info.bits_per_pixel);
895
0
              if(bmp_info.compression <= BI_ALPHABITFIELDS)
896
0
                  (void) LogMagickEvent(CoderEvent, GetMagickModule(),
897
0
                                          "  Compression: %s", DecodeBiCompression(bmp_info.compression,bmp_info.size));
898
0
              else
899
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
900
0
                                          "  Compression: UNKNOWN (%u)",bmp_info.compression);
901
0
              (void) LogMagickEvent(CoderEvent, GetMagickModule(),
902
0
                                    "  Number of colors: %u\n"
903
0
                                    "    Important colors: %u",
904
0
                                    bmp_info.number_colors, bmp_info.colors_important);
905
0
            }
906
907
10.7k
          if(bmp_info.size==64)
908
1.08k
            {                           /* OS22XBITMAPHEADER */
909
1.08k
              magick_uint16_t  Units;            /* Type of units used to measure resolution */
910
1.08k
              magick_uint16_t  Reserved;         /* Pad structure to 4-byte boundary */
911
1.08k
              magick_uint16_t  Recording;        /* Recording algorithm */
912
1.08k
              magick_uint16_t  Rendering;        /* Halftoning algorithm used */
913
1.08k
              magick_uint32_t  Size1;            /* Reserved for halftoning algorithm use */
914
1.08k
              magick_uint32_t  Size2;            /* Reserved for halftoning algorithm use */
915
1.08k
              magick_uint32_t  ColorEncoding;    /* Color model used in bitmap */
916
1.08k
              magick_uint32_t  Identifier;       /* Reserved for application use */
917
1.08k
              Units = ReadBlobLSBShort(image);
918
1.08k
              Reserved = ReadBlobLSBShort(image);
919
1.08k
              Recording = ReadBlobLSBShort(image);
920
1.08k
              Rendering = ReadBlobLSBShort(image);
921
1.08k
              Size1 = ReadBlobLSBLong(image);
922
1.08k
              Size2 = ReadBlobLSBLong(image);
923
1.08k
              ColorEncoding = ReadBlobLSBLong(image);
924
1.08k
              Identifier = ReadBlobLSBLong(image);
925
926
1.08k
              if(logging)
927
0
                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
928
0
                              "    Units: %u\n"
929
0
                              "    Reserved: %u\n"
930
0
                              "    Recording: %u\n"
931
0
                              "    Rendering: %u\n"
932
0
                              "    Size1: %u\n"
933
0
                              "    Size2: %u\n"
934
0
                              "    ColorEncoding: %u\n"
935
0
                              "    Identifier: %u",
936
0
                              Units, Reserved, Recording, Rendering,
937
0
                              Size1, Size2, ColorEncoding, Identifier);
938
                  /* OS/2 does not recognise JPEG nor PNG. */
939
1.08k
              if(bmp_info.compression==BI_JPEG || bmp_info.compression==BI_PNG)
940
3
                  ThrowBMPReaderException(CoderError,CompressionNotValid,image)
941
1.08k
            }
942
943
10.7k
          if (bmp_info.size>=52 && bmp_info.size!=64)
944
2.33k
            {
945
2.33k
              bmp_info.red_mask=ReadBlobLSBLong(image);
946
2.33k
              bmp_info.green_mask=ReadBlobLSBLong(image);
947
2.33k
              bmp_info.blue_mask=ReadBlobLSBLong(image);
948
2.33k
              if (bmp_info.size >= 56)
949
2.32k
                {
950
                  /*
951
                    Read color management information.
952
                  */
953
2.32k
                  bmp_info.alpha_mask=ReadBlobLSBLong(image);
954
2.32k
                  if (image->logging)
955
2.32k
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
956
2.32k
                                          "Alpha Mask: 0x%04x",
957
2.32k
                                          bmp_info.alpha_mask);
958
959
2.32k
                  if (bmp_info.size > 120)
960
2.03k
                    {
961
                      /*
962
                        https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapv4header
963
                      */
964
2.03k
                      magick_uint32_t
965
2.03k
                        v4_red_primary_x, v4_red_primary_y, v4_red_primary_z,
966
2.03k
                        v4_green_primary_x, v4_green_primary_y, v4_green_primary_z,
967
2.03k
                        v4_blue_primary_x, v4_blue_primary_y, v4_blue_primary_z,
968
2.03k
                        v4_gamma_x, v4_gamma_y, v4_gamma_z;
969
970
2.03k
                      double
971
2.03k
                        bmp_gamma,
972
2.03k
                        sum;
973
974
2.03k
                      bmp_info.colorspace=(magick_int32_t) ReadBlobLSBLong(image);
975
2.03k
                      if (image->logging)
976
2.03k
                        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
977
2.03k
                                              "BMP Colorspace: 0x%04x",
978
2.03k
                                              bmp_info.colorspace);
979
980
2.03k
                      v4_red_primary_x=ReadBlobLSBLong(image);
981
2.03k
                      v4_red_primary_y=ReadBlobLSBLong(image);
982
2.03k
                      v4_red_primary_z=ReadBlobLSBLong(image);
983
2.03k
                      v4_green_primary_x=ReadBlobLSBLong(image);
984
2.03k
                      v4_green_primary_y=ReadBlobLSBLong(image);
985
2.03k
                      v4_green_primary_z=ReadBlobLSBLong(image);
986
2.03k
                      v4_blue_primary_x=ReadBlobLSBLong(image);
987
2.03k
                      v4_blue_primary_y=ReadBlobLSBLong(image);
988
2.03k
                      v4_blue_primary_z=ReadBlobLSBLong(image);
989
2.03k
                      v4_gamma_x = ReadBlobLSBLong(image);
990
2.03k
                      v4_gamma_y = ReadBlobLSBLong(image);
991
2.03k
                      v4_gamma_z = ReadBlobLSBLong(image);
992
993
2.03k
                      if (LCS_CALIBRATED_RGB == bmp_info.colorspace)
994
584
                        {
995
                          /*
996
                            Decode 2^30 fixed point formatted CIE primaries.
997
                            https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-ciexyztriple
998
                            https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-ciexyz
999
                          */
1000
584
                          bmp_info.red_primary.x=(double) v4_red_primary_x/0x3ffffff;
1001
584
                          bmp_info.red_primary.y=(double) v4_red_primary_y/0x3ffffff;
1002
584
                          bmp_info.red_primary.z=(double) v4_red_primary_z/0x3ffffff;
1003
1004
584
                          bmp_info.green_primary.x=(double) v4_green_primary_x/0x3ffffff;
1005
584
                          bmp_info.green_primary.y=(double) v4_green_primary_y/0x3ffffff;
1006
584
                          bmp_info.green_primary.z=(double) v4_green_primary_z/0x3ffffff;
1007
1008
584
                          bmp_info.blue_primary.x=(double) v4_blue_primary_x/0x3ffffff;
1009
584
                          bmp_info.blue_primary.y=(double) v4_blue_primary_y/0x3ffffff;
1010
584
                          bmp_info.blue_primary.z=(double) v4_blue_primary_z/0x3ffffff;
1011
1012
584
                          if (image->logging)
1013
584
                            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1014
584
                                                  "BMP Primaries: red(%g,%g,%g),"
1015
584
                                                  " green(%g,%g,%g),"
1016
584
                                                  " blue(%g,%g,%g)",
1017
584
                                                  bmp_info.red_primary.x,
1018
584
                                                  bmp_info.red_primary.y,
1019
584
                                                  bmp_info.red_primary.z,
1020
584
                                                  bmp_info.green_primary.x,
1021
584
                                                  bmp_info.green_primary.y,
1022
584
                                                  bmp_info.green_primary.z,
1023
584
                                                  bmp_info.blue_primary.x,
1024
584
                                                  bmp_info.blue_primary.y,
1025
584
                                                  bmp_info.blue_primary.z);
1026
1027
584
                          sum=bmp_info.red_primary.x+bmp_info.red_primary.y+bmp_info.red_primary.z;
1028
584
                          sum=Max(MagickEpsilon,sum);
1029
584
                          bmp_info.red_primary.x/=sum;
1030
584
                          bmp_info.red_primary.y/=sum;
1031
584
                          image->chromaticity.red_primary.x=bmp_info.red_primary.x;
1032
584
                          image->chromaticity.red_primary.y=bmp_info.red_primary.y;
1033
1034
584
                          sum=bmp_info.green_primary.x+bmp_info.green_primary.y+bmp_info.green_primary.z;
1035
584
                          sum=Max(MagickEpsilon,sum);
1036
584
                          bmp_info.green_primary.x/=sum;
1037
584
                          bmp_info.green_primary.y/=sum;
1038
584
                          image->chromaticity.green_primary.x=bmp_info.green_primary.x;
1039
584
                          image->chromaticity.green_primary.y=bmp_info.green_primary.y;
1040
1041
584
                          sum=bmp_info.blue_primary.x+bmp_info.blue_primary.y+bmp_info.blue_primary.z;
1042
584
                          sum=Max(MagickEpsilon,sum);
1043
584
                          bmp_info.blue_primary.x/=sum;
1044
584
                          bmp_info.blue_primary.y/=sum;
1045
584
                          image->chromaticity.blue_primary.x=bmp_info.blue_primary.x;
1046
584
                          image->chromaticity.blue_primary.y=bmp_info.blue_primary.y;
1047
1048
                          /*
1049
                            Decode 16^16 fixed point formatted gamma_scales.
1050
                            Gamma encoded in unsigned fixed 16.16 format. The
1051
                            upper 16 bits are the unsigned integer value. The
1052
                            lower 16 bits are the fractional part.
1053
                          */
1054
584
                          bmp_info.gamma_scale.x=v4_gamma_x/0xffff;
1055
584
                          bmp_info.gamma_scale.y=v4_gamma_y/0xffff;
1056
584
                          bmp_info.gamma_scale.z=v4_gamma_z/0xffff;
1057
1058
                          /*
1059
                            Compute a single averaged gamma from the BMP 3-channel gamma.
1060
                          */
1061
584
                          bmp_gamma = (bmp_info.gamma_scale.x+bmp_info.gamma_scale.y+
1062
584
                                       bmp_info.gamma_scale.z)/3.0;
1063
584
                          if (image->logging)
1064
584
                            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1065
584
                                                  "BMP Gamma: %g", bmp_gamma);
1066
                          /* This range is based on what libpng is willing to accept */
1067
584
                          if (bmp_gamma > 0.00016 && bmp_gamma < 6250.0)
1068
79
                            {
1069
79
                              image->gamma=bmp_gamma;
1070
79
                            }
1071
505
                          else
1072
505
                            {
1073
505
                              if (image->logging)
1074
505
                                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1075
505
                                                      "Ignoring illegal BMP gamma value %g "
1076
505
                                                      "(gamma scale xyz %g,%g,%g)",
1077
505
                                                      bmp_gamma, bmp_info.gamma_scale.x,
1078
505
                                                      bmp_info.gamma_scale.y, bmp_info.gamma_scale.z);
1079
505
                            }
1080
584
                        }
1081
2.03k
                    }
1082
2.32k
                }
1083
2.33k
            }
1084
10.7k
          if (bmp_info.size > 108)
1085
2.25k
            {
1086
              /*
1087
                https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapv5header
1088
                https://www.loc.gov/preservation/digital/formats/fdd/fdd000189.shtml
1089
              */
1090
2.25k
              magick_uint32_t
1091
2.25k
                intent;
1092
1093
              /*
1094
                Read BMP Version 5 color management information.
1095
              */
1096
2.25k
              intent=ReadBlobLSBLong(image);
1097
2.25k
              switch ((int) intent)
1098
2.25k
                {
1099
8
                case LCS_GM_BUSINESS:
1100
8
                  {
1101
8
                    image->rendering_intent=SaturationIntent;
1102
8
                    break;
1103
0
                  }
1104
2
                case LCS_GM_GRAPHICS:
1105
2
                  {
1106
2
                    image->rendering_intent=RelativeIntent;
1107
2
                    break;
1108
0
                  }
1109
2
                case LCS_GM_IMAGES:
1110
2
                  {
1111
2
                    image->rendering_intent=PerceptualIntent;
1112
2
                    break;
1113
0
                  }
1114
70
                case LCS_GM_ABS_COLORIMETRIC:
1115
70
                  {
1116
70
                    image->rendering_intent=AbsoluteIntent;
1117
70
                    break;
1118
0
                  }
1119
2.25k
                }
1120
2.25k
              profile_data=ReadBlobLSBLong(image);
1121
2.25k
              profile_size=ReadBlobLSBLong(image);
1122
2.25k
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1123
2.25k
                                    "  Profile: size %u data %u",
1124
2.25k
                                    profile_size,profile_data);
1125
2.25k
              (void) ReadBlobLSBLong(image);  /* Reserved byte */
1126
2.25k
            }
1127
10.7k
        }
1128
1129
11.3k
      if (EOFBlob(image))
1130
10.3k
        ThrowBMPReaderException(CorruptImageError,UnexpectedEndOfFile,image);
1131
1132
      /*
1133
        It seems that some BMPs claim a file size two bytes larger than
1134
        they actually are so allow some slop before warning about file
1135
        size.
1136
      */
1137
10.3k
      if ((magick_off_t) bmp_info.file_size > file_size+2)
1138
0
        {
1139
0
          ThrowException(exception,CorruptImageWarning,
1140
0
                         LengthAndFilesizeDoNotMatch,image->filename);
1141
0
        }
1142
10.3k
      if (logging && (magick_off_t) bmp_info.file_size < file_size)
1143
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1144
0
                              "  Discarding all data beyond bmp_info.file_size");
1145
10.3k
      if (bmp_info.width <= 0)
1146
9.78k
        ThrowBMPReaderException(CorruptImageError,NegativeOrZeroImageSize,image);
1147
9.78k
      if ((bmp_info.height) == 0 || (bmp_info.height < -2147483647))
1148
9.77k
        ThrowBMPReaderException(CorruptImageError,NegativeOrZeroImageSize,image);
1149
9.77k
      if ((bmp_info.height < 0) && (bmp_info.compression !=0))
1150
9.28k
        ThrowBMPReaderException(CorruptImageError,CompressionNotValid,image);
1151
9.28k
      switch ((unsigned int) bmp_info.compression)
1152
9.28k
        {
1153
198
        case BI_BITFIELDS:
1154
198
          if(bmp_info.size==40)
1155
188
            {
1156
188
              if(bmp_info.ba_offset==0) bmp_info.ba_offset=52;
1157
188
              if(bmp_info.ba_offset<52)         /* check for gap size >=12*/
1158
184
                 ThrowBMPReaderException(CorruptImageError,CorruptImage,image);
1159
184
              bmp_info.red_mask=ReadBlobLSBLong(image);
1160
184
              bmp_info.green_mask=ReadBlobLSBLong(image);
1161
184
              bmp_info.blue_mask=ReadBlobLSBLong(image);
1162
184
              goto CheckBitSize;
1163
188
            }
1164
10
          goto CheckAlphaBitSize;
1165
325
        case BI_ALPHABITFIELDS:
1166
325
          if(bmp_info.size==40)
1167
289
            {
1168
289
              if(bmp_info.ba_offset==0) bmp_info.ba_offset=56;
1169
289
              if(bmp_info.ba_offset<56)         /* check for gap size >=16*/
1170
288
                 ThrowBMPReaderException(CorruptImageError,CorruptImage,image);
1171
288
              bmp_info.red_mask=ReadBlobLSBLong(image);
1172
288
              bmp_info.green_mask=ReadBlobLSBLong(image);
1173
288
              bmp_info.blue_mask=ReadBlobLSBLong(image);
1174
288
              bmp_info.alpha_mask=ReadBlobLSBLong(image);
1175
288
            }
1176
334
CheckAlphaBitSize:
1177
334
            if (image->logging)
1178
334
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1179
334
                                        "Alpha Mask: 0x%04x",
1180
334
                                        bmp_info.alpha_mask);
1181
518
CheckBitSize:
1182
518
            if (image->logging)
1183
518
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1184
518
                                        "Red Mask: 0x%04x\n"
1185
518
                                        "Green Mask: 0x%04x\n"
1186
518
                                        "Blue Mask: 0x%04x",
1187
518
                                            bmp_info.red_mask, bmp_info.green_mask, bmp_info.blue_mask);
1188
518
          if(!(bmp_info.bits_per_pixel==16 || bmp_info.bits_per_pixel==32))
1189
360
              ThrowBMPReaderException(CorruptImageError,CorruptImage,image);
1190
360
          break;
1191
1192
709
        case BI_RGB:
1193
1.08k
        case BI_RLE8:
1194
1.26k
        case BI_RLE4:
1195
1.26k
          break;
1196
1197
4.54k
        case BI_JPEG:
1198
4.54k
          offset = start_position + 14 + bmp_info.size;
1199
4.54k
          if(logging)
1200
0
              (void)LogMagickEvent(CoderEvent,GetMagickModule(),
1201
0
                                  "Seek offset %" MAGICK_OFF_F "d",
1202
0
                                  (magick_off_t) offset);
1203
4.54k
          if((offset < start_position) ||
1204
4.54k
              (SeekBlob(image,offset,SEEK_SET) != (magick_off_t) offset))
1205
4.54k
              ThrowBMPReaderException(CorruptImageError,ImproperImageHeader,image);
1206
4.54k
          {
1207
4.54k
            MonitorHandler previous_handler;
1208
4.54k
            previous_handler = SetMonitorHandler(0);
1209
4.54k
            image = ExtractNestedBlob(&image, image_info, bmp_info.compression, exception);
1210
4.54k
            (void) SetMonitorHandler(previous_handler);
1211
4.54k
            if (exception->severity >= ErrorException)
1212
3.27k
                ThrowBMPReaderException(CoderError,JPEGCompressionNotSupported,image)
1213
4.54k
          }
1214
1.26k
          goto ExitLoop;        /* I need to break a loop. Other BMPs in a chain are ignored. */
1215
1216
2.52k
        case BI_PNG:
1217
2.52k
          offset = start_position + 14 + bmp_info.size;
1218
2.52k
          if(logging)
1219
0
              (void)LogMagickEvent(CoderEvent,GetMagickModule(),
1220
0
                                  "Seek offset %" MAGICK_OFF_F "d",
1221
0
                                  (magick_off_t) offset);
1222
2.52k
          if((offset < start_position) ||
1223
2.52k
              (SeekBlob(image,offset,SEEK_SET) != (magick_off_t) offset))
1224
2.52k
              ThrowBMPReaderException(CorruptImageError,ImproperImageHeader,image);
1225
2.52k
          {
1226
2.52k
            MonitorHandler previous_handler;
1227
2.52k
            previous_handler = SetMonitorHandler(0);
1228
2.52k
            image = ExtractNestedBlob(&image, image_info, bmp_info.compression, exception);
1229
2.52k
            (void) SetMonitorHandler(previous_handler);
1230
2.52k
            if (exception->severity >= ErrorException)
1231
2.52k
                ThrowBMPReaderException(CoderError,PNGCompressionNotSupported,image)
1232
2.52k
          }
1233
0
          goto ExitLoop;        /* I need to break a loop. Other BMPs in a chain are ignored. */
1234
1235
423
        default:
1236
423
          ThrowBMPReaderException(CorruptImageError,UnrecognizedImageCompression,image)
1237
9.28k
        }
1238
1239
1.62k
      if (bmp_info.planes != 1)
1240
24
        ThrowBMPReaderException(CorruptImageError,StaticPlanesValueNotEqualToOne,
1241
1.62k
                                image);
1242
1.60k
      if ((bmp_info.bits_per_pixel != 1) && (bmp_info.bits_per_pixel != 2) && (bmp_info.bits_per_pixel != 4) &&
1243
1.60k
          (bmp_info.bits_per_pixel != 8) && (bmp_info.bits_per_pixel != 16) &&
1244
1.60k
          (bmp_info.bits_per_pixel != 24) && (bmp_info.bits_per_pixel != 32) &&
1245
1.60k
          (bmp_info.bits_per_pixel != 48) && (bmp_info.bits_per_pixel != 64))
1246
1.56k
        ThrowBMPReaderException(CorruptImageError,UnrecognizedBitsPerPixel,image);
1247
1.56k
      if (bmp_info.bits_per_pixel < 16)
1248
794
        {
1249
794
          if (bmp_info.number_colors > (1UL << bmp_info.bits_per_pixel))
1250
768
            ThrowBMPReaderException(CorruptImageError,UnrecognizedNumberOfColors,image);
1251
768
        }
1252
1.53k
      if ((bmp_info.compression == 1) && (bmp_info.bits_per_pixel != 8))
1253
1.53k
        ThrowBMPReaderException(CorruptImageError,UnrecognizedBitsPerPixel,image);
1254
1.53k
      if ((bmp_info.compression == 2) && (bmp_info.bits_per_pixel != 4))
1255
1.52k
        ThrowBMPReaderException(CorruptImageError,UnrecognizedBitsPerPixel,image);
1256
1.52k
      if ((bmp_info.compression == 3) && (bmp_info.bits_per_pixel < 16))
1257
1.52k
        ThrowBMPReaderException(CorruptImageError,UnrecognizedBitsPerPixel,image);
1258
1259
1.52k
      image->columns=bmp_info.width;
1260
1.52k
      image->rows=AbsoluteValue(bmp_info.height);
1261
#if (QuantumDepth == 8)
1262
      image->depth=8;
1263
#else
1264
1.52k
      if(bmp_info.bits_per_pixel==48 || bmp_info.bits_per_pixel==64)
1265
213
          image->depth=16;
1266
1.31k
      else
1267
1.31k
          image->depth=8;
1268
1.52k
#endif
1269
      /*
1270
        Image has alpha channel if alpha mask is specified, or is
1271
        uncompressed and 32-bits per pixel
1272
      */
1273
1.52k
      image->matte=((bmp_info.alpha_mask != 0)
1274
1.52k
                    || ((bmp_info.compression == BI_RGB)
1275
1.38k
                        && (bmp_info.bits_per_pixel == 32)));
1276
1.52k
      if (bmp_info.bits_per_pixel < 16)
1277
765
        {
1278
765
          if (bmp_info.number_colors == 0)
1279
227
            image->colors=1L << bmp_info.bits_per_pixel;
1280
538
          else
1281
538
            image->colors=bmp_info.number_colors;
1282
765
          image->storage_class=PseudoClass;
1283
765
        }
1284
1.52k
      if (image->storage_class == PseudoClass)
1285
765
        {
1286
765
          unsigned int
1287
765
            packet_size;
1288
1289
          /*
1290
            Read BMP raster colormap.
1291
          */
1292
765
          if (logging)
1293
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1294
0
                                  "  Reading colormap of %u colors",image->colors);
1295
765
          if (!AllocateImageColormap(image,image->colors))
1296
0
            ThrowBMPReaderException(ResourceLimitError,MemoryAllocationFailed,
1297
765
                                    image);
1298
765
          bmp_colormap=MagickAllocateResourceLimitedArray(unsigned char *,4,image->colors);
1299
765
          if (bmp_colormap == (unsigned char *) NULL)
1300
0
            ThrowBMPReaderException(ResourceLimitError,MemoryAllocationFailed,
1301
765
                                    image);
1302
765
          if ((bmp_info.size == 12) || (bmp_info.size == 64))
1303
152
            packet_size=3;
1304
613
          else
1305
613
            packet_size=4;
1306
765
          offset=start_position+14+bmp_info.size;
1307
765
          if (logging)
1308
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1309
0
                                  "Seek offset %" MAGICK_OFF_F "d",
1310
0
                                  (magick_off_t) offset);
1311
765
          if ((offset < start_position) ||
1312
765
              (SeekBlob(image,offset,SEEK_SET) != (magick_off_t) offset))
1313
765
            ThrowBMPReaderException(CorruptImageError,ImproperImageHeader,image);
1314
765
          if (ReadBlob(image,(size_t) packet_size*image->colors,(char *) bmp_colormap)
1315
765
              != (size_t) packet_size*image->colors)
1316
629
            ThrowBMPReaderException(CorruptImageError,UnexpectedEndOfFile,image);
1317
629
          p=bmp_colormap;
1318
9.01k
          for (i=0; i < (long) image->colors; i++)
1319
8.38k
            {
1320
8.38k
              image->colormap[i].blue=ScaleCharToQuantum(*p++);
1321
8.38k
              image->colormap[i].green=ScaleCharToQuantum(*p++);
1322
8.38k
              image->colormap[i].red=ScaleCharToQuantum(*p++);
1323
8.38k
              if (packet_size == 4)
1324
4.40k
              p++;
1325
8.38k
            }
1326
629
          MagickFreeResourceLimitedMemory(bmp_colormap);
1327
629
        }
1328
1329
1.39k
      if (image_info->ping && (image_info->subrange != 0))
1330
0
        if (image->scene >= (image_info->subimage+image_info->subrange-1))
1331
0
          break;
1332
1333
1.39k
      if (CheckImagePixelLimits(image, exception) != MagickPass)
1334
1.33k
        ThrowBMPReaderException(ResourceLimitError,ImagePixelLimitExceeded,image);
1335
1336
      /*
1337
        Read image data.
1338
      */
1339
1.33k
      if (logging)
1340
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1341
0
                              "start_position %" MAGICK_OFF_F "d,"
1342
0
                              " bmp_info.offset_bits %" MAGICK_OFF_F "d,"
1343
0
                              " bmp_info.ba_offset %" MAGICK_OFF_F "d" ,
1344
0
                              (magick_off_t) start_position,
1345
0
                              (magick_off_t) bmp_info.offset_bits,
1346
0
                              (magick_off_t) bmp_info.ba_offset);
1347
1.33k
      offset=start_position+bmp_info.offset_bits;
1348
1.33k
      if (logging)
1349
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1350
0
                              "Seek offset %" MAGICK_OFF_F "d",
1351
0
                              (magick_off_t) offset);
1352
1.33k
      if ((offset < start_position) ||
1353
1.33k
          (SeekBlob(image,offset,SEEK_SET) != (magick_off_t) offset))
1354
1.33k
        ThrowBMPReaderException(CorruptImageError,ImproperImageHeader,image);
1355
1.33k
      if (bmp_info.compression == BI_RLE4)
1356
154
        bmp_info.bits_per_pixel<<=1;
1357
1.33k
      if (logging)
1358
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1359
0
                              "image->columns: %lu, bmp_info.bits_per_pixel %u",
1360
0
                              image->columns, bmp_info.bits_per_pixel);
1361
      /*
1362
        Below emulates:
1363
        bytes_per_line=4*((image->columns*bmp_info.bits_per_pixel+31)/32);
1364
      */
1365
1.33k
      bytes_per_line=MagickArraySize(image->columns,bmp_info.bits_per_pixel);
1366
1.33k
      if ((bytes_per_line > 0) && (~((size_t) 0) - bytes_per_line) > 31)
1367
1.33k
        bytes_per_line = MagickArraySize(4,(bytes_per_line+31)/32);
1368
1.33k
      if (bytes_per_line == 0)
1369
1.33k
        ThrowBMPReaderException(CoderError,ArithmeticOverflow,image);
1370
1371
1.33k
      if (logging)
1372
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1373
0
                              "  Bytes per line: %" MAGICK_SIZE_T_F "u",
1374
0
                              (MAGICK_SIZE_T) bytes_per_line);
1375
1376
1.33k
      length=MagickArraySize(bytes_per_line,image->rows);
1377
1.33k
      if (logging)
1378
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1379
0
                              "  Expected total raster length: %" MAGICK_SIZE_T_F "u",
1380
0
                              (MAGICK_SIZE_T) length);
1381
1.33k
      if (length == 0)
1382
1.33k
        ThrowBMPReaderException(CoderError,ArithmeticOverflow,image);
1383
1384
      /*
1385
        Check that file data is reasonable given claims by file header.
1386
        We do this before allocating raster memory to avoid DOS.
1387
      */
1388
1.33k
      if ((bmp_info.compression == BI_RGB) ||
1389
1.33k
          (bmp_info.compression == BI_BITFIELDS) ||
1390
1.33k
          (bmp_info.compression == BI_ALPHABITFIELDS))
1391
877
        {
1392
          /*
1393
            Not compressed.
1394
          */
1395
877
          file_remaining=file_size-TellBlob(image);
1396
877
          if (file_remaining < (magick_off_t) length)
1397
76
            ThrowBMPReaderException(CorruptImageError,InsufficientImageDataInFile,
1398
877
                                    image);
1399
801
        }
1400
459
      else if ((bmp_info.compression == BI_RLE4) ||
1401
459
               (bmp_info.compression == BI_RLE8))
1402
459
        {
1403
          /* RLE Compressed.  Assume a maximum compression ratio. */
1404
459
          file_remaining=file_size-TellBlob(image);
1405
459
          if ((file_remaining <= 0) || (((double) length/file_remaining) > 254.0))
1406
40
            ThrowBMPReaderException(CorruptImageError,InsufficientImageDataInFile,
1407
459
                                    image);
1408
419
        }
1409
1410
1.22k
      if ((image->columns+1UL) < image->columns)
1411
1.22k
        ThrowBMPReaderException(CoderError,ArithmeticOverflow,image);
1412
1.22k
      pixels_size=MagickArraySize(Max(bytes_per_line,(size_t) image->columns+1),
1413
1.22k
                                  image->rows);
1414
1.22k
      if (logging)
1415
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1416
0
                              "  Pixels size %" MAGICK_SIZE_T_F "u",
1417
0
                              (MAGICK_SIZE_T) pixels_size);
1418
1.22k
      if (pixels_size == 0)
1419
1.22k
        ThrowBMPReaderException(CoderError,ArithmeticOverflow,image);
1420
1.22k
      pixels=MagickAllocateResourceLimitedMemory(unsigned char *, pixels_size);
1421
1.22k
      if (pixels == (unsigned char *) NULL)
1422
1.22k
        ThrowBMPReaderException(ResourceLimitError,MemoryAllocationFailed,image);
1423
1.22k
      if ((bmp_info.compression == BI_RGB) ||
1424
1.22k
          (bmp_info.compression == BI_BITFIELDS) ||
1425
1.22k
          (bmp_info.compression == BI_ALPHABITFIELDS))
1426
801
        {
1427
801
          if (logging)
1428
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1429
0
                                  "  Reading pixels (%" MAGICK_SIZE_T_F "u bytes)",
1430
0
                                  (MAGICK_SIZE_T) length);
1431
801
          if (ReadBlob(image,length,(char *) pixels) != (size_t) length)
1432
800
            ThrowBMPReaderException(CorruptImageError,UnexpectedEndOfFile,image);
1433
800
        }
1434
419
      else
1435
419
        {
1436
          /*
1437
            Convert run-length encoded raster pixels.
1438
1439
            DecodeImage() normally decompresses to rows*columns bytes of data.
1440
          */
1441
419
          status=DecodeImage(image,bmp_info.compression,pixels,
1442
419
                             (size_t) image->rows*image->columns);
1443
419
          if (status == MagickFail)
1444
198
            ThrowBMPReaderException(CorruptImageError,UnableToRunlengthDecodeImage,
1445
419
                                    image);
1446
221
        }
1447
      /*
1448
        Initialize image structure.
1449
      */
1450
1.02k
      image->units=PixelsPerCentimeterResolution;
1451
1.02k
      image->x_resolution=bmp_info.x_pixels/100.0;
1452
1.02k
      image->y_resolution=bmp_info.y_pixels/100.0;
1453
1.02k
      (void) memset(&quantum_bits,0,sizeof(PixelPacket));
1454
1.02k
      (void) memset(&shift,0,sizeof(PixelPacket));
1455
      /*
1456
        Convert BMP raster image to pixel packets.
1457
      */
1458
#if 0
1459
      if (bmp_info.compression == BI_RGB)
1460
        {
1461
          bmp_info.alpha_mask=(image->matte ? 0xff000000U : 0U);
1462
          bmp_info.red_mask=0x00ff0000U;
1463
          bmp_info.green_mask=0x0000ff00U;
1464
          bmp_info.blue_mask=0x000000ffU;
1465
          if (bmp_info.bits_per_pixel == 16)
1466
            {
1467
              /* RGB555.   JFO: Please consider whether this is correct ?? I guess RGB 565! */
1468
              bmp_info.red_mask=0x00007c00U;
1469
              bmp_info.green_mask=0x000003e0U;
1470
              bmp_info.blue_mask=0x0000001fU;
1471
            }
1472
        }
1473
#endif
1474
1.02k
      if ((bmp_info.bits_per_pixel == 16) || (bmp_info.bits_per_pixel == 32))
1475
406
        {
1476
406
          register magick_uint32_t
1477
406
            sample;
1478
1479
          /* Use defaults for 40 bytes header and also a reminder of a culture of sloth. */
1480
406
          if(bmp_info.compression == BI_RGB ||
1481
406
             (bmp_info.red_mask==0 && bmp_info.green_mask==0 && bmp_info.blue_mask==0 && bmp_info.alpha_mask==0))
1482
147
            {
1483
147
              if (bmp_info.bits_per_pixel == 16)
1484
57
                {
1485
57
                  if(bmp_info.compression==BI_ALPHABITFIELDS)
1486
7
                  {                                   /* USE ARGB 1555 */
1487
7
                    image->matte = MagickTrue;
1488
7
                    bmp_info.alpha_mask=0x00008000U;
1489
7
                    bmp_info.red_mask=0x00007c00U;
1490
7
                    bmp_info.green_mask=0x000003e0U;
1491
7
                    bmp_info.blue_mask=0x0000001fU;
1492
7
                  }
1493
50
                  else                                /* USE RGB 565 */
1494
50
                  {
1495
50
                    bmp_info.red_mask=0x0000F800U;
1496
50
                    bmp_info.green_mask=0x000007e0U;
1497
50
                    bmp_info.blue_mask=0x0000001fU;
1498
50
                  }
1499
57
                }
1500
147
              if ( bmp_info.bits_per_pixel == 32)
1501
90
                {
1502
90
                  if(bmp_info.compression==BI_RGB || bmp_info.compression==BI_ALPHABITFIELDS)
1503
85
                  {
1504
85
                    image->matte = MagickTrue;
1505
85
                    bmp_info.alpha_mask=0xff000000U;
1506
85
                  }
1507
90
                  bmp_info.red_mask=0x00ff0000U;
1508
90
                  bmp_info.green_mask=0x0000ff00U;
1509
90
                  bmp_info.blue_mask=0x000000ffU;
1510
90
                }
1511
147
            }
1512
1513
          /*
1514
            Get shift and quantum bits info from bitfield masks.
1515
          */
1516
406
          if (bmp_info.red_mask != 0U)
1517
3.53k
            while ((shift.red < 32U) && (((bmp_info.red_mask << shift.red) & 0x80000000U) == 0))
1518
3.23k
              shift.red++;
1519
406
          if (bmp_info.green_mask != 0)
1520
3.63k
            while ((shift.green < 32U) && (((bmp_info.green_mask << shift.green) & 0x80000000U) == 0))
1521
3.33k
              shift.green++;
1522
406
          if (bmp_info.blue_mask != 0)
1523
5.46k
            while ((shift.blue < 32U) && (((bmp_info.blue_mask << shift.blue) & 0x80000000U) == 0))
1524
5.17k
              shift.blue++;
1525
406
          if (bmp_info.alpha_mask != 0)
1526
504
            while ((shift.opacity < 32U) && (((bmp_info.alpha_mask << shift.opacity) & 0x80000000U) == 0))
1527
341
              shift.opacity++;
1528
406
          sample=shift.red;
1529
2.53k
          while ((sample < 32U) && (((bmp_info.red_mask << sample) & 0x80000000U) != 0))
1530
2.13k
            sample++;
1531
406
          quantum_bits.red=(Quantum) (sample-shift.red);
1532
406
          sample=shift.green;
1533
2.74k
          while ((sample < 32U) && (((bmp_info.green_mask << sample) & 0x80000000U) != 0))
1534
2.33k
            sample++;
1535
406
          quantum_bits.green=(Quantum) (sample-shift.green);
1536
406
          sample=shift.blue;
1537
2.76k
          while ((sample < 32U) && (((bmp_info.blue_mask << sample) & 0x80000000U) != 0))
1538
2.35k
            sample++;
1539
406
          quantum_bits.blue=(Quantum) (sample-shift.blue);
1540
406
          sample=shift.opacity;
1541
1.97k
          while ((sample < 32U) && (((bmp_info.alpha_mask << sample) & 0x80000000U) != 0))
1542
1.56k
            sample++;
1543
406
          quantum_bits.opacity=(Quantum) (sample-shift.opacity);
1544
406
        }
1545
1.02k
      switch (bmp_info.bits_per_pixel)
1546
1.02k
        {
1547
76
        case 1:
1548
110
        case 2:
1549
140
        case 4:
1550
140
          {
1551
            /*
1552
              Convert PseudoColor scanline.
1553
            */
1554
6.07k
            for (y=(long) image->rows-1; y >= 0; y--)
1555
5.93k
              {
1556
5.93k
                p=pixels+((size_t)image->rows-y-1)*bytes_per_line;
1557
5.93k
                q=SetImagePixels(image,0,y,image->columns,1);
1558
5.93k
                if (q == (PixelPacket *) NULL)
1559
0
                  break;
1560
5.93k
                if (ImportImagePixelArea(image,IndexQuantum,bmp_info.bits_per_pixel,p,0,0)
1561
5.93k
                    == MagickFail)
1562
0
                  break;
1563
5.93k
                if (!SyncImagePixels(image))
1564
0
                  break;
1565
5.93k
                if (image->previous == (Image *) NULL)
1566
5.93k
                  if (QuantumTick(y,image->rows))
1567
3.00k
                    {
1568
3.00k
                      status=MagickMonitorFormatted((size_t)image->rows-y-1,image->rows,
1569
3.00k
                                                    exception,LoadImageText,
1570
3.00k
                                                    image->filename,
1571
3.00k
                                                    image->columns,image->rows);
1572
3.00k
                      if (status == MagickFalse)
1573
0
                        break;
1574
3.00k
                    }
1575
5.93k
              }
1576
140
            break;
1577
110
          }
1578
240
        case 8:
1579
240
          {
1580
            /*
1581
              Convert PseudoColor scanline.
1582
            */
1583
240
            if ((bmp_info.compression == BI_RLE8) ||
1584
240
                (bmp_info.compression == BI_RLE4))
1585
221
              bytes_per_line=image->columns;
1586
79.9k
            for (y=(long) image->rows-1; y >= 0; y--)
1587
79.7k
              {
1588
79.7k
                p=pixels+((size_t)image->rows-y-1)*bytes_per_line;
1589
79.7k
                q=SetImagePixels(image,0,y,image->columns,1);
1590
79.7k
                if (q == (PixelPacket *) NULL)
1591
0
                  break;
1592
79.7k
                if (ImportImagePixelArea(image,IndexQuantum,bmp_info.bits_per_pixel,p,0,0)
1593
79.7k
                    == MagickFail)
1594
0
                  break;
1595
79.7k
                if (!SyncImagePixels(image))
1596
0
                  break;
1597
79.7k
                if (image->previous == (Image *) NULL)
1598
79.7k
                  if (QuantumTick(y,image->rows))
1599
16.1k
                    {
1600
16.1k
                      status=MagickMonitorFormatted((size_t)image->rows-y-1,image->rows,
1601
16.1k
                                                    exception,LoadImageText,
1602
16.1k
                                                    image->filename,
1603
16.1k
                                                    image->columns,image->rows);
1604
16.1k
                      if (status == MagickFalse)
1605
0
                        break;
1606
16.1k
                    }
1607
79.7k
              }
1608
240
            break;
1609
110
          }
1610
215
        case 16:
1611
215
          {
1612
215
            magick_uint32_t
1613
215
              pixel;
1614
1615
            /*
1616
              Convert bitfield encoded 16-bit PseudoColor scanline.
1617
            */
1618
215
            if (bmp_info.compression != BI_RGB &&
1619
215
                bmp_info.compression != BI_BITFIELDS &&
1620
215
                bmp_info.compression != BI_ALPHABITFIELDS)
1621
0
              ThrowBMPReaderException(CorruptImageError,UnrecognizedImageCompression,image)
1622
215
                bytes_per_line=2*((size_t)image->columns+image->columns%2);
1623
215
            image->storage_class=DirectClass;
1624
6.63k
            for (y=(long) image->rows-1; y >= 0; y--)
1625
6.42k
              {
1626
6.42k
                p=pixels+((size_t)image->rows-y-1)*bytes_per_line;
1627
6.42k
                q=SetImagePixels(image,0,y,image->columns,1);
1628
6.42k
                if (q == (PixelPacket *) NULL)
1629
0
                  break;
1630
146k
                for (x=0; x < (long) image->columns; x++)
1631
140k
                  {
1632
#ifdef WORDS_BIGENDIAN
1633
                    pixel=(*p++);
1634
                    pixel|=(*p++) << 8;
1635
#else
1636
140k
                    pixel = *(magick_uint16_t*)p;
1637
140k
                    p += 2;
1638
140k
#endif
1639
140k
                    red=((pixel & bmp_info.red_mask) << shift.red) >> 16;
1640
140k
                    if (quantum_bits.red <= 8)          /* TODO: this is ugly, but better than nothing. Should be reworked. */
1641
139k
                      red|=(red >> 8);
1642
140k
                    green=((pixel & bmp_info.green_mask) << shift.green) >> 16;
1643
140k
                    if (quantum_bits.green <= 8)
1644
139k
                      green|=(green >> 8);
1645
140k
                    blue=((pixel & bmp_info.blue_mask) << shift.blue) >> 16;
1646
140k
                    if (quantum_bits.blue <= 8)
1647
139k
                      blue|=(blue >> 8);
1648
140k
                    if (image->matte != MagickFalse)
1649
518
                      {
1650
518
                        opacity=((pixel & bmp_info.alpha_mask) << shift.opacity) >> 16;
1651
518
                        if (quantum_bits.opacity <= 8)
1652
260
                          opacity|=(opacity >> 8);
1653
518
                        q->opacity=MaxRGB-ScaleShortToQuantum(opacity);
1654
518
                      }
1655
140k
                    q->red=ScaleShortToQuantum(red);
1656
140k
                    q->green=ScaleShortToQuantum(green);
1657
140k
                    q->blue=ScaleShortToQuantum(blue);
1658
140k
                    q->opacity=OpaqueOpacity;
1659
140k
                    q++;
1660
140k
                  }
1661
6.42k
                if (!SyncImagePixels(image))
1662
0
                  break;
1663
6.42k
                if (image->previous == (Image *) NULL)
1664
6.42k
                  if (QuantumTick(y,image->rows))
1665
2.94k
                    {
1666
2.94k
                      status=MagickMonitorFormatted((size_t)image->rows-y-1,image->rows,
1667
2.94k
                                                    exception,LoadImageText,
1668
2.94k
                                                    image->filename,
1669
2.94k
                                                    image->columns,image->rows);
1670
2.94k
                      if (status == MagickFalse)
1671
0
                        break;
1672
2.94k
                    }
1673
6.42k
              }
1674
215
            break;
1675
215
          }
1676
37
        case 24:
1677
37
          {
1678
            /*
1679
              Convert DirectColor scanline.
1680
            */
1681
37
            bytes_per_line=4*(((size_t)image->columns*24+31)/32);
1682
5.09k
            for (y=(long) image->rows-1; y >= 0; y--)
1683
5.05k
              {
1684
5.05k
                p=pixels+((size_t)image->rows-y-1)*bytes_per_line;
1685
5.05k
                q=SetImagePixels(image,0,y,image->columns,1);
1686
5.05k
                if (q == (PixelPacket *) NULL)
1687
0
                  break;
1688
10.3k
                for (x=0; x < (long) image->columns; x++)
1689
5.25k
                  {
1690
5.25k
                    q->blue=ScaleCharToQuantum(*p++);
1691
5.25k
                    q->green=ScaleCharToQuantum(*p++);
1692
5.25k
                    q->red=ScaleCharToQuantum(*p++);
1693
5.25k
                    q->opacity=OpaqueOpacity;
1694
5.25k
                    q++;
1695
5.25k
                  }
1696
5.05k
                if (!SyncImagePixels(image))
1697
0
                  break;
1698
5.05k
                if (image->previous == (Image *) NULL)
1699
5.05k
                  if (QuantumTick(y,image->rows))
1700
2.25k
                    {
1701
2.25k
                      status=MagickMonitorFormatted((size_t)image->rows-y-1,image->rows,
1702
2.25k
                                                    exception,LoadImageText,
1703
2.25k
                                                    image->filename,
1704
2.25k
                                                    image->columns,image->rows);
1705
2.25k
                      if (status == MagickFalse)
1706
0
                        break;
1707
2.25k
                    }
1708
5.05k
              }
1709
37
            break;
1710
215
          }
1711
191
        case 32:
1712
191
          {
1713
             /* char ZeroOpacity = 1; */
1714
            /*
1715
              Convert bitfield encoded DirectColor scanline.
1716
            */
1717
191
            if(bmp_info.compression != BI_RGB &&
1718
191
               bmp_info.compression != BI_BITFIELDS &&
1719
191
               bmp_info.compression != BI_ALPHABITFIELDS)
1720
0
              ThrowBMPReaderException(CorruptImageError,UnrecognizedImageCompression,image)
1721
191
                bytes_per_line=4*((size_t) image->columns);
1722
5.65k
            for (y=(long) image->rows-1; y >= 0; y--)
1723
5.46k
              {
1724
5.46k
                magick_uint32_t
1725
5.46k
                  pixel;
1726
1727
5.46k
                p=pixels+((size_t) image->rows-y-1)*bytes_per_line;
1728
5.46k
                q=SetImagePixels(image,0,y,image->columns,1);
1729
5.46k
                if (q == (PixelPacket *) NULL)
1730
0
                  break;
1731
11.3k
                for (x=0; x < (long) image->columns; x++)
1732
5.88k
                  {
1733
#ifdef WORDS_BIGENDIAN
1734
                    pixel =((magick_uint32_t) *p++);
1735
                    pixel|=((magick_uint32_t) *p++ << 8);
1736
                    pixel|=((magick_uint32_t) *p++ << 16);
1737
                    pixel|=((magick_uint32_t) *p++ << 24);
1738
#else
1739
5.88k
                    pixel = *(magick_uint32_t*)p;
1740
5.88k
                    p += 4;
1741
5.88k
#endif
1742
5.88k
                    red=((pixel & bmp_info.red_mask) << shift.red) >> 16;
1743
5.88k
                    if (quantum_bits.red <= 8)
1744
5.65k
                      red|=(red >> 8);
1745
5.88k
                    green=((pixel & bmp_info.green_mask) << shift.green) >> 16;
1746
5.88k
                    if (quantum_bits.green <= 8)
1747
5.64k
                      green|=(green >> 8);
1748
5.88k
                    blue=((pixel & bmp_info.blue_mask) << shift.blue) >> 16;
1749
5.88k
                    if (quantum_bits.blue <= 8)
1750
5.62k
                      blue|=(blue >> 8);
1751
5.88k
                    if (image->matte != MagickFalse)
1752
5.39k
                      {
1753
5.39k
                        opacity=((pixel & bmp_info.alpha_mask) << shift.opacity) >> 16;
1754
                        /* if(opacity!=0) ZeroOpacity=0; */
1755
5.39k
                        if (quantum_bits.opacity <= 8)
1756
5.18k
                          opacity|=(opacity >> 8);
1757
5.39k
                        q->opacity=MaxRGB-ScaleShortToQuantum(opacity);
1758
5.39k
                      }
1759
488
                    else
1760
488
                      {
1761
488
                        q->opacity = OpaqueOpacity;
1762
488
                      }
1763
5.88k
                    q->red=ScaleShortToQuantum(red);
1764
5.88k
                    q->green=ScaleShortToQuantum(green);
1765
5.88k
                    q->blue=ScaleShortToQuantum(blue);
1766
5.88k
                    q++;
1767
5.88k
                  }
1768
5.46k
                if (!SyncImagePixels(image))
1769
0
                  break;
1770
5.46k
                if (image->previous == (Image *) NULL)
1771
5.46k
                  if (QuantumTick(y,image->rows))
1772
2.65k
                    {
1773
2.65k
                      status=MagickMonitorFormatted((size_t)image->rows-y-1,image->rows,
1774
2.65k
                                                    exception,LoadImageText,
1775
2.65k
                                                    image->filename,
1776
2.65k
                                                    image->columns,image->rows);
1777
2.65k
                      if (status == MagickFalse)
1778
0
                        break;
1779
2.65k
                    }
1780
5.46k
              }
1781
            /* if(ZeroOpacity) image->matte = MagickFalse; */
1782
191
            break;
1783
191
          }
1784
1785
97
        case 48:
1786
97
          {
1787
97
            magick_uint16_t val_16;
1788
            /*
1789
              Convert DirectColor scanline.
1790
            */
1791
5.12k
            for(y=(long) image->rows-1; y >= 0; y--)
1792
5.03k
              {
1793
5.03k
                p = pixels+((size_t) image->rows-y-1)*bytes_per_line;
1794
5.03k
                q = SetImagePixels(image,0,y,image->columns,1);
1795
5.03k
                if(q == (PixelPacket *) NULL)
1796
0
                  break;
1797
11.6k
                for(x=0; x < (long) image->columns; x++)
1798
6.57k
                  {
1799
6.57k
                    LD_UINT16_LSB(val_16,p);
1800
6.57k
                    q->blue = MS_VAL16_TO_QUANTUM(val_16);
1801
6.57k
                    LD_UINT16_LSB(val_16,p);
1802
6.57k
                    q->green = MS_VAL16_TO_QUANTUM(val_16);
1803
6.57k
                    LD_UINT16_LSB(val_16,p);
1804
6.57k
                    q->red = MS_VAL16_TO_QUANTUM(val_16);
1805
6.57k
                    q->opacity = OpaqueOpacity;
1806
6.57k
                    q++;
1807
6.57k
                  }
1808
5.03k
                if(!SyncImagePixels(image))
1809
0
                  break;
1810
5.03k
                if(image->previous == (Image *) NULL)
1811
5.03k
                  if(QuantumTick(y,image->rows))
1812
2.29k
                    {
1813
2.29k
                      status=MagickMonitorFormatted((size_t)image->rows-y-1,image->rows,
1814
2.29k
                                                    exception,LoadImageText,
1815
2.29k
                                                    image->filename,
1816
2.29k
                                                    image->columns,image->rows);
1817
2.29k
                      if(status == MagickFalse)
1818
0
                        break;
1819
2.29k
                    }
1820
5.03k
              }
1821
97
            break;
1822
191
          }
1823
1824
101
        case 64:
1825
101
          {
1826
101
            magick_uint16_t val_16;
1827
            /*
1828
              Convert DirectColor scanline.
1829
            */
1830
5.87k
            for(y=(long) image->rows-1; y >= 0; y--)
1831
5.77k
              {
1832
5.77k
                p = pixels+((size_t) image->rows-y-1)*bytes_per_line;
1833
5.77k
                q = SetImagePixels(image,0,y,image->columns,1);
1834
5.77k
                if(q == (PixelPacket *) NULL)
1835
0
                  break;
1836
17.8k
                for(x=0; x < (long) image->columns; x++)
1837
12.0k
                  {
1838
12.0k
                    LD_UINT16_LSB(val_16,p);
1839
12.0k
                    q->blue = MS_VAL16_TO_QUANTUM(val_16);
1840
12.0k
                    LD_UINT16_LSB(val_16,p);
1841
12.0k
                    q->green = MS_VAL16_TO_QUANTUM(val_16);
1842
12.0k
                    LD_UINT16_LSB(val_16,p);
1843
12.0k
                    q->red = MS_VAL16_TO_QUANTUM(val_16);
1844
                    /* FIXME: support alpha */
1845
12.0k
                    q->opacity = OpaqueOpacity;
1846
12.0k
                    p+=2;
1847
12.0k
                    q++;
1848
12.0k
                  }
1849
5.77k
                if(!SyncImagePixels(image))
1850
0
                  break;
1851
5.77k
                if(image->previous == (Image *) NULL)
1852
5.77k
                  if(QuantumTick(y,image->rows))
1853
2.35k
                    {
1854
2.35k
                      status=MagickMonitorFormatted((size_t) image->rows-y-1,image->rows,
1855
2.35k
                                                    exception,LoadImageText,
1856
2.35k
                                                    image->filename,
1857
2.35k
                                                    image->columns,image->rows);
1858
2.35k
                      if(status == MagickFalse)
1859
0
                        break;
1860
2.35k
                    }
1861
5.77k
              }
1862
101
            break;
1863
191
          }
1864
0
        default:
1865
0
          ThrowBMPReaderException(CorruptImageError,ImproperImageHeader,image);
1866
1.02k
        }
1867
1.02k
      MagickFreeResourceLimitedMemory(pixels);
1868
1.02k
      if (EOFBlob(image))
1869
24
        {
1870
24
          ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,
1871
24
                         image->filename);
1872
24
          break;
1873
24
        }
1874
997
      if (bmp_info.height < 0)
1875
244
        {
1876
244
          Image
1877
244
            *flipped_image;
1878
1879
          /*
1880
            Correct image orientation.
1881
          */
1882
244
          flipped_image=FlipImage(image,exception);
1883
244
          if (flipped_image == (Image *) NULL)
1884
0
            {
1885
0
              DestroyImageList(image);
1886
0
              return((Image *) NULL);
1887
0
            }
1888
244
          DestroyBlob(flipped_image);
1889
244
          flipped_image->blob=ReferenceBlob(image->blob);
1890
244
          ReplaceImageInList(&image,flipped_image);
1891
244
        }
1892
997
      StopTimer(&image->timer);
1893
      /*
1894
        Proceed to next image.
1895
      */
1896
997
      if (image_info->subrange != 0)
1897
997
        if (image->scene >= (image_info->subimage+image_info->subrange-1))
1898
997
          break;
1899
0
      *magick='\0';
1900
0
      file_remaining=file_size-TellBlob(image);
1901
0
      if (file_remaining == 0)
1902
0
        break;
1903
0
      offset=bmp_info.ba_offset;
1904
0
      if (logging)
1905
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1906
0
                              "Seek offset %" MAGICK_OFF_F "d",
1907
0
                              (magick_off_t) offset);
1908
0
      if (offset > 0)
1909
0
        if ((offset < TellBlob(image)) ||
1910
0
            (SeekBlob(image,offset,SEEK_SET) != (magick_off_t) offset))
1911
0
          ThrowBMPReaderException(CorruptImageError,ImproperImageHeader,image);
1912
0
      if (ReadBlob(image,2,(char *) magick) != (size_t) 2)
1913
0
        break;
1914
0
      if (IsBMP(magick,2))
1915
0
        {
1916
          /*
1917
            Acquire next image structure.
1918
          */
1919
0
          AllocateNextImage(image_info,image);
1920
0
          if (image->next == (Image *) NULL)
1921
0
            {
1922
0
              DestroyImageList(image);
1923
0
              return((Image *) NULL);
1924
0
            }
1925
0
          image=SyncNextImageInList(image);
1926
0
          status=MagickMonitorFormatted(TellBlob(image),GetBlobSize(image),
1927
0
                                        exception,LoadImagesText,
1928
0
                                        image->filename);
1929
0
          if (status == MagickFalse)
1930
0
            break;
1931
0
        }
1932
0
    } while (IsBMP(magick,2));
1933
2.28k
ExitLoop:
1934
1935
2.28k
  {
1936
2.28k
    Image *p;
1937
2.28k
    long scene=0;
1938
1939
    /*
1940
      Rewind list, removing any empty images while rewinding.
1941
    */
1942
2.28k
    p=image;
1943
2.28k
    image=NULL;
1944
4.57k
    while (p != (Image *)NULL)
1945
2.28k
      {
1946
2.28k
        Image *tmp=p;
1947
2.28k
        if ((p->rows == 0) || (p->columns == 0)) {
1948
0
          p=p->previous;
1949
0
          DeleteImageFromList(&tmp);
1950
2.28k
        } else {
1951
2.28k
          image=p;
1952
2.28k
          p=p->previous;
1953
2.28k
        }
1954
2.28k
      }
1955
1956
    /*
1957
      Fix scene numbers
1958
    */
1959
4.57k
    for (p=image; p != (Image *) NULL; p=p->next)
1960
2.28k
      p->scene=scene++;
1961
2.28k
  }
1962
1963
/*
1964
  while (image->previous != (Image *) NULL)
1965
    image=image->previous;
1966
*/
1967
2.28k
  CloseBlob(image);
1968
#if 0
1969
  if (logging)
1970
    {
1971
      const size_t list_length = GetImageListLength(image);
1972
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1973
                            "%lu image%s in list", list_length, list_length > 1 ? "s" : "");
1974
    }
1975
#endif
1976
1977
2.28k
  if (logging)
1978
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),"return");
1979
2.28k
  return(image);
1980
14.0k
}
1981

1982
/*
1983
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1984
%                                                                             %
1985
%                                                                             %
1986
%                                                                             %
1987
%   R e g i s t e r B M P I m a g e                                           %
1988
%                                                                             %
1989
%                                                                             %
1990
%                                                                             %
1991
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1992
%
1993
%  Method RegisterBMPImage adds attributes for the BMP image format to
1994
%  the list of supported formats.  The attributes include the image format
1995
%  tag, a method to read and/or write the format, whether the format
1996
%  supports the saving of more than one frame to the same file or blob,
1997
%  whether the format supports native in-memory I/O, and a brief
1998
%  description of the format.
1999
%
2000
%  The format of the RegisterBMPImage method is:
2001
%
2002
%      RegisterBMPImage(void)
2003
%
2004
*/
2005
ModuleExport void RegisterBMPImage(void)
2006
5
{
2007
5
  MagickInfo
2008
5
    *entry;
2009
2010
5
  entry=SetMagickInfo("BMP");
2011
5
  entry->decoder=(DecoderHandler) ReadBMPImage;
2012
5
  entry->encoder=(EncoderHandler) WriteBMPImage;
2013
5
  entry->magick=(MagickHandler) IsBMP;
2014
5
  entry->description="Microsoft Windows bitmap image";
2015
5
  entry->module="BMP";
2016
5
  entry->adjoin=MagickFalse;
2017
5
  entry->seekable_stream=MagickTrue;
2018
5
  entry->coder_class=PrimaryCoderClass;
2019
5
  (void) RegisterMagickInfo(entry);
2020
2021
5
  entry=SetMagickInfo("BMP2");
2022
5
  entry->encoder=(EncoderHandler) WriteBMPImage;
2023
5
  entry->magick=(MagickHandler) IsBMP;
2024
5
  entry->description="Microsoft Windows bitmap image v2";
2025
5
  entry->module="BMP";
2026
5
  entry->adjoin=MagickFalse;
2027
5
  entry->coder_class=PrimaryCoderClass;
2028
5
  entry->seekable_stream=MagickTrue;
2029
5
  (void) RegisterMagickInfo(entry);
2030
2031
5
  entry=SetMagickInfo("BMP3");
2032
5
  entry->encoder=(EncoderHandler) WriteBMPImage;
2033
5
  entry->magick=(MagickHandler) IsBMP;
2034
5
  entry->description="Microsoft Windows bitmap image v3";
2035
5
  entry->module="BMP";
2036
5
  entry->adjoin=MagickFalse;
2037
5
  entry->seekable_stream=MagickTrue;
2038
5
  entry->coder_class=PrimaryCoderClass;
2039
5
  (void) RegisterMagickInfo(entry);
2040
5
}
2041

2042
/*
2043
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2044
%                                                                             %
2045
%                                                                             %
2046
%                                                                             %
2047
%   U n r e g i s t e r B M P I m a g e                                       %
2048
%                                                                             %
2049
%                                                                             %
2050
%                                                                             %
2051
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2052
%
2053
%  Method UnregisterBMPImage removes format registrations made by the
2054
%  BMP module from the list of supported formats.
2055
%
2056
%  The format of the UnregisterBMPImage method is:
2057
%
2058
%      UnregisterBMPImage(void)
2059
%
2060
*/
2061
ModuleExport void UnregisterBMPImage(void)
2062
0
{
2063
0
  (void) UnregisterMagickInfo("BMP");
2064
0
  (void) UnregisterMagickInfo("BMP2");
2065
0
  (void) UnregisterMagickInfo("BMP3");
2066
0
}
2067
2068
2069
typedef struct
2070
{
2071
    const char FormatName[5];
2072
    const char FormatNameDDot[6];
2073
    const char Desc[24];
2074
} TForeignFormatDesc;
2075
2076
static const TForeignFormatDesc StoreDescJPG = {"JPEG", "JPEG:", "  Creating jpeg_image."};
2077
static const TForeignFormatDesc StoreDescPNG = {"PNG", "PNG:", "  Creating png_image."};
2078
2079
2080
static int StoreAlienBlob(Image * image, const ImageInfo * image_info, const TForeignFormatDesc *pFormatDesc)
2081
0
{
2082
0
ImageInfo *jpeg_image_info;
2083
0
Image *jpeg_image;
2084
0
void *Data;
2085
0
size_t DataSize = 0;
2086
2087
0
  jpeg_image_info = (ImageInfo *)CloneImageInfo(image_info);
2088
0
  if(jpeg_image_info == (ImageInfo *) NULL)
2089
0
      ThrowWriterException(ResourceLimitError,MemoryAllocationFailed, image);
2090
0
  if(image->logging)
2091
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(), "%s", pFormatDesc->Desc);
2092
2093
0
  jpeg_image = CloneImage(image,0,0,MagickTrue,&image->exception);
2094
2095
0
  (void)strlcpy(jpeg_image_info->magick, pFormatDesc->FormatName, MaxTextExtent);
2096
0
  (void)strlcpy(jpeg_image_info->filename,"JPEG:",MaxTextExtent);
2097
0
  (void)strlcpy(jpeg_image->magick, pFormatDesc->FormatName, MaxTextExtent);
2098
0
  (void)strlcpy(jpeg_image->filename, pFormatDesc->FormatNameDDot, MaxTextExtent);
2099
2100
0
  Data = ImageToBlob(jpeg_image_info,jpeg_image,&DataSize,&image->exception);
2101
0
  if(Data!=NULL)
2102
0
  {
2103
0
    WriteBlob(image,DataSize,Data);
2104
0
    MagickFreeMemory(Data);
2105
0
  }
2106
2107
      /* Destroy JPEG image and image_info */
2108
0
  DestroyImage(jpeg_image);
2109
0
  DestroyImageInfo(jpeg_image_info);
2110
2111
0
return 0;
2112
0
}
2113
2114

2115
/*
2116
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2117
%                                                                             %
2118
%                                                                             %
2119
%                                                                             %
2120
%   W r i t e B M P I m a g e                                                 %
2121
%                                                                             %
2122
%                                                                             %
2123
%                                                                             %
2124
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2125
%
2126
%  Method WriteBMPImage writes an image in Microsoft Windows bitmap encoded
2127
%  image format, version 3 for Windows or (if the image has a matte channel)
2128
%  version 4.
2129
%
2130
%  The format of the WriteBMPImage method is:
2131
%
2132
%      unsigned int WriteBMPImage(const ImageInfo *image_info,Image *image)
2133
%
2134
%  A description of each parameter follows.
2135
%
2136
%    o status: Method WriteBMPImage return MagickTrue if the image is written.
2137
%      MagickFalse is returned is there is a memory shortage or if the image file
2138
%      fails to write.
2139
%
2140
%    o image_info: Specifies a pointer to a ImageInfo structure.
2141
%
2142
%    o image:  A pointer to an Image structure.
2143
%
2144
%
2145
*/
2146
static unsigned int WriteBMPImage(const ImageInfo *image_info,Image *image)
2147
870
{
2148
870
  BMPInfo
2149
870
    bmp_info;
2150
2151
870
  int
2152
870
    logging;
2153
2154
870
  unsigned long
2155
870
    y;
2156
2157
870
  register const PixelPacket
2158
870
    *p;
2159
2160
870
  register unsigned long
2161
870
    i,
2162
870
    x;
2163
2164
870
  register unsigned char
2165
870
    *q;
2166
2167
870
  unsigned char
2168
870
    *bmp_data,
2169
870
    *pixels;
2170
2171
870
  size_t
2172
870
    bytes_per_line,
2173
870
    image_size;
2174
2175
870
  MagickBool
2176
870
    adjoin,
2177
870
    have_color_info;
2178
2179
870
  MagickPassFail
2180
870
    status;
2181
2182
870
  unsigned long
2183
870
    scene,
2184
870
    type;
2185
2186
  /*   const unsigned char */
2187
  /*     *color_profile=0; */
2188
2189
870
  size_t
2190
870
    color_profile_length=0;
2191
2192
870
  size_t
2193
870
    image_list_length;
2194
2195
  /*
2196
    Open output image file.
2197
  */
2198
870
  assert(image_info != (const ImageInfo *) NULL);
2199
870
  assert(image_info->signature == MagickSignature);
2200
870
  assert(image != (Image *) NULL);
2201
870
  assert(image->signature == MagickSignature);
2202
870
  image_list_length=GetImageListLength(image);
2203
870
  logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter");
2204
870
  if (logging)
2205
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2206
0
                          "%" MAGICK_SIZE_T_F "u image frames in list",
2207
0
                          (MAGICK_SIZE_T) image_list_length);
2208
870
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
2209
870
  if (status == MagickFail)
2210
870
    ThrowWriterException(FileOpenError,UnableToOpenFile,image);
2211
870
  type=4;
2212
870
  if (LocaleCompare(image_info->magick,"BMP2") == 0)
2213
0
    type=2;
2214
870
  else
2215
870
    if (LocaleCompare(image_info->magick,"BMP3") == 0)
2216
0
      type=3;
2217
870
  scene=0;
2218
870
  adjoin=image_info->adjoin;
2219
2220
  /*
2221
    Retrieve color profile from Image (if any)
2222
    FIXME: is color profile support writing not properly implemented?
2223
  */
2224
  /* color_profile= */ (void) GetImageProfile(image,"ICM",&color_profile_length);
2225
2226
870
  do
2227
870
    {
2228
      /*
2229
        Initialize BMP raster file header.
2230
      */
2231
870
      if (logging)
2232
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2233
0
                              "Original: Scene %lu, storage_class %s, colors %u",
2234
0
                              scene,
2235
0
                              ClassTypeToString(image->storage_class),
2236
0
                              image->colors);
2237
870
      (void) TransformColorspace(image,RGBColorspace);
2238
870
      (void) memset(&bmp_info,0,sizeof(BMPInfo));
2239
870
      bmp_info.file_size=14+12;
2240
870
      if (type > 2)
2241
870
        bmp_info.file_size+=28;
2242
870
      bmp_info.offset_bits=(magick_uint32_t) bmp_info.file_size;
2243
870
      bmp_info.compression=BI_RGB;
2244
870
      if ((image->storage_class != DirectClass) && (image->colors > 256))
2245
0
        (void) SetImageType(image,TrueColorType);
2246
2247
870
      if(type>2 && AccessDefinition(image_info,"bmp","allow-jpeg"))
2248
0
        {
2249
0
          image->compression = JPEGCompression;
2250
0
          bmp_info.number_colors = 0;
2251
0
          bmp_info.bits_per_pixel = 0;
2252
0
          bmp_info.compression = BI_JPEG;
2253
0
        }
2254
870
      else if(type>2 && AccessDefinition(image_info,"bmp","allow-png"))
2255
0
        {
2256
0
          image->compression = ZipCompression;
2257
0
          bmp_info.number_colors = 0;
2258
0
          bmp_info.bits_per_pixel = 0;
2259
0
          bmp_info.compression = BI_PNG;
2260
0
        }
2261
870
      else
2262
870
      {
2263
870
        if(image->storage_class != DirectClass)
2264
325
        {
2265
          /*
2266
            Colormapped BMP raster.
2267
          */
2268
325
          bmp_info.bits_per_pixel=8;
2269
325
          if (image->colors <= 2)
2270
123
            bmp_info.bits_per_pixel=1;
2271
202
          else if (image->colors <= 16)
2272
102
            bmp_info.bits_per_pixel=4;
2273
100
          else if (image->colors <= 256)
2274
100
            bmp_info.bits_per_pixel=8;
2275
325
          bmp_info.number_colors=1 << bmp_info.bits_per_pixel;
2276
325
          if (image->matte)
2277
14
            (void) SetImageType(image,TrueColorMatteType);
2278
311
          else
2279
311
            if (bmp_info.number_colors < image->colors)
2280
0
              (void) SetImageType(image,TrueColorType);
2281
311
            else
2282
311
              {
2283
311
                bmp_info.file_size+=3U*(((size_t)1U) << bmp_info.bits_per_pixel);
2284
311
                bmp_info.offset_bits+=3U*(1U << bmp_info.bits_per_pixel);
2285
311
                if (type > 2)
2286
311
                  {
2287
311
                    bmp_info.file_size+=((size_t)1U << bmp_info.bits_per_pixel);
2288
311
                    bmp_info.offset_bits+=(1U << bmp_info.bits_per_pixel);
2289
311
                  }
2290
311
              }
2291
325
        }
2292
           /* Note: Image class could be changed in a code above. */
2293
870
        if (image->storage_class==DirectClass)
2294
559
        {
2295
          /*
2296
            Full color BMP raster.
2297
          */
2298
559
          bmp_info.number_colors=0;
2299
559
          bmp_info.bits_per_pixel=((type > 3) && image->matte) ? 32 : 24;
2300
559
          bmp_info.compression=
2301
559
            (type > 3) && image->matte ?  BI_BITFIELDS : BI_RGB;
2302
559
        }
2303
870
      }
2304
2305
870
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2306
870
                            "Final: Scene %lu, storage_class %s, colors %u",
2307
870
                            scene,
2308
870
                            ClassTypeToString(image->storage_class),
2309
870
                            image->colors);
2310
870
      if(bmp_info.compression==BI_JPEG || bmp_info.compression==BI_PNG)
2311
0
      {
2312
0
        bytes_per_line = 0;
2313
0
        image_size = 0;
2314
0
        have_color_info = 0;
2315
0
      }
2316
870
      else
2317
870
      {
2318
        /*
2319
          Below emulates:
2320
          bytes_per_line=4*((image->columns*bmp_info.bits_per_pixel+31)/32);
2321
        */
2322
870
        bytes_per_line=MagickArraySize(image->columns,bmp_info.bits_per_pixel);
2323
870
        if ((bytes_per_line > 0) && (~((size_t) 0) - bytes_per_line) > 31)
2324
870
          bytes_per_line = MagickArraySize(4,(bytes_per_line+31)/32);
2325
870
        if (bytes_per_line==0)
2326
870
          ThrowWriterException(CoderError,ArithmeticOverflow,image);
2327
870
        image_size=MagickArraySize(bytes_per_line,image->rows);
2328
870
        if ((image_size == 0) || ((image_size & 0xffffffff) != image_size))
2329
870
          ThrowWriterException(CoderError,ArithmeticOverflow,image);
2330
870
        have_color_info=(int) ((image->rendering_intent != UndefinedIntent) ||
2331
870
                             (color_profile_length != 0) || (image->gamma != 0.0));
2332
870
      }
2333
870
      bmp_info.ba_offset=0;
2334
870
      if (type == 2)
2335
0
        bmp_info.size=12;
2336
870
      else
2337
870
        if ((type == 3) || (!image->matte && !have_color_info))
2338
743
          {
2339
743
            type=3;
2340
743
            bmp_info.size=40;
2341
743
          }
2342
127
        else
2343
127
          {
2344
127
            int
2345
127
              extra_size;
2346
2347
127
            bmp_info.size=108;
2348
127
            extra_size=68;
2349
127
            if ((image->rendering_intent != UndefinedIntent) ||
2350
127
                (color_profile_length != 0))
2351
4
              {
2352
4
                bmp_info.size=124;
2353
4
                extra_size+=16;
2354
4
              }
2355
127
            bmp_info.file_size+=extra_size;
2356
127
            bmp_info.offset_bits+=extra_size;
2357
127
          }
2358
      /*
2359
        Verify and enforce that image dimensions do not exceed limit
2360
        imposed by file format.
2361
      */
2362
870
      if (type == 2)
2363
0
        {
2364
0
          bmp_info.width=(magick_int16_t) image->columns;
2365
0
          bmp_info.height=(magick_int16_t) image->rows;
2366
0
        }
2367
870
      else
2368
870
        {
2369
870
          bmp_info.width=(magick_int32_t) image->columns;
2370
870
          bmp_info.height=(magick_int32_t) image->rows;
2371
870
        }
2372
870
      if (((unsigned long) bmp_info.width != image->columns) ||
2373
870
          ((unsigned long) bmp_info.height != image->rows))
2374
0
        {
2375
0
          ThrowWriterException(CoderError,ImageColumnOrRowSizeIsNotSupported,image);
2376
0
        }
2377
2378
870
      bmp_info.planes=1;
2379
870
      bmp_info.image_size=image_size;
2380
870
      bmp_info.file_size+=bmp_info.image_size;
2381
870
      bmp_info.x_pixels=75*39;
2382
870
      bmp_info.y_pixels=75*39;
2383
870
      if (image->units == PixelsPerInchResolution)
2384
0
        {
2385
0
          bmp_info.x_pixels=(unsigned long) (100.0*image->x_resolution/2.54);
2386
0
          bmp_info.y_pixels=(unsigned long) (100.0*image->y_resolution/2.54);
2387
0
        }
2388
870
      if (image->units == PixelsPerCentimeterResolution)
2389
822
        {
2390
822
          bmp_info.x_pixels=(unsigned long) (100.0*image->x_resolution);
2391
822
          bmp_info.y_pixels=(unsigned long) (100.0*image->y_resolution);
2392
822
        }
2393
870
      bmp_info.colors_important=bmp_info.number_colors;
2394
      /*
2395
        Convert MIFF to BMP raster pixels.
2396
      */
2397
870
      if(bmp_info.compression==BI_JPEG || bmp_info.compression==BI_PNG)
2398
0
        pixels=NULL;
2399
870
      else
2400
870
      {
2401
870
        pixels=MagickAllocateResourceLimitedMemory(unsigned char *,bmp_info.image_size);
2402
870
        if (pixels == (unsigned char *) NULL)
2403
870
          ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image);
2404
870
      }
2405
870
      switch (bmp_info.bits_per_pixel)
2406
870
        {
2407
120
        case 1:
2408
120
          {
2409
120
            ExportPixelAreaOptions
2410
120
              export_options;
2411
2412
            /*
2413
              Convert PseudoClass image to a BMP monochrome image.
2414
            */
2415
120
            if (logging)
2416
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2417
0
                                    "  Output %u-bit PseudoClass pixels",
2418
0
                                    bmp_info.bits_per_pixel);
2419
120
            ExportPixelAreaOptionsInit(&export_options);
2420
120
            export_options.pad_bytes=(unsigned long) (bytes_per_line - (((size_t) image->columns+7)/8));
2421
120
            export_options.pad_value=0x00;
2422
18.3k
            for (y=0; y < image->rows; y++)
2423
18.2k
              {
2424
18.2k
                p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
2425
18.2k
                if (p == (const PixelPacket *) NULL)
2426
0
                  break;
2427
18.2k
                q=pixels+((size_t) image->rows-y-1)*bytes_per_line;
2428
18.2k
                if (ExportImagePixelArea(image,IndexQuantum,1,q,&export_options,0)
2429
18.2k
                    == MagickFail)
2430
0
                  {
2431
0
                    break;
2432
0
                  }
2433
18.2k
                if (image->previous == (Image *) NULL)
2434
18.2k
                  if (QuantumTick(y,image->rows))
2435
6.09k
                    if (!MagickMonitorFormatted(y,image->rows,&image->exception,
2436
6.09k
                                                SaveImageText,image->filename,
2437
6.09k
                                                image->columns,image->rows))
2438
0
                      break;
2439
18.2k
              }
2440
120
            break;
2441
0
          }
2442
94
        case 4:
2443
94
          {
2444
94
            ExportPixelAreaOptions
2445
94
              export_options;
2446
2447
            /*
2448
              Convert PseudoClass image to a BMP monochrome image.
2449
            */
2450
94
            if (logging)
2451
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2452
0
                                    "  Output %u-bit PseudoClass pixels",
2453
0
                                    bmp_info.bits_per_pixel);
2454
94
            ExportPixelAreaOptionsInit(&export_options);
2455
94
            export_options.pad_bytes=(unsigned long) (bytes_per_line - ((image->columns+1)/2));
2456
94
            export_options.pad_value=0x00;
2457
26.6k
            for (y=0; y < image->rows; y++)
2458
26.6k
              {
2459
26.6k
                p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
2460
26.6k
                if (p == (const PixelPacket *) NULL)
2461
0
                  break;
2462
26.6k
                q=pixels+((size_t) image->rows-y-1)*bytes_per_line;
2463
26.6k
                if (ExportImagePixelArea(image,IndexQuantum,4,q,&export_options,0)
2464
26.6k
                    == MagickFail)
2465
0
                  {
2466
0
                    break;
2467
0
                  }
2468
26.6k
                if (image->previous == (Image *) NULL)
2469
26.6k
                  if (QuantumTick(y,image->rows))
2470
5.09k
                    if (!MagickMonitorFormatted(y,image->rows,&image->exception,
2471
5.09k
                                                SaveImageText,image->filename,
2472
5.09k
                                                image->columns,image->rows))
2473
0
                      break;
2474
26.6k
              }
2475
94
            break;
2476
0
          }
2477
97
        case 8:
2478
97
          {
2479
97
            ExportPixelAreaOptions
2480
97
              export_options;
2481
2482
            /*
2483
              Convert PseudoClass packet to BMP pixel.
2484
            */
2485
97
            if (logging)
2486
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2487
0
                                    "  Output %u-bit PseudoClass pixels",
2488
0
                                    bmp_info.bits_per_pixel);
2489
97
            ExportPixelAreaOptionsInit(&export_options);
2490
97
            export_options.pad_bytes=(unsigned long) (bytes_per_line - image->columns);
2491
40.6k
            for (y=0; y < image->rows; y++)
2492
40.5k
              {
2493
40.5k
                p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
2494
40.5k
                if (p == (const PixelPacket *) NULL)
2495
0
                  break;
2496
40.5k
                q=pixels+((size_t) image->rows-y-1)*bytes_per_line;
2497
40.5k
                if (ExportImagePixelArea(image,IndexQuantum,8,q,&export_options,0)
2498
40.5k
                    == MagickFail)
2499
0
                  {
2500
                      /* Please note that pixels array has uninitialised elements when this fails. */
2501
0
                    if(logging)
2502
0
                      (void)LogMagickEvent(CoderEvent,GetMagickModule(),
2503
0
                                    "  ExportImagePixelArea failed at row %lu", y);
2504
0
                    ThrowWriterException(CoderError,DataEncodingSchemeIsNotSupported,image);
2505
0
                    break;
2506
0
                  }
2507
40.5k
                if (image->previous == (Image *) NULL)
2508
40.5k
                  if (QuantumTick(y,image->rows))
2509
8.38k
                    if (!MagickMonitorFormatted(y,image->rows,&image->exception,
2510
8.38k
                                                SaveImageText,image->filename,
2511
8.38k
                                                image->columns,image->rows))
2512
0
                      break;
2513
40.5k
              }
2514
97
            break;
2515
97
          }
2516
434
        case 24:
2517
559
        case 32:
2518
559
          {
2519
            /*
2520
              Convert DirectClass packet to BMP BGR888 or BGRA8888 pixel.
2521
            */
2522
559
            if (logging)
2523
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2524
0
                                    "  Output %u-bit DirectClass pixels",
2525
0
                                    bmp_info.bits_per_pixel);
2526
37.3k
            for (y=0; y < image->rows; y++)
2527
36.8k
              {
2528
36.8k
                p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
2529
36.8k
                if (p == (const PixelPacket *) NULL)
2530
0
                  break;
2531
36.8k
                q=pixels+((size_t) image->rows-y-1)*bytes_per_line;
2532
615k
                for (x=0; x < image->columns; x++)
2533
578k
                  {
2534
578k
                    *q++=ScaleQuantumToChar(p->blue);
2535
578k
                    *q++=ScaleQuantumToChar(p->green);
2536
578k
                    *q++=ScaleQuantumToChar(p->red);
2537
578k
                    if (bmp_info.bits_per_pixel == 32)
2538
414k
                      *q++=ScaleQuantumToChar(MaxRGB-p->opacity);
2539
578k
                    p++;
2540
578k
                  }
2541
36.8k
                if (bmp_info.bits_per_pixel == 24)
2542
22.1k
                  {
2543
                    /* initialize padding bytes */
2544
46.8k
                    for (x=3*image->columns; x < bytes_per_line; x++)
2545
24.7k
                      *q++=0x00;
2546
22.1k
                  }
2547
36.8k
                if (image->previous == (Image *) NULL)
2548
36.8k
                  if (QuantumTick(y,image->rows))
2549
13.6k
                    if (!MagickMonitorFormatted(y,image->rows,&image->exception,
2550
13.6k
                                                SaveImageText,image->filename,
2551
13.6k
                                                image->columns,image->rows))
2552
0
                      break;
2553
36.8k
              }
2554
559
            break;
2555
434
          }
2556
0
        default:
2557
0
          {
2558
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2559
0
                                  "Unsupported bits-per-pixel %u!",
2560
0
                                  bmp_info.bits_per_pixel);
2561
2562
0
            break;
2563
434
          }
2564
870
        }
2565
870
      if ((type > 2) && (bmp_info.bits_per_pixel == 8))
2566
97
        if (image_info->compression != NoCompression)
2567
97
          {
2568
97
            size_t
2569
97
              length;
2570
2571
            /*
2572
              Convert run-length encoded raster pixels.
2573
            */
2574
97
            length=2*(bytes_per_line+2)*((size_t)image->rows+2)+2;
2575
97
            bmp_data=MagickAllocateResourceLimitedMemory(unsigned char *,length);
2576
97
            if (bmp_data == (unsigned char *) NULL)
2577
0
              {
2578
0
                MagickFreeResourceLimitedMemory(pixels);
2579
0
                ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,
2580
0
                                     image);
2581
0
              }
2582
97
            bmp_info.file_size-=bmp_info.image_size;
2583
97
            bmp_info.image_size=EncodeImage(image,bytes_per_line,pixels,
2584
97
                                            bmp_data);
2585
97
            bmp_info.file_size+=bmp_info.image_size;
2586
97
            MagickFreeResourceLimitedMemory(pixels);
2587
97
            pixels=bmp_data;
2588
97
            bmp_info.compression=BI_RLE8;
2589
97
          }
2590
      /*
2591
        Write BMP for Windows, all versions, 14-byte header.
2592
      */
2593
870
      if (logging)
2594
0
        {
2595
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2596
0
                                "   Writing BMP version %ld datastream",type);
2597
0
          if (image->storage_class == DirectClass)
2598
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2599
0
                                  "   Storage class=DirectClass");
2600
0
          else
2601
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2602
0
                                  "   Storage class=PseudoClass");
2603
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2604
0
                                "   Image depth=%u",image->depth);
2605
0
          if (image->matte)
2606
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2607
0
                                  "   Matte=True");
2608
0
          else
2609
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2610
0
                                  "   Matte=False");
2611
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2612
0
                                "   BMP bits_per_pixel=%d",bmp_info.bits_per_pixel);
2613
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2614
0
                                "   BMP file_size=%" MAGICK_SIZE_T_F "u bytes",
2615
0
                                (MAGICK_SIZE_T) bmp_info.file_size);
2616
0
          if(bmp_info.compression <=BI_ALPHABITFIELDS)
2617
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2618
0
                                      "   Compression=%s", DecodeBiCompression(bmp_info.compression,40));
2619
0
          else
2620
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2621
0
                                      "   Compression=UNKNOWN (%u)",bmp_info.compression);
2622
0
          if (bmp_info.number_colors == 0)
2623
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2624
0
                                  "   Number_colors=unspecified");
2625
0
          else
2626
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2627
0
                                  "   Number_colors=%u",bmp_info.number_colors);
2628
0
        }
2629
870
      (void) WriteBlob(image,2,"BM");
2630
870
      (void) WriteBlobLSBLong(image,(magick_uint32_t) bmp_info.file_size);
2631
870
      (void) WriteBlobLSBLong(image,bmp_info.ba_offset);  /* always 0 */
2632
870
      (void) WriteBlobLSBLong(image,bmp_info.offset_bits);
2633
870
      if (type == 2)
2634
0
        {
2635
          /*
2636
            Write 12-byte version 2 bitmap header.
2637
          */
2638
0
          (void) WriteBlobLSBLong(image,bmp_info.size);
2639
0
          (void) WriteBlobLSBShort(image,bmp_info.width);
2640
0
          (void) WriteBlobLSBShort(image,bmp_info.height);
2641
0
          (void) WriteBlobLSBShort(image,bmp_info.planes);
2642
0
          (void) WriteBlobLSBShort(image,bmp_info.bits_per_pixel);
2643
0
        }
2644
870
      else
2645
870
        {
2646
          /*
2647
            Write 40-byte version 3+ bitmap header.
2648
          */
2649
870
          (void) WriteBlobLSBLong(image,bmp_info.size);
2650
870
          (void) WriteBlobLSBLong(image,bmp_info.width);
2651
870
          (void) WriteBlobLSBLong(image,bmp_info.height);
2652
870
          (void) WriteBlobLSBShort(image,bmp_info.planes);
2653
870
          (void) WriteBlobLSBShort(image,bmp_info.bits_per_pixel);
2654
870
          (void) WriteBlobLSBLong(image,bmp_info.compression);
2655
870
          (void) WriteBlobLSBLong(image,(magick_uint32_t) bmp_info.image_size);
2656
870
          (void) WriteBlobLSBLong(image,bmp_info.x_pixels);
2657
870
          (void) WriteBlobLSBLong(image,bmp_info.y_pixels);
2658
870
          (void) WriteBlobLSBLong(image,bmp_info.number_colors);
2659
870
          (void) WriteBlobLSBLong(image,bmp_info.colors_important);
2660
870
        }
2661
870
      if ((type > 3) && (image->matte || have_color_info))
2662
127
        {
2663
          /*
2664
            Write the rest of the 108-byte BMP Version 4 header.
2665
          */
2666
127
          (void) WriteBlobLSBLong(image,0x00ff0000L);  /* Red mask */
2667
127
          (void) WriteBlobLSBLong(image,0x0000ff00L);  /* Green mask */
2668
127
          (void) WriteBlobLSBLong(image,0x000000ffL);  /* Blue mask */
2669
127
          (void) WriteBlobLSBLong(image,0xff000000UL);  /* Alpha mask */
2670
127
          (void) WriteBlobLSBLong(image,0x00000001L);   /* CSType==Calib. RGB */
2671
127
          (void) WriteBlobLSBLong(image,
2672
127
                                  (magick_uint32_t) (image->chromaticity.red_primary.x*0x3ffffff));
2673
127
          (void) WriteBlobLSBLong(image,
2674
127
                                  (magick_uint32_t) (image->chromaticity.red_primary.y*0x3ffffff));
2675
127
          (void) WriteBlobLSBLong(image,
2676
127
                                  (magick_uint32_t) (1.000f-(image->chromaticity.red_primary.x
2677
127
                                                             +image->chromaticity.red_primary.y)*0x3ffffff));
2678
127
          (void) WriteBlobLSBLong(image,
2679
127
                                  (magick_uint32_t) (image->chromaticity.green_primary.x*0x3ffffff));
2680
127
          (void) WriteBlobLSBLong(image,
2681
127
                                  (magick_uint32_t) (image->chromaticity.green_primary.y*0x3ffffff));
2682
127
          (void) WriteBlobLSBLong(image,
2683
127
                                  (magick_uint32_t) (1.000f-(image->chromaticity.green_primary.x
2684
127
                                                             +image->chromaticity.green_primary.y)*0x3ffffff));
2685
127
          (void) WriteBlobLSBLong(image,
2686
127
                                  (magick_uint32_t) (image->chromaticity.blue_primary.x*0x3ffffff));
2687
127
          (void) WriteBlobLSBLong(image,
2688
127
                                  (magick_uint32_t) (image->chromaticity.blue_primary.y*0x3ffffff));
2689
127
          (void) WriteBlobLSBLong(image,
2690
127
                                  (magick_uint32_t) (1.000f-(image->chromaticity.blue_primary.x
2691
127
                                                             +image->chromaticity.blue_primary.y)*0x3ffffff));
2692
2693
127
          (void) WriteBlobLSBLong(image,(magick_uint32_t) (bmp_info.gamma_scale.x*0xffff));
2694
127
          (void) WriteBlobLSBLong(image,(magick_uint32_t) (bmp_info.gamma_scale.y*0xffff));
2695
127
          (void) WriteBlobLSBLong(image,(magick_uint32_t) (bmp_info.gamma_scale.z*0xffff));
2696
127
          if ((image->rendering_intent != UndefinedIntent) ||
2697
127
              (color_profile_length != 0))
2698
4
            {
2699
4
              long
2700
4
                intent;
2701
2702
4
              switch ((int) image->rendering_intent)
2703
4
                {
2704
1
                case SaturationIntent:
2705
1
                  {
2706
1
                    intent=LCS_GM_BUSINESS;
2707
1
                    break;
2708
0
                  }
2709
1
                case RelativeIntent:
2710
1
                  {
2711
1
                    intent=LCS_GM_GRAPHICS;
2712
1
                    break;
2713
0
                  }
2714
1
                case PerceptualIntent:
2715
1
                  {
2716
1
                    intent=LCS_GM_IMAGES;
2717
1
                    break;
2718
0
                  }
2719
1
                case AbsoluteIntent:
2720
1
                  {
2721
1
                    intent=LCS_GM_ABS_COLORIMETRIC;
2722
1
                    break;
2723
0
                  }
2724
0
                default:
2725
0
                  {
2726
0
                    intent=0;
2727
0
                    break;
2728
0
                  }
2729
4
                }
2730
4
              (void) WriteBlobLSBLong(image,intent);
2731
4
              (void) WriteBlobLSBLong(image,0x0);  /* dummy profile data */
2732
4
              (void) WriteBlobLSBLong(image,0x0);  /* dummy profile length */
2733
4
              (void) WriteBlobLSBLong(image,0x0);  /* reserved */
2734
4
            }
2735
127
        }
2736
870
        if(pixels==NULL)
2737
0
        {
2738
0
          StoreAlienBlob(image,image_info, (bmp_info.compression==BI_JPEG)? &StoreDescJPG : &StoreDescPNG);
2739
0
        }
2740
870
        else
2741
870
        {
2742
870
          if (image->storage_class==PseudoClass)
2743
311
            {
2744
311
            unsigned char
2745
311
              *bmp_colormap;
2746
2747
          /*
2748
            Dump colormap to file.
2749
          */
2750
311
            if (logging)
2751
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2752
0
                                  "  Colormap: %u entries",image->colors);
2753
311
            bmp_colormap=MagickAllocateResourceLimitedArray(unsigned char *,4,
2754
311
                                                           ((size_t)1L << bmp_info.bits_per_pixel));
2755
311
            if (bmp_colormap == (unsigned char *) NULL)
2756
0
              {
2757
0
                MagickFreeResourceLimitedMemory(pixels);
2758
0
                ThrowWriterException(ResourceLimitError,MemoryAllocationFailed, image);
2759
0
              }
2760
311
            q=bmp_colormap;
2761
18.5k
            for (i=0; i < Min(image->colors,bmp_info.number_colors); i++)
2762
18.2k
              {
2763
18.2k
                *q++=ScaleQuantumToChar(image->colormap[i].blue);
2764
18.2k
                *q++=ScaleQuantumToChar(image->colormap[i].green);
2765
18.2k
                *q++=ScaleQuantumToChar(image->colormap[i].red);
2766
18.2k
                if (type > 2)
2767
18.2k
                  *q++=(Quantum) 0x0;
2768
18.2k
              }
2769
8.64k
            for ( ; i < (1UL << bmp_info.bits_per_pixel); i++)
2770
8.33k
              {
2771
8.33k
              *q++=(Quantum) 0x0;
2772
8.33k
                *q++=(Quantum) 0x0;
2773
8.33k
                *q++=(Quantum) 0x0;
2774
8.33k
                if (type > 2)
2775
8.33k
                  *q++=(Quantum) 0x0;
2776
8.33k
                }
2777
311
            if (type <= 2)
2778
0
              (void) WriteBlob(image,3*((size_t)1UL << bmp_info.bits_per_pixel),
2779
0
                             (char *) bmp_colormap);
2780
311
            else
2781
311
              (void) WriteBlob(image,4*((size_t)1UL << bmp_info.bits_per_pixel),
2782
311
                             (char *) bmp_colormap);
2783
311
            MagickFreeResourceLimitedMemory(bmp_colormap);
2784
311
          }
2785
870
        if (logging)
2786
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2787
0
                              "  Pixels:  %" MAGICK_SIZE_T_F "u bytes",
2788
0
                              (MAGICK_SIZE_T) bmp_info.image_size);
2789
870
        (void) WriteBlob(image,bmp_info.image_size,(char *) pixels);
2790
870
        MagickFreeResourceLimitedMemory(pixels);
2791
870
      }
2792
870
      if (image->next == (Image *) NULL)
2793
870
        {
2794
870
          if (logging)
2795
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2796
0
                                  "No more image frames in list (scene=%lu)",
2797
0
                                  scene);
2798
870
          break;
2799
870
        }
2800
0
      image=SyncNextImageInList(image);
2801
0
      status&=MagickMonitorFormatted(scene++,image_list_length,
2802
0
                                     &image->exception,SaveImagesText,
2803
0
                                     image->filename);
2804
0
      if (status != MagickPass)
2805
0
        break;
2806
0
      if (logging)
2807
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2808
0
                              "At end of image adjoin loop (adjoin=%u, scene=%lu)",
2809
0
                              image_info->adjoin, scene);
2810
0
    } while (adjoin);
2811
870
  if (adjoin)
2812
870
    while (image->previous != (Image *) NULL)
2813
0
      image=image->previous;
2814
870
  status &= CloseBlob(image);
2815
870
  if (logging)
2816
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),"return");
2817
870
  return(status);
2818
870
}