1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % BBBB M M PPPP %
7 % B B MM MM P P %
8 % BBBB M M M PPPP %
9 % B B M M P %
10 % BBBB M M P %
11 % %
12 % %
13 % Read/Write Microsoft Windows Bitmap Image Format %
14 % %
15 % Software Design %
16 % Cristy %
17 % Glenn Randers-Pehrson %
18 % December 2001 %
19 % %
20 % %
21 % Copyright 1999-2019 ImageMagick Studio LLC, a non-profit organization %
22 % dedicated to making software imaging solutions freely available. %
23 % %
24 % You may not use this file except in compliance with the License. You may %
25 % obtain a copy of the License at %
26 % %
27 % https://imagemagick.org/script/license.php %
28 % %
29 % Unless required by applicable law or agreed to in writing, software %
30 % distributed under the License is distributed on an "AS IS" BASIS, %
31 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
32 % See the License for the specific language governing permissions and %
33 % limitations under the License. %
34 % %
35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36 %
37 %
38 */
39
40 /*
41 Include declarations.
42 */
43 #include "MagickCore/studio.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/colormap-private.h"
48 #include "MagickCore/color-private.h"
49 #include "MagickCore/colormap.h"
50 #include "MagickCore/colorspace.h"
51 #include "MagickCore/colorspace-private.h"
52 #include "MagickCore/exception.h"
53 #include "MagickCore/exception-private.h"
54 #include "MagickCore/image.h"
55 #include "MagickCore/image-private.h"
56 #include "MagickCore/list.h"
57 #include "MagickCore/log.h"
58 #include "MagickCore/magick.h"
59 #include "MagickCore/memory_.h"
60 #include "MagickCore/monitor.h"
61 #include "MagickCore/monitor-private.h"
62 #include "MagickCore/option.h"
63 #include "MagickCore/pixel-accessor.h"
64 #include "MagickCore/profile.h"
65 #include "MagickCore/quantum-private.h"
66 #include "MagickCore/static.h"
67 #include "MagickCore/string_.h"
68 #include "MagickCore/module.h"
69 #include "MagickCore/transform.h"
70
71 /*
72 Macro definitions (from Windows wingdi.h).
73 */
74 #undef BI_JPEG
75 #define BI_JPEG 4
76 #undef BI_PNG
77 #define BI_PNG 5
78 #if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__MINGW32__)
79 #undef BI_RGB
80 #define BI_RGB 0
81 #undef BI_RLE8
82 #define BI_RLE8 1
83 #undef BI_RLE4
84 #define BI_RLE4 2
85 #undef BI_BITFIELDS
86 #define BI_BITFIELDS 3
87
88 #undef LCS_CALIBRATED_RBG
89 #define LCS_CALIBRATED_RBG 0
90 #undef LCS_sRGB
91 #define LCS_sRGB 1
92 #undef LCS_WINDOWS_COLOR_SPACE
93 #define LCS_WINDOWS_COLOR_SPACE 2
94 #undef PROFILE_LINKED
95 #define PROFILE_LINKED 3
96 #undef PROFILE_EMBEDDED
97 #define PROFILE_EMBEDDED 4
98
99 #undef LCS_GM_BUSINESS
100 #define LCS_GM_BUSINESS 1 /* Saturation */
101 #undef LCS_GM_GRAPHICS
102 #define LCS_GM_GRAPHICS 2 /* Relative */
103 #undef LCS_GM_IMAGES
104 #define LCS_GM_IMAGES 4 /* Perceptual */
105 #undef LCS_GM_ABS_COLORIMETRIC
106 #define LCS_GM_ABS_COLORIMETRIC 8 /* Absolute */
107 #endif
108
109 /*
110 Enumerated declaractions.
111 */
112 typedef enum
113 {
114 UndefinedSubtype,
115 RGB555,
116 RGB565,
117 ARGB4444,
118 ARGB1555
119 } BMPSubtype;
120
121 /*
122 Typedef declarations.
123 */
124 typedef struct _BMPInfo
125 {
126 unsigned int
127 file_size,
128 ba_offset,
129 offset_bits,
130 size;
131
132 ssize_t
133 width,
134 height;
135
136 unsigned short
137 planes,
138 bits_per_pixel;
139
140 unsigned int
141 compression,
142 image_size,
143 x_pixels,
144 y_pixels,
145 number_colors,
146 red_mask,
147 green_mask,
148 blue_mask,
149 alpha_mask,
150 colors_important;
151
152 long
153 colorspace;
154
155 PrimaryInfo
156 red_primary,
157 green_primary,
158 blue_primary,
159 gamma_scale;
160 } BMPInfo;
161
162 /*
163 Forward declarations.
164 */
165 static MagickBooleanType
166 WriteBMPImage(const ImageInfo *,Image *,ExceptionInfo *);
167
168 /*
169 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
170 % %
171 % %
172 % %
173 % D e c o d e I m a g e %
174 % %
175 % %
176 % %
177 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
178 %
179 % DecodeImage unpacks the packed image pixels into runlength-encoded
180 % pixel packets.
181 %
182 % The format of the DecodeImage method is:
183 %
184 % MagickBooleanType DecodeImage(Image *image,const size_t compression,
185 % unsigned char *pixels,const size_t number_pixels)
186 %
187 % A description of each parameter follows:
188 %
189 % o image: the address of a structure of type Image.
190 %
191 % o compression: Zero means uncompressed. A value of 1 means the
192 % compressed pixels are runlength encoded for a 256-color bitmap.
193 % A value of 2 means a 16-color bitmap. A value of 3 means bitfields
194 % encoding.
195 %
196 % o pixels: The address of a byte (8 bits) array of pixel data created by
197 % the decoding process.
198 %
199 % o number_pixels: The number of pixels.
200 %
201 */
DecodeImage(Image * image,const size_t compression,unsigned char * pixels,const size_t number_pixels)202 static MagickBooleanType DecodeImage(Image *image,const size_t compression,
203 unsigned char *pixels,const size_t number_pixels)
204 {
205 int
206 byte,
207 count;
208
209 register ssize_t
210 i,
211 x;
212
213 register unsigned char
214 *p,
215 *q;
216
217 ssize_t
218 y;
219
220 assert(image != (Image *) NULL);
221 assert(image->signature == MagickCoreSignature);
222 if (image->debug != MagickFalse)
223 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
224 assert(pixels != (unsigned char *) NULL);
225 (void) memset(pixels,0,number_pixels*sizeof(*pixels));
226 byte=0;
227 x=0;
228 p=pixels;
229 q=pixels+number_pixels;
230 for (y=0; y < (ssize_t) image->rows; )
231 {
232 MagickBooleanType
233 status;
234
235 if ((p < pixels) || (p > q))
236 break;
237 count=ReadBlobByte(image);
238 if (count == EOF)
239 break;
240 if (count > 0)
241 {
242 /*
243 Encoded mode.
244 */
245 count=(int) MagickMin((ssize_t) count,(ssize_t) (q-p));
246 byte=ReadBlobByte(image);
247 if (byte == EOF)
248 break;
249 if (compression == BI_RLE8)
250 {
251 for (i=0; i < (ssize_t) count; i++)
252 *p++=(unsigned char) byte;
253 }
254 else
255 {
256 for (i=0; i < (ssize_t) count; i++)
257 *p++=(unsigned char)
258 ((i & 0x01) != 0 ? (byte & 0x0f) : ((byte >> 4) & 0x0f));
259 }
260 x+=count;
261 }
262 else
263 {
264 /*
265 Escape mode.
266 */
267 count=ReadBlobByte(image);
268 if (count == EOF)
269 break;
270 if (count == 0x01)
271 return(MagickTrue);
272 switch (count)
273 {
274 case 0x00:
275 {
276 /*
277 End of line.
278 */
279 x=0;
280 y++;
281 p=pixels+y*image->columns;
282 break;
283 }
284 case 0x02:
285 {
286 /*
287 Delta mode.
288 */
289 x+=ReadBlobByte(image);
290 y+=ReadBlobByte(image);
291 p=pixels+y*image->columns+x;
292 break;
293 }
294 default:
295 {
296 /*
297 Absolute mode.
298 */
299 count=(int) MagickMin((ssize_t) count,(ssize_t) (q-p));
300 if (compression == BI_RLE8)
301 for (i=0; i < (ssize_t) count; i++)
302 {
303 byte=ReadBlobByte(image);
304 if (byte == EOF)
305 break;
306 *p++=(unsigned char) byte;
307 }
308 else
309 for (i=0; i < (ssize_t) count; i++)
310 {
311 if ((i & 0x01) == 0)
312 {
313 byte=ReadBlobByte(image);
314 if (byte == EOF)
315 break;
316 }
317 *p++=(unsigned char)
318 ((i & 0x01) != 0 ? (byte & 0x0f) : ((byte >> 4) & 0x0f));
319 }
320 x+=count;
321 /*
322 Read pad byte.
323 */
324 if (compression == BI_RLE8)
325 {
326 if ((count & 0x01) != 0)
327 if (ReadBlobByte(image) == EOF)
328 break;
329 }
330 else
331 if (((count & 0x03) == 1) || ((count & 0x03) == 2))
332 if (ReadBlobByte(image) == EOF)
333 break;
334 break;
335 }
336 }
337 }
338 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
339 image->rows);
340 if (status == MagickFalse)
341 break;
342 }
343 (void) ReadBlobByte(image); /* end of line */
344 (void) ReadBlobByte(image);
345 return(y < (ssize_t) image->rows ? MagickFalse : MagickTrue);
346 }
347
348 /*
349 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
350 % %
351 % %
352 % %
353 % E n c o d e I m a g e %
354 % %
355 % %
356 % %
357 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
358 %
359 % EncodeImage compresses pixels using a runlength encoded format.
360 %
361 % The format of the EncodeImage method is:
362 %
363 % static MagickBooleanType EncodeImage(Image *image,
364 % const size_t bytes_per_line,const unsigned char *pixels,
365 % unsigned char *compressed_pixels)
366 %
367 % A description of each parameter follows:
368 %
369 % o image: The image.
370 %
371 % o bytes_per_line: the number of bytes in a scanline of compressed pixels
372 %
373 % o pixels: The address of a byte (8 bits) array of pixel data created by
374 % the compression process.
375 %
376 % o compressed_pixels: The address of a byte (8 bits) array of compressed
377 % pixel data.
378 %
379 */
EncodeImage(Image * image,const size_t bytes_per_line,const unsigned char * pixels,unsigned char * compressed_pixels)380 static size_t EncodeImage(Image *image,const size_t bytes_per_line,
381 const unsigned char *pixels,unsigned char *compressed_pixels)
382 {
383 MagickBooleanType
384 status;
385
386 register const unsigned char
387 *p;
388
389 register ssize_t
390 i,
391 x;
392
393 register unsigned char
394 *q;
395
396 ssize_t
397 y;
398
399 /*
400 Runlength encode pixels.
401 */
402 assert(image != (Image *) NULL);
403 assert(image->signature == MagickCoreSignature);
404 if (image->debug != MagickFalse)
405 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
406 assert(pixels != (const unsigned char *) NULL);
407 assert(compressed_pixels != (unsigned char *) NULL);
408 p=pixels;
409 q=compressed_pixels;
410 i=0;
411 for (y=0; y < (ssize_t) image->rows; y++)
412 {
413 for (x=0; x < (ssize_t) bytes_per_line; x+=i)
414 {
415 /*
416 Determine runlength.
417 */
418 for (i=1; ((x+i) < (ssize_t) bytes_per_line); i++)
419 if ((i == 255) || (*(p+i) != *p))
420 break;
421 *q++=(unsigned char) i;
422 *q++=(*p);
423 p+=i;
424 }
425 /*
426 End of line.
427 */
428 *q++=(unsigned char) 0x00;
429 *q++=(unsigned char) 0x00;
430 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
431 image->rows);
432 if (status == MagickFalse)
433 break;
434 }
435 /*
436 End of bitmap.
437 */
438 *q++=(unsigned char) 0x00;
439 *q++=(unsigned char) 0x01;
440 return((size_t) (q-compressed_pixels));
441 }
442
443 /*
444 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
445 % %
446 % %
447 % %
448 % I s B M P %
449 % %
450 % %
451 % %
452 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
453 %
454 % IsBMP() returns MagickTrue if the image format type, identified by the
455 % magick string, is BMP.
456 %
457 % The format of the IsBMP method is:
458 %
459 % MagickBooleanType IsBMP(const unsigned char *magick,const size_t length)
460 %
461 % A description of each parameter follows:
462 %
463 % o magick: compare image format pattern against these bytes.
464 %
465 % o length: Specifies the length of the magick string.
466 %
467 */
IsBMP(const unsigned char * magick,const size_t length)468 static MagickBooleanType IsBMP(const unsigned char *magick,const size_t length)
469 {
470 if (length < 2)
471 return(MagickFalse);
472 if ((LocaleNCompare((char *) magick,"BA",2) == 0) ||
473 (LocaleNCompare((char *) magick,"BM",2) == 0) ||
474 (LocaleNCompare((char *) magick,"IC",2) == 0) ||
475 (LocaleNCompare((char *) magick,"PI",2) == 0) ||
476 (LocaleNCompare((char *) magick,"CI",2) == 0) ||
477 (LocaleNCompare((char *) magick,"CP",2) == 0))
478 return(MagickTrue);
479 return(MagickFalse);
480 }
481
482 /*
483 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
484 % %
485 % %
486 % %
487 % R e a d B M P I m a g e %
488 % %
489 % %
490 % %
491 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
492 %
493 % ReadBMPImage() reads a Microsoft Windows bitmap image file, Version
494 % 2, 3 (for Windows or NT), or 4, and returns it. It allocates the memory
495 % necessary for the new Image structure and returns a pointer to the new
496 % image.
497 %
498 % The format of the ReadBMPImage method is:
499 %
500 % image=ReadBMPImage(image_info)
501 %
502 % A description of each parameter follows:
503 %
504 % o image_info: the image info.
505 %
506 % o exception: return any errors or warnings in this structure.
507 %
508 */
509
ReadBMPImage(const ImageInfo * image_info,ExceptionInfo * exception)510 static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
511 {
512 BMPInfo
513 bmp_info;
514
515 Image
516 *image;
517
518 MagickBooleanType
519 status;
520
521 MagickOffsetType
522 offset,
523 profile_data,
524 profile_size,
525 start_position;
526
527 MemoryInfo
528 *pixel_info;
529
530 Quantum
531 index;
532
533 register Quantum
534 *q;
535
536 register ssize_t
537 i,
538 x;
539
540 register unsigned char
541 *p;
542
543 size_t
544 bit,
545 bytes_per_line,
546 length;
547
548 ssize_t
549 count,
550 y;
551
552 unsigned char
553 magick[12],
554 *pixels;
555
556 unsigned int
557 blue,
558 green,
559 offset_bits,
560 red;
561
562 /*
563 Open image file.
564 */
565 assert(image_info != (const ImageInfo *) NULL);
566 assert(image_info->signature == MagickCoreSignature);
567 if (image_info->debug != MagickFalse)
568 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
569 image_info->filename);
570 assert(exception != (ExceptionInfo *) NULL);
571 assert(exception->signature == MagickCoreSignature);
572 image=AcquireImage(image_info,exception);
573 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
574 if (status == MagickFalse)
575 {
576 image=DestroyImageList(image);
577 return((Image *) NULL);
578 }
579 /*
580 Determine if this a BMP file.
581 */
582 (void) memset(&bmp_info,0,sizeof(bmp_info));
583 bmp_info.ba_offset=0;
584 start_position=0;
585 offset_bits=0;
586 count=ReadBlob(image,2,magick);
587 if (count != 2)
588 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
589 do
590 {
591 PixelInfo
592 quantum_bits;
593
594 PixelPacket
595 shift;
596
597 /*
598 Verify BMP identifier.
599 */
600 start_position=TellBlob(image)-2;
601 bmp_info.ba_offset=0;
602 while (LocaleNCompare((char *) magick,"BA",2) == 0)
603 {
604 bmp_info.file_size=ReadBlobLSBLong(image);
605 bmp_info.ba_offset=ReadBlobLSBLong(image);
606 bmp_info.offset_bits=ReadBlobLSBLong(image);
607 count=ReadBlob(image,2,magick);
608 if (count != 2)
609 break;
610 }
611 if (image->debug != MagickFalse)
612 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Magick: %c%c",
613 magick[0],magick[1]);
614 if ((count != 2) || ((LocaleNCompare((char *) magick,"BM",2) != 0) &&
615 (LocaleNCompare((char *) magick,"CI",2) != 0)))
616 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
617 bmp_info.file_size=ReadBlobLSBLong(image);
618 (void) ReadBlobLSBLong(image);
619 bmp_info.offset_bits=ReadBlobLSBLong(image);
620 bmp_info.size=ReadBlobLSBLong(image);
621 if (image->debug != MagickFalse)
622 (void) LogMagickEvent(CoderEvent,GetMagickModule()," BMP size: %u",
623 bmp_info.size);
624 profile_data=0;
625 profile_size=0;
626 if (bmp_info.size == 12)
627 {
628 /*
629 OS/2 BMP image file.
630 */
631 (void) CopyMagickString(image->magick,"BMP2",MagickPathExtent);
632 bmp_info.width=(ssize_t) ((short) ReadBlobLSBShort(image));
633 bmp_info.height=(ssize_t) ((short) ReadBlobLSBShort(image));
634 bmp_info.planes=ReadBlobLSBShort(image);
635 bmp_info.bits_per_pixel=ReadBlobLSBShort(image);
636 bmp_info.x_pixels=0;
637 bmp_info.y_pixels=0;
638 bmp_info.number_colors=0;
639 bmp_info.compression=BI_RGB;
640 bmp_info.image_size=0;
641 bmp_info.alpha_mask=0;
642 if (image->debug != MagickFalse)
643 {
644 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
645 " Format: OS/2 Bitmap");
646 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
647 " Geometry: %.20gx%.20g",(double) bmp_info.width,(double)
648 bmp_info.height);
649 }
650 }
651 else
652 {
653 /*
654 Microsoft Windows BMP image file.
655 */
656 if (bmp_info.size < 40)
657 ThrowReaderException(CorruptImageError,"NonOS2HeaderSizeError");
658 bmp_info.width=(ssize_t) ReadBlobLSBSignedLong(image);
659 bmp_info.height=(ssize_t) ReadBlobLSBSignedLong(image);
660 bmp_info.planes=ReadBlobLSBShort(image);
661 bmp_info.bits_per_pixel=ReadBlobLSBShort(image);
662 bmp_info.compression=ReadBlobLSBLong(image);
663 bmp_info.image_size=ReadBlobLSBLong(image);
664 bmp_info.x_pixels=ReadBlobLSBLong(image);
665 bmp_info.y_pixels=ReadBlobLSBLong(image);
666 bmp_info.number_colors=ReadBlobLSBLong(image);
667 if ((MagickSizeType) bmp_info.number_colors > GetBlobSize(image))
668 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
669 bmp_info.colors_important=ReadBlobLSBLong(image);
670 if (image->debug != MagickFalse)
671 {
672 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
673 " Format: MS Windows bitmap");
674 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
675 " Geometry: %.20gx%.20g",(double) bmp_info.width,(double)
676 bmp_info.height);
677 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
678 " Bits per pixel: %.20g",(double) bmp_info.bits_per_pixel);
679 switch (bmp_info.compression)
680 {
681 case BI_RGB:
682 {
683 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
684 " Compression: BI_RGB");
685 break;
686 }
687 case BI_RLE4:
688 {
689 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
690 " Compression: BI_RLE4");
691 break;
692 }
693 case BI_RLE8:
694 {
695 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
696 " Compression: BI_RLE8");
697 break;
698 }
699 case BI_BITFIELDS:
700 {
701 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
702 " Compression: BI_BITFIELDS");
703 break;
704 }
705 case BI_PNG:
706 {
707 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
708 " Compression: BI_PNG");
709 break;
710 }
711 case BI_JPEG:
712 {
713 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
714 " Compression: BI_JPEG");
715 break;
716 }
717 default:
718 {
719 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
720 " Compression: UNKNOWN (%u)",bmp_info.compression);
721 }
722 }
723 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
724 " Number of colors: %u",bmp_info.number_colors);
725 }
726 bmp_info.red_mask=ReadBlobLSBLong(image);
727 bmp_info.green_mask=ReadBlobLSBLong(image);
728 bmp_info.blue_mask=ReadBlobLSBLong(image);
729 if (bmp_info.size > 40)
730 {
731 double
732 gamma;
733
734 /*
735 Read color management information.
736 */
737 bmp_info.alpha_mask=ReadBlobLSBLong(image);
738 bmp_info.colorspace=ReadBlobLSBSignedLong(image);
739 /*
740 Decode 2^30 fixed point formatted CIE primaries.
741 */
742 # define BMP_DENOM ((double) 0x40000000)
743 bmp_info.red_primary.x=(double) ReadBlobLSBLong(image)/BMP_DENOM;
744 bmp_info.red_primary.y=(double) ReadBlobLSBLong(image)/BMP_DENOM;
745 bmp_info.red_primary.z=(double) ReadBlobLSBLong(image)/BMP_DENOM;
746 bmp_info.green_primary.x=(double) ReadBlobLSBLong(image)/BMP_DENOM;
747 bmp_info.green_primary.y=(double) ReadBlobLSBLong(image)/BMP_DENOM;
748 bmp_info.green_primary.z=(double) ReadBlobLSBLong(image)/BMP_DENOM;
749 bmp_info.blue_primary.x=(double) ReadBlobLSBLong(image)/BMP_DENOM;
750 bmp_info.blue_primary.y=(double) ReadBlobLSBLong(image)/BMP_DENOM;
751 bmp_info.blue_primary.z=(double) ReadBlobLSBLong(image)/BMP_DENOM;
752
753 gamma=bmp_info.red_primary.x+bmp_info.red_primary.y+
754 bmp_info.red_primary.z;
755 gamma=PerceptibleReciprocal(gamma);
756 bmp_info.red_primary.x*=gamma;
757 bmp_info.red_primary.y*=gamma;
758 image->chromaticity.red_primary.x=bmp_info.red_primary.x;
759 image->chromaticity.red_primary.y=bmp_info.red_primary.y;
760
761 gamma=bmp_info.green_primary.x+bmp_info.green_primary.y+
762 bmp_info.green_primary.z;
763 gamma=PerceptibleReciprocal(gamma);
764 bmp_info.green_primary.x*=gamma;
765 bmp_info.green_primary.y*=gamma;
766 image->chromaticity.green_primary.x=bmp_info.green_primary.x;
767 image->chromaticity.green_primary.y=bmp_info.green_primary.y;
768
769 gamma=bmp_info.blue_primary.x+bmp_info.blue_primary.y+
770 bmp_info.blue_primary.z;
771 gamma=PerceptibleReciprocal(gamma);
772 bmp_info.blue_primary.x*=gamma;
773 bmp_info.blue_primary.y*=gamma;
774 image->chromaticity.blue_primary.x=bmp_info.blue_primary.x;
775 image->chromaticity.blue_primary.y=bmp_info.blue_primary.y;
776
777 /*
778 Decode 16^16 fixed point formatted gamma_scales.
779 */
780 bmp_info.gamma_scale.x=(double) ReadBlobLSBLong(image)/0x10000;
781 bmp_info.gamma_scale.y=(double) ReadBlobLSBLong(image)/0x10000;
782 bmp_info.gamma_scale.z=(double) ReadBlobLSBLong(image)/0x10000;
783 /*
784 Compute a single gamma from the BMP 3-channel gamma.
785 */
786 image->gamma=(bmp_info.gamma_scale.x+bmp_info.gamma_scale.y+
787 bmp_info.gamma_scale.z)/3.0;
788 }
789 else
790 (void) CopyMagickString(image->magick,"BMP3",MagickPathExtent);
791
792 if (bmp_info.size > 108)
793 {
794 size_t
795 intent;
796
797 /*
798 Read BMP Version 5 color management information.
799 */
800 intent=ReadBlobLSBLong(image);
801 switch ((int) intent)
802 {
803 case LCS_GM_BUSINESS:
804 {
805 image->rendering_intent=SaturationIntent;
806 break;
807 }
808 case LCS_GM_GRAPHICS:
809 {
810 image->rendering_intent=RelativeIntent;
811 break;
812 }
813 case LCS_GM_IMAGES:
814 {
815 image->rendering_intent=PerceptualIntent;
816 break;
817 }
818 case LCS_GM_ABS_COLORIMETRIC:
819 {
820 image->rendering_intent=AbsoluteIntent;
821 break;
822 }
823 }
824 profile_data=(MagickOffsetType)ReadBlobLSBLong(image);
825 profile_size=(MagickOffsetType)ReadBlobLSBLong(image);
826 (void) ReadBlobLSBLong(image); /* Reserved byte */
827 }
828 }
829 if ((MagickSizeType) bmp_info.file_size > GetBlobSize(image))
830 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
831 "LengthAndFilesizeDoNotMatch","`%s'",image->filename);
832 else
833 if ((MagickSizeType) bmp_info.file_size < GetBlobSize(image))
834 (void) ThrowMagickException(exception,GetMagickModule(),
835 CorruptImageWarning,"LengthAndFilesizeDoNotMatch","`%s'",
836 image->filename);
837 if (bmp_info.width <= 0)
838 ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize");
839 if (bmp_info.height == 0)
840 ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize");
841 if (bmp_info.planes != 1)
842 ThrowReaderException(CorruptImageError,"StaticPlanesValueNotEqualToOne");
843 if ((bmp_info.bits_per_pixel != 1) && (bmp_info.bits_per_pixel != 4) &&
844 (bmp_info.bits_per_pixel != 8) && (bmp_info.bits_per_pixel != 16) &&
845 (bmp_info.bits_per_pixel != 24) && (bmp_info.bits_per_pixel != 32))
846 ThrowReaderException(CorruptImageError,"UnsupportedBitsPerPixel");
847 if (bmp_info.bits_per_pixel < 16 &&
848 bmp_info.number_colors > (1U << bmp_info.bits_per_pixel))
849 ThrowReaderException(CorruptImageError,"UnrecognizedNumberOfColors");
850 if ((bmp_info.compression == 1) && (bmp_info.bits_per_pixel != 8))
851 ThrowReaderException(CorruptImageError,"UnsupportedBitsPerPixel");
852 if ((bmp_info.compression == 2) && (bmp_info.bits_per_pixel != 4))
853 ThrowReaderException(CorruptImageError,"UnsupportedBitsPerPixel");
854 if ((bmp_info.compression == 3) && (bmp_info.bits_per_pixel < 16))
855 ThrowReaderException(CorruptImageError,"UnsupportedBitsPerPixel");
856 switch (bmp_info.compression)
857 {
858 case BI_RGB:
859 image->compression=NoCompression;
860 break;
861 case BI_RLE8:
862 case BI_RLE4:
863 image->compression=RLECompression;
864 break;
865 case BI_BITFIELDS:
866 break;
867 case BI_JPEG:
868 ThrowReaderException(CoderError,"JPEGCompressNotSupported");
869 case BI_PNG:
870 ThrowReaderException(CoderError,"PNGCompressNotSupported");
871 default:
872 ThrowReaderException(CorruptImageError,"UnrecognizedImageCompression");
873 }
874 image->columns=(size_t) MagickAbsoluteValue(bmp_info.width);
875 image->rows=(size_t) MagickAbsoluteValue(bmp_info.height);
876 image->depth=bmp_info.bits_per_pixel <= 8 ? bmp_info.bits_per_pixel : 8;
877 image->alpha_trait=((bmp_info.alpha_mask != 0) &&
878 (bmp_info.compression == BI_BITFIELDS)) ? BlendPixelTrait :
879 UndefinedPixelTrait;
880 if (bmp_info.bits_per_pixel < 16)
881 {
882 size_t
883 one;
884
885 image->storage_class=PseudoClass;
886 image->colors=bmp_info.number_colors;
887 one=1;
888 if (image->colors == 0)
889 image->colors=one << bmp_info.bits_per_pixel;
890 }
891 image->resolution.x=(double) bmp_info.x_pixels/100.0;
892 image->resolution.y=(double) bmp_info.y_pixels/100.0;
893 image->units=PixelsPerCentimeterResolution;
894 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
895 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
896 break;
897 status=SetImageExtent(image,image->columns,image->rows,exception);
898 if (status == MagickFalse)
899 return(DestroyImageList(image));
900 if (image->storage_class == PseudoClass)
901 {
902 unsigned char
903 *bmp_colormap;
904
905 size_t
906 packet_size;
907
908 /*
909 Read BMP raster colormap.
910 */
911 if (image->debug != MagickFalse)
912 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
913 " Reading colormap of %.20g colors",(double) image->colors);
914 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
915 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
916 bmp_colormap=(unsigned char *) AcquireQuantumMemory((size_t)
917 image->colors,4*sizeof(*bmp_colormap));
918 if (bmp_colormap == (unsigned char *) NULL)
919 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
920 if ((bmp_info.size == 12) || (bmp_info.size == 64))
921 packet_size=3;
922 else
923 packet_size=4;
924 offset=SeekBlob(image,start_position+14+bmp_info.size,SEEK_SET);
925 if (offset < 0)
926 {
927 bmp_colormap=(unsigned char *) RelinquishMagickMemory(bmp_colormap);
928 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
929 }
930 count=ReadBlob(image,packet_size*image->colors,bmp_colormap);
931 if (count != (ssize_t) (packet_size*image->colors))
932 {
933 bmp_colormap=(unsigned char *) RelinquishMagickMemory(bmp_colormap);
934 ThrowReaderException(CorruptImageError,
935 "InsufficientImageDataInFile");
936 }
937 p=bmp_colormap;
938 for (i=0; i < (ssize_t) image->colors; i++)
939 {
940 image->colormap[i].blue=(MagickRealType) ScaleCharToQuantum(*p++);
941 image->colormap[i].green=(MagickRealType) ScaleCharToQuantum(*p++);
942 image->colormap[i].red=(MagickRealType) ScaleCharToQuantum(*p++);
943 if (packet_size == 4)
944 p++;
945 }
946 bmp_colormap=(unsigned char *) RelinquishMagickMemory(bmp_colormap);
947 }
948 /*
949 Read image data.
950 */
951 if (bmp_info.offset_bits == offset_bits)
952 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
953 offset_bits=bmp_info.offset_bits;
954 offset=SeekBlob(image,start_position+bmp_info.offset_bits,SEEK_SET);
955 if (offset < 0)
956 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
957 if (bmp_info.compression == BI_RLE4)
958 bmp_info.bits_per_pixel<<=1;
959 bytes_per_line=4*((image->columns*bmp_info.bits_per_pixel+31)/32);
960 length=(size_t) bytes_per_line*image->rows;
961 if ((MagickSizeType) (length/256) > GetBlobSize(image))
962 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
963 if ((bmp_info.compression == BI_RGB) ||
964 (bmp_info.compression == BI_BITFIELDS))
965 {
966 pixel_info=AcquireVirtualMemory(image->rows,
967 MagickMax(bytes_per_line,image->columns+256UL)*sizeof(*pixels));
968 if (pixel_info == (MemoryInfo *) NULL)
969 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
970 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
971 if (image->debug != MagickFalse)
972 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
973 " Reading pixels (%.20g bytes)",(double) length);
974 count=ReadBlob(image,length,pixels);
975 if (count != (ssize_t) length)
976 {
977 pixel_info=RelinquishVirtualMemory(pixel_info);
978 ThrowReaderException(CorruptImageError,
979 "InsufficientImageDataInFile");
980 }
981 }
982 else
983 {
984 /*
985 Convert run-length encoded raster pixels.
986 */
987 pixel_info=AcquireVirtualMemory(image->rows,
988 MagickMax(bytes_per_line,image->columns+256UL)*sizeof(*pixels));
989 if (pixel_info == (MemoryInfo *) NULL)
990 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
991 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
992 status=DecodeImage(image,bmp_info.compression,pixels,
993 image->columns*image->rows);
994 if (status == MagickFalse)
995 {
996 pixel_info=RelinquishVirtualMemory(pixel_info);
997 ThrowReaderException(CorruptImageError,
998 "UnableToRunlengthDecodeImage");
999 }
1000 }
1001 /*
1002 Convert BMP raster image to pixel packets.
1003 */
1004 if (bmp_info.compression == BI_RGB)
1005 {
1006 /*
1007 We should ignore the alpha value in BMP3 files but there have been
1008 reports about 32 bit files with alpha. We do a quick check to see if
1009 the alpha channel contains a value that is not zero (default value).
1010 If we find a non zero value we asume the program that wrote the file
1011 wants to use the alpha channel.
1012 */
1013 if ((image->alpha_trait == UndefinedPixelTrait) &&
1014 (bmp_info.size == 40) && (bmp_info.bits_per_pixel == 32))
1015 {
1016 bytes_per_line=4*(image->columns);
1017 for (y=(ssize_t) image->rows-1; y >= 0; y--)
1018 {
1019 p=pixels+(image->rows-y-1)*bytes_per_line;
1020 for (x=0; x < (ssize_t) image->columns; x++)
1021 {
1022 if (*(p+3) != 0)
1023 {
1024 image->alpha_trait=BlendPixelTrait;
1025 y=-1;
1026 break;
1027 }
1028 p+=4;
1029 }
1030 }
1031 }
1032 bmp_info.alpha_mask=image->alpha_trait != UndefinedPixelTrait ?
1033 0xff000000U : 0U;
1034 bmp_info.red_mask=0x00ff0000U;
1035 bmp_info.green_mask=0x0000ff00U;
1036 bmp_info.blue_mask=0x000000ffU;
1037 if (bmp_info.bits_per_pixel == 16)
1038 {
1039 /*
1040 RGB555.
1041 */
1042 bmp_info.red_mask=0x00007c00U;
1043 bmp_info.green_mask=0x000003e0U;
1044 bmp_info.blue_mask=0x0000001fU;
1045 }
1046 }
1047 (void) memset(&shift,0,sizeof(shift));
1048 (void) memset(&quantum_bits,0,sizeof(quantum_bits));
1049 if ((bmp_info.bits_per_pixel == 16) || (bmp_info.bits_per_pixel == 32))
1050 {
1051 register unsigned int
1052 sample;
1053
1054 /*
1055 Get shift and quantum bits info from bitfield masks.
1056 */
1057 if (bmp_info.red_mask != 0)
1058 while (((bmp_info.red_mask << shift.red) & 0x80000000UL) == 0)
1059 {
1060 shift.red++;
1061 if (shift.red >= 32U)
1062 break;
1063 }
1064 if (bmp_info.green_mask != 0)
1065 while (((bmp_info.green_mask << shift.green) & 0x80000000UL) == 0)
1066 {
1067 shift.green++;
1068 if (shift.green >= 32U)
1069 break;
1070 }
1071 if (bmp_info.blue_mask != 0)
1072 while (((bmp_info.blue_mask << shift.blue) & 0x80000000UL) == 0)
1073 {
1074 shift.blue++;
1075 if (shift.blue >= 32U)
1076 break;
1077 }
1078 if (bmp_info.alpha_mask != 0)
1079 while (((bmp_info.alpha_mask << shift.alpha) & 0x80000000UL) == 0)
1080 {
1081 shift.alpha++;
1082 if (shift.alpha >= 32U)
1083 break;
1084 }
1085 sample=shift.red;
1086 while (((bmp_info.red_mask << sample) & 0x80000000UL) != 0)
1087 {
1088 sample++;
1089 if (sample >= 32U)
1090 break;
1091 }
1092 quantum_bits.red=(MagickRealType) (sample-shift.red);
1093 sample=shift.green;
1094 while (((bmp_info.green_mask << sample) & 0x80000000UL) != 0)
1095 {
1096 sample++;
1097 if (sample >= 32U)
1098 break;
1099 }
1100 quantum_bits.green=(MagickRealType) (sample-shift.green);
1101 sample=shift.blue;
1102 while (((bmp_info.blue_mask << sample) & 0x80000000UL) != 0)
1103 {
1104 sample++;
1105 if (sample >= 32U)
1106 break;
1107 }
1108 quantum_bits.blue=(MagickRealType) (sample-shift.blue);
1109 sample=shift.alpha;
1110 while (((bmp_info.alpha_mask << sample) & 0x80000000UL) != 0)
1111 {
1112 sample++;
1113 if (sample >= 32U)
1114 break;
1115 }
1116 quantum_bits.alpha=(MagickRealType) (sample-shift.alpha);
1117 }
1118 switch (bmp_info.bits_per_pixel)
1119 {
1120 case 1:
1121 {
1122 /*
1123 Convert bitmap scanline.
1124 */
1125 for (y=(ssize_t) image->rows-1; y >= 0; y--)
1126 {
1127 p=pixels+(image->rows-y-1)*bytes_per_line;
1128 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1129 if (q == (Quantum *) NULL)
1130 break;
1131 for (x=0; x < ((ssize_t) image->columns-7); x+=8)
1132 {
1133 for (bit=0; bit < 8; bit++)
1134 {
1135 index=(Quantum) (((*p) & (0x80 >> bit)) != 0 ? 0x01 : 0x00);
1136 SetPixelIndex(image,index,q);
1137 q+=GetPixelChannels(image);
1138 }
1139 p++;
1140 }
1141 if ((image->columns % 8) != 0)
1142 {
1143 for (bit=0; bit < (image->columns % 8); bit++)
1144 {
1145 index=(Quantum) (((*p) & (0x80 >> bit)) != 0 ? 0x01 : 0x00);
1146 SetPixelIndex(image,index,q);
1147 q+=GetPixelChannels(image);
1148 }
1149 p++;
1150 }
1151 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1152 break;
1153 if (image->previous == (Image *) NULL)
1154 {
1155 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
1156 (image->rows-y),image->rows);
1157 if (status == MagickFalse)
1158 break;
1159 }
1160 }
1161 (void) SyncImage(image,exception);
1162 break;
1163 }
1164 case 4:
1165 {
1166 /*
1167 Convert PseudoColor scanline.
1168 */
1169 for (y=(ssize_t) image->rows-1; y >= 0; y--)
1170 {
1171 p=pixels+(image->rows-y-1)*bytes_per_line;
1172 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1173 if (q == (Quantum *) NULL)
1174 break;
1175 for (x=0; x < ((ssize_t) image->columns-1); x+=2)
1176 {
1177 ValidateColormapValue(image,(ssize_t) ((*p >> 4) & 0x0f),&index,
1178 exception);
1179 SetPixelIndex(image,index,q);
1180 q+=GetPixelChannels(image);
1181 ValidateColormapValue(image,(ssize_t) (*p & 0x0f),&index,exception);
1182 SetPixelIndex(image,index,q);
1183 q+=GetPixelChannels(image);
1184 p++;
1185 }
1186 if ((image->columns % 2) != 0)
1187 {
1188 ValidateColormapValue(image,(ssize_t) ((*p >> 4) & 0xf),&index,
1189 exception);
1190 SetPixelIndex(image,index,q);
1191 q+=GetPixelChannels(image);
1192 p++;
1193 x++;
1194 }
1195 if (x < (ssize_t) image->columns)
1196 break;
1197 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1198 break;
1199 if (image->previous == (Image *) NULL)
1200 {
1201 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
1202 (image->rows-y),image->rows);
1203 if (status == MagickFalse)
1204 break;
1205 }
1206 }
1207 (void) SyncImage(image,exception);
1208 break;
1209 }
1210 case 8:
1211 {
1212 /*
1213 Convert PseudoColor scanline.
1214 */
1215 if ((bmp_info.compression == BI_RLE8) ||
1216 (bmp_info.compression == BI_RLE4))
1217 bytes_per_line=image->columns;
1218 for (y=(ssize_t) image->rows-1; y >= 0; y--)
1219 {
1220 p=pixels+(image->rows-y-1)*bytes_per_line;
1221 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1222 if (q == (Quantum *) NULL)
1223 break;
1224 for (x=(ssize_t) image->columns; x != 0; --x)
1225 {
1226 ValidateColormapValue(image,(ssize_t) *p++,&index,exception);
1227 SetPixelIndex(image,index,q);
1228 q+=GetPixelChannels(image);
1229 }
1230 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1231 break;
1232 offset=(MagickOffsetType) (image->rows-y-1);
1233 if (image->previous == (Image *) NULL)
1234 {
1235 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
1236 (image->rows-y),image->rows);
1237 if (status == MagickFalse)
1238 break;
1239 }
1240 }
1241 (void) SyncImage(image,exception);
1242 break;
1243 }
1244 case 16:
1245 {
1246 unsigned int
1247 alpha,
1248 pixel;
1249
1250 /*
1251 Convert bitfield encoded 16-bit PseudoColor scanline.
1252 */
1253 if ((bmp_info.compression != BI_RGB) &&
1254 (bmp_info.compression != BI_BITFIELDS))
1255 {
1256 pixel_info=RelinquishVirtualMemory(pixel_info);
1257 ThrowReaderException(CorruptImageError,
1258 "UnrecognizedImageCompression");
1259 }
1260 bytes_per_line=2*(image->columns+image->columns % 2);
1261 image->storage_class=DirectClass;
1262 for (y=(ssize_t) image->rows-1; y >= 0; y--)
1263 {
1264 p=pixels+(image->rows-y-1)*bytes_per_line;
1265 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1266 if (q == (Quantum *) NULL)
1267 break;
1268 for (x=0; x < (ssize_t) image->columns; x++)
1269 {
1270 pixel=(unsigned int) (*p++);
1271 pixel|=(*p++) << 8;
1272 red=((pixel & bmp_info.red_mask) << shift.red) >> 16;
1273 if (quantum_bits.red == 5)
1274 red|=((red & 0xe000) >> 5);
1275 if (quantum_bits.red <= 8)
1276 red|=((red & 0xff00) >> 8);
1277 green=((pixel & bmp_info.green_mask) << shift.green) >> 16;
1278 if (quantum_bits.green == 5)
1279 green|=((green & 0xe000) >> 5);
1280 if (quantum_bits.green == 6)
1281 green|=((green & 0xc000) >> 6);
1282 if (quantum_bits.green <= 8)
1283 green|=((green & 0xff00) >> 8);
1284 blue=((pixel & bmp_info.blue_mask) << shift.blue) >> 16;
1285 if (quantum_bits.blue == 5)
1286 blue|=((blue & 0xe000) >> 5);
1287 if (quantum_bits.blue <= 8)
1288 blue|=((blue & 0xff00) >> 8);
1289 SetPixelRed(image,ScaleShortToQuantum((unsigned short) red),q);
1290 SetPixelGreen(image,ScaleShortToQuantum((unsigned short) green),q);
1291 SetPixelBlue(image,ScaleShortToQuantum((unsigned short) blue),q);
1292 SetPixelAlpha(image,OpaqueAlpha,q);
1293 if (image->alpha_trait != UndefinedPixelTrait)
1294 {
1295 alpha=((pixel & bmp_info.alpha_mask) << shift.alpha) >> 16;
1296 if (quantum_bits.alpha <= 8)
1297 alpha|=((alpha & 0xff00) >> 8);
1298 SetPixelAlpha(image,ScaleShortToQuantum(
1299 (unsigned short) alpha),q);
1300 }
1301 q+=GetPixelChannels(image);
1302 }
1303 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1304 break;
1305 offset=(MagickOffsetType) (image->rows-y-1);
1306 if (image->previous == (Image *) NULL)
1307 {
1308 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
1309 (image->rows-y),image->rows);
1310 if (status == MagickFalse)
1311 break;
1312 }
1313 }
1314 break;
1315 }
1316 case 24:
1317 {
1318 /*
1319 Convert DirectColor scanline.
1320 */
1321 bytes_per_line=4*((image->columns*24+31)/32);
1322 for (y=(ssize_t) image->rows-1; y >= 0; y--)
1323 {
1324 p=pixels+(image->rows-y-1)*bytes_per_line;
1325 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1326 if (q == (Quantum *) NULL)
1327 break;
1328 for (x=0; x < (ssize_t) image->columns; x++)
1329 {
1330 SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
1331 SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
1332 SetPixelRed(image,ScaleCharToQuantum(*p++),q);
1333 SetPixelAlpha(image,OpaqueAlpha,q);
1334 q+=GetPixelChannels(image);
1335 }
1336 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1337 break;
1338 offset=(MagickOffsetType) (image->rows-y-1);
1339 if (image->previous == (Image *) NULL)
1340 {
1341 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
1342 (image->rows-y),image->rows);
1343 if (status == MagickFalse)
1344 break;
1345 }
1346 }
1347 break;
1348 }
1349 case 32:
1350 {
1351 /*
1352 Convert bitfield encoded DirectColor scanline.
1353 */
1354 if ((bmp_info.compression != BI_RGB) &&
1355 (bmp_info.compression != BI_BITFIELDS))
1356 {
1357 pixel_info=RelinquishVirtualMemory(pixel_info);
1358 ThrowReaderException(CorruptImageError,
1359 "UnrecognizedImageCompression");
1360 }
1361 bytes_per_line=4*(image->columns);
1362 for (y=(ssize_t) image->rows-1; y >= 0; y--)
1363 {
1364 unsigned int
1365 alpha,
1366 pixel;
1367
1368 p=pixels+(image->rows-y-1)*bytes_per_line;
1369 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1370 if (q == (Quantum *) NULL)
1371 break;
1372 for (x=0; x < (ssize_t) image->columns; x++)
1373 {
1374 pixel=(unsigned int) (*p++);
1375 pixel|=((unsigned int) *p++ << 8);
1376 pixel|=((unsigned int) *p++ << 16);
1377 pixel|=((unsigned int) *p++ << 24);
1378 red=((pixel & bmp_info.red_mask) << shift.red) >> 16;
1379 if (quantum_bits.red == 8)
1380 red|=(red >> 8);
1381 green=((pixel & bmp_info.green_mask) << shift.green) >> 16;
1382 if (quantum_bits.green == 8)
1383 green|=(green >> 8);
1384 blue=((pixel & bmp_info.blue_mask) << shift.blue) >> 16;
1385 if (quantum_bits.blue == 8)
1386 blue|=(blue >> 8);
1387 SetPixelRed(image,ScaleShortToQuantum((unsigned short) red),q);
1388 SetPixelGreen(image,ScaleShortToQuantum((unsigned short) green),q);
1389 SetPixelBlue(image,ScaleShortToQuantum((unsigned short) blue),q);
1390 SetPixelAlpha(image,OpaqueAlpha,q);
1391 if (image->alpha_trait != UndefinedPixelTrait)
1392 {
1393 alpha=((pixel & bmp_info.alpha_mask) << shift.alpha) >> 16;
1394 if (quantum_bits.alpha == 8)
1395 alpha|=(alpha >> 8);
1396 SetPixelAlpha(image,ScaleShortToQuantum(
1397 (unsigned short) alpha),q);
1398 }
1399 q+=GetPixelChannels(image);
1400 }
1401 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1402 break;
1403 offset=(MagickOffsetType) (image->rows-y-1);
1404 if (image->previous == (Image *) NULL)
1405 {
1406 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
1407 (image->rows-y),image->rows);
1408 if (status == MagickFalse)
1409 break;
1410 }
1411 }
1412 break;
1413 }
1414 default:
1415 {
1416 pixel_info=RelinquishVirtualMemory(pixel_info);
1417 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1418 }
1419 }
1420 pixel_info=RelinquishVirtualMemory(pixel_info);
1421 if (y > 0)
1422 break;
1423 if (EOFBlob(image) != MagickFalse)
1424 {
1425 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
1426 image->filename);
1427 break;
1428 }
1429 if (bmp_info.height < 0)
1430 {
1431 Image
1432 *flipped_image;
1433
1434 /*
1435 Correct image orientation.
1436 */
1437 flipped_image=FlipImage(image,exception);
1438 if (flipped_image != (Image *) NULL)
1439 {
1440 DuplicateBlob(flipped_image,image);
1441 ReplaceImageInList(&image, flipped_image);
1442 image=flipped_image;
1443 }
1444 }
1445 /*
1446 Read embeded ICC profile
1447 */
1448 if ((bmp_info.colorspace == 0x4D424544L) && (profile_data > 0) &&
1449 (profile_size > 0))
1450 {
1451 StringInfo
1452 *profile;
1453
1454 unsigned char
1455 *datum;
1456
1457 offset=start_position+14+profile_data;
1458 if ((offset < TellBlob(image)) ||
1459 (SeekBlob(image,offset,SEEK_SET) != offset) ||
1460 (GetBlobSize(image) < (MagickSizeType) (offset+profile_size)))
1461 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1462 profile=AcquireStringInfo((size_t) profile_size);
1463 if (profile == (StringInfo *) NULL)
1464 ThrowReaderException(CorruptImageError,"MemoryAllocationFailed");
1465 datum=GetStringInfoDatum(profile);
1466 if (ReadBlob(image,(size_t) profile_size,datum) == (ssize_t) profile_size)
1467 {
1468 MagickOffsetType
1469 profile_size_orig;
1470
1471 /*
1472 Trimming padded bytes.
1473 */
1474 profile_size_orig=(MagickOffsetType) datum[0] << 24;
1475 profile_size_orig|=(MagickOffsetType) datum[1] << 16;
1476 profile_size_orig|=(MagickOffsetType) datum[2] << 8;
1477 profile_size_orig|=(MagickOffsetType) datum[3];
1478 if (profile_size_orig < profile_size)
1479 SetStringInfoLength(profile,(size_t) profile_size_orig);
1480 if (image->debug != MagickFalse)
1481 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1482 "Profile: ICC, %u bytes",(unsigned int) profile_size_orig);
1483 (void) SetImageProfile(image,"icc",profile,exception);
1484 }
1485 profile=DestroyStringInfo(profile);
1486 }
1487 /*
1488 Proceed to next image.
1489 */
1490 if (image_info->number_scenes != 0)
1491 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1492 break;
1493 offset=(MagickOffsetType) bmp_info.ba_offset;
1494 if (offset != 0)
1495 if ((offset < TellBlob(image)) ||
1496 (SeekBlob(image,offset,SEEK_SET) != offset))
1497 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1498 *magick='\0';
1499 count=ReadBlob(image,2,magick);
1500 if ((count == 2) && (IsBMP(magick,2) != MagickFalse))
1501 {
1502 /*
1503 Acquire next image structure.
1504 */
1505 AcquireNextImage(image_info,image,exception);
1506 if (GetNextImageInList(image) == (Image *) NULL)
1507 {
1508 status=MagickFalse;
1509 return((Image *) NULL);
1510 }
1511 image=SyncNextImageInList(image);
1512 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
1513 GetBlobSize(image));
1514 if (status == MagickFalse)
1515 break;
1516 }
1517 } while (IsBMP(magick,2) != MagickFalse);
1518 (void) CloseBlob(image);
1519 if (status == MagickFalse)
1520 return(DestroyImageList(image));
1521 return(GetFirstImageInList(image));
1522 }
1523
1524 /*
1525 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1526 % %
1527 % %
1528 % %
1529 % R e g i s t e r B M P I m a g e %
1530 % %
1531 % %
1532 % %
1533 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1534 %
1535 % RegisterBMPImage() adds attributes for the BMP image format to
1536 % the list of supported formats. The attributes include the image format
1537 % tag, a method to read and/or write the format, whether the format
1538 % supports the saving of more than one frame to the same file or blob,
1539 % whether the format supports native in-memory I/O, and a brief
1540 % description of the format.
1541 %
1542 % The format of the RegisterBMPImage method is:
1543 %
1544 % size_t RegisterBMPImage(void)
1545 %
1546 */
RegisterBMPImage(void)1547 ModuleExport size_t RegisterBMPImage(void)
1548 {
1549 MagickInfo
1550 *entry;
1551
1552 entry=AcquireMagickInfo("BMP","BMP","Microsoft Windows bitmap image");
1553 entry->decoder=(DecodeImageHandler *) ReadBMPImage;
1554 entry->encoder=(EncodeImageHandler *) WriteBMPImage;
1555 entry->magick=(IsImageFormatHandler *) IsBMP;
1556 entry->flags^=CoderAdjoinFlag;
1557 entry->flags|=CoderDecoderSeekableStreamFlag;
1558 (void) RegisterMagickInfo(entry);
1559 entry=AcquireMagickInfo("BMP","BMP2","Microsoft Windows bitmap image (V2)");
1560 entry->decoder=(DecodeImageHandler *) ReadBMPImage;
1561 entry->encoder=(EncodeImageHandler *) WriteBMPImage;
1562 entry->magick=(IsImageFormatHandler *) IsBMP;
1563 entry->flags^=CoderAdjoinFlag;
1564 entry->flags|=CoderDecoderSeekableStreamFlag;
1565 (void) RegisterMagickInfo(entry);
1566 entry=AcquireMagickInfo("BMP","BMP3","Microsoft Windows bitmap image (V3)");
1567 entry->decoder=(DecodeImageHandler *) ReadBMPImage;
1568 entry->encoder=(EncodeImageHandler *) WriteBMPImage;
1569 entry->magick=(IsImageFormatHandler *) IsBMP;
1570 entry->flags^=CoderAdjoinFlag;
1571 entry->flags|=CoderDecoderSeekableStreamFlag;
1572 (void) RegisterMagickInfo(entry);
1573 return(MagickImageCoderSignature);
1574 }
1575
1576 /*
1577 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1578 % %
1579 % %
1580 % %
1581 % U n r e g i s t e r B M P I m a g e %
1582 % %
1583 % %
1584 % %
1585 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1586 %
1587 % UnregisterBMPImage() removes format registrations made by the
1588 % BMP module from the list of supported formats.
1589 %
1590 % The format of the UnregisterBMPImage method is:
1591 %
1592 % UnregisterBMPImage(void)
1593 %
1594 */
UnregisterBMPImage(void)1595 ModuleExport void UnregisterBMPImage(void)
1596 {
1597 (void) UnregisterMagickInfo("BMP");
1598 (void) UnregisterMagickInfo("BMP2");
1599 (void) UnregisterMagickInfo("BMP3");
1600 }
1601
1602 /*
1603 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1604 % %
1605 % %
1606 % %
1607 % W r i t e B M P I m a g e %
1608 % %
1609 % %
1610 % %
1611 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1612 %
1613 % WriteBMPImage() writes an image in Microsoft Windows bitmap encoded
1614 % image format, version 3 for Windows or (if the image has a matte channel)
1615 % version 4.
1616 %
1617 % The format of the WriteBMPImage method is:
1618 %
1619 % MagickBooleanType WriteBMPImage(const ImageInfo *image_info,
1620 % Image *image,ExceptionInfo *exception)
1621 %
1622 % A description of each parameter follows.
1623 %
1624 % o image_info: the image info.
1625 %
1626 % o image: The image.
1627 %
1628 % o exception: return any errors or warnings in this structure.
1629 %
1630 */
WriteBMPImage(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)1631 static MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image,
1632 ExceptionInfo *exception)
1633 {
1634 BMPInfo
1635 bmp_info;
1636
1637 BMPSubtype
1638 bmp_subtype;
1639
1640 const char
1641 *option;
1642
1643 const StringInfo
1644 *profile;
1645
1646 MagickBooleanType
1647 have_color_info,
1648 status;
1649
1650 MagickOffsetType
1651 scene;
1652
1653 MemoryInfo
1654 *pixel_info;
1655
1656 register const Quantum
1657 *p;
1658
1659 register ssize_t
1660 i,
1661 x;
1662
1663 register unsigned char
1664 *q;
1665
1666 size_t
1667 bytes_per_line,
1668 imageListLength,
1669 type;
1670
1671 ssize_t
1672 y;
1673
1674 unsigned char
1675 *bmp_data,
1676 *pixels;
1677
1678 MagickOffsetType
1679 profile_data,
1680 profile_size,
1681 profile_size_pad;
1682
1683 /*
1684 Open output image file.
1685 */
1686 assert(image_info != (const ImageInfo *) NULL);
1687 assert(image_info->signature == MagickCoreSignature);
1688 assert(image != (Image *) NULL);
1689 assert(image->signature == MagickCoreSignature);
1690 if (image->debug != MagickFalse)
1691 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1692 assert(exception != (ExceptionInfo *) NULL);
1693 assert(exception->signature == MagickCoreSignature);
1694 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1695 if (status == MagickFalse)
1696 return(status);
1697 type=4;
1698 if (LocaleCompare(image_info->magick,"BMP2") == 0)
1699 type=2;
1700 else
1701 if (LocaleCompare(image_info->magick,"BMP3") == 0)
1702 type=3;
1703 option=GetImageOption(image_info,"bmp:format");
1704 if (option != (char *) NULL)
1705 {
1706 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1707 " Format=%s",option);
1708 if (LocaleCompare(option,"bmp2") == 0)
1709 type=2;
1710 if (LocaleCompare(option,"bmp3") == 0)
1711 type=3;
1712 if (LocaleCompare(option,"bmp4") == 0)
1713 type=4;
1714 }
1715 scene=0;
1716 imageListLength=GetImageListLength(image);
1717 do
1718 {
1719 /*
1720 Initialize BMP raster file header.
1721 */
1722 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
1723 (void) TransformImageColorspace(image,sRGBColorspace,exception);
1724 (void) memset(&bmp_info,0,sizeof(bmp_info));
1725 bmp_info.file_size=14+12;
1726 if (type > 2)
1727 bmp_info.file_size+=28;
1728 bmp_info.offset_bits=bmp_info.file_size;
1729 bmp_info.compression=BI_RGB;
1730 bmp_info.red_mask=0x00ff0000U;
1731 bmp_info.green_mask=0x0000ff00U;
1732 bmp_info.blue_mask=0x000000ffU;
1733 bmp_info.alpha_mask=0xff000000U;
1734 bmp_subtype=UndefinedSubtype;
1735 if ((image->storage_class == PseudoClass) && (image->colors > 256))
1736 (void) SetImageStorageClass(image,DirectClass,exception);
1737 if (image->storage_class != DirectClass)
1738 {
1739 /*
1740 Colormapped BMP raster.
1741 */
1742 bmp_info.bits_per_pixel=8;
1743 if (image->colors <= 2)
1744 bmp_info.bits_per_pixel=1;
1745 else
1746 if (image->colors <= 16)
1747 bmp_info.bits_per_pixel=4;
1748 else
1749 if (image->colors <= 256)
1750 bmp_info.bits_per_pixel=8;
1751 if (image_info->compression == RLECompression)
1752 bmp_info.bits_per_pixel=8;
1753 bmp_info.number_colors=1U << bmp_info.bits_per_pixel;
1754 if (image->alpha_trait != UndefinedPixelTrait)
1755 (void) SetImageStorageClass(image,DirectClass,exception);
1756 else
1757 if ((size_t) bmp_info.number_colors < image->colors)
1758 (void) SetImageStorageClass(image,DirectClass,exception);
1759 else
1760 {
1761 bmp_info.file_size+=3*(1UL << bmp_info.bits_per_pixel);
1762 bmp_info.offset_bits+=3*(1UL << bmp_info.bits_per_pixel);
1763 if (type > 2)
1764 {
1765 bmp_info.file_size+=(1UL << bmp_info.bits_per_pixel);
1766 bmp_info.offset_bits+=(1UL << bmp_info.bits_per_pixel);
1767 }
1768 }
1769 }
1770 if (image->storage_class == DirectClass)
1771 {
1772 /*
1773 Full color BMP raster.
1774 */
1775 bmp_info.number_colors=0;
1776 option=GetImageOption(image_info,"bmp:subtype");
1777 if (option != (const char *) NULL)
1778 {
1779 if (image->alpha_trait != UndefinedPixelTrait)
1780 {
1781 if (LocaleNCompare(option,"ARGB4444",8) == 0)
1782 {
1783 bmp_subtype=ARGB4444;
1784 bmp_info.red_mask=0x00000f00U;
1785 bmp_info.green_mask=0x000000f0U;
1786 bmp_info.blue_mask=0x0000000fU;
1787 bmp_info.alpha_mask=0x0000f000U;
1788 }
1789 else if (LocaleNCompare(option,"ARGB1555",8) == 0)
1790 {
1791 bmp_subtype=ARGB1555;
1792 bmp_info.red_mask=0x00007c00U;
1793 bmp_info.green_mask=0x000003e0U;
1794 bmp_info.blue_mask=0x0000001fU;
1795 bmp_info.alpha_mask=0x00008000U;
1796 }
1797 }
1798 else
1799 {
1800 if (LocaleNCompare(option,"RGB555",6) == 0)
1801 {
1802 bmp_subtype=RGB555;
1803 bmp_info.red_mask=0x00007c00U;
1804 bmp_info.green_mask=0x000003e0U;
1805 bmp_info.blue_mask=0x0000001fU;
1806 bmp_info.alpha_mask=0U;
1807 }
1808 else if (LocaleNCompare(option,"RGB565",6) == 0)
1809 {
1810 bmp_subtype=RGB565;
1811 bmp_info.red_mask=0x0000f800U;
1812 bmp_info.green_mask=0x000007e0U;
1813 bmp_info.blue_mask=0x0000001fU;
1814 bmp_info.alpha_mask=0U;
1815 }
1816 }
1817 }
1818 if (bmp_subtype != UndefinedSubtype)
1819 {
1820 bmp_info.bits_per_pixel=16;
1821 bmp_info.compression=BI_BITFIELDS;
1822 }
1823 else
1824 {
1825 bmp_info.bits_per_pixel=(unsigned short) ((type > 3) &&
1826 (image->alpha_trait != UndefinedPixelTrait) ? 32 : 24);
1827 bmp_info.compression=(unsigned int) ((type > 3) &&
1828 (image->alpha_trait != UndefinedPixelTrait) ? BI_BITFIELDS : BI_RGB);
1829 if ((type == 3) && (image->alpha_trait != UndefinedPixelTrait))
1830 {
1831 option=GetImageOption(image_info,"bmp3:alpha");
1832 if (IsStringTrue(option))
1833 bmp_info.bits_per_pixel=32;
1834 }
1835 }
1836 }
1837 bytes_per_line=4*((image->columns*bmp_info.bits_per_pixel+31)/32);
1838 bmp_info.ba_offset=0;
1839 profile=GetImageProfile(image,"icc");
1840 have_color_info=(image->rendering_intent != UndefinedIntent) ||
1841 (profile != (StringInfo *) NULL) || (image->gamma != 0.0) ? MagickTrue :
1842 MagickFalse;
1843 if (type == 2)
1844 bmp_info.size=12;
1845 else
1846 if ((type == 3) || ((image->alpha_trait == UndefinedPixelTrait) &&
1847 (have_color_info == MagickFalse)))
1848 {
1849 type=3;
1850 bmp_info.size=40;
1851 }
1852 else
1853 {
1854 int
1855 extra_size;
1856
1857 bmp_info.size=108;
1858 extra_size=68;
1859 if ((image->rendering_intent != UndefinedIntent) ||
1860 (profile != (StringInfo *) NULL))
1861 {
1862 bmp_info.size=124;
1863 extra_size+=16;
1864 }
1865 bmp_info.file_size+=extra_size;
1866 bmp_info.offset_bits+=extra_size;
1867 }
1868 if (((ssize_t) image->columns != (ssize_t) ((signed int) image->columns)) ||
1869 ((ssize_t) image->rows != (ssize_t) ((signed int) image->rows)))
1870 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
1871 bmp_info.width=(ssize_t) image->columns;
1872 bmp_info.height=(ssize_t) image->rows;
1873 bmp_info.planes=1;
1874 bmp_info.image_size=(unsigned int) (bytes_per_line*image->rows);
1875 bmp_info.file_size+=bmp_info.image_size;
1876 bmp_info.x_pixels=75*39;
1877 bmp_info.y_pixels=75*39;
1878 switch (image->units)
1879 {
1880 case UndefinedResolution:
1881 case PixelsPerInchResolution:
1882 {
1883 bmp_info.x_pixels=(unsigned int) (100.0*image->resolution.x/2.54);
1884 bmp_info.y_pixels=(unsigned int) (100.0*image->resolution.y/2.54);
1885 break;
1886 }
1887 case PixelsPerCentimeterResolution:
1888 {
1889 bmp_info.x_pixels=(unsigned int) (100.0*image->resolution.x);
1890 bmp_info.y_pixels=(unsigned int) (100.0*image->resolution.y);
1891 break;
1892 }
1893 }
1894 bmp_info.colors_important=bmp_info.number_colors;
1895 /*
1896 Convert MIFF to BMP raster pixels.
1897 */
1898 pixel_info=AcquireVirtualMemory(image->rows,MagickMax(bytes_per_line,
1899 image->columns+256UL)*sizeof(*pixels));
1900 if (pixel_info == (MemoryInfo *) NULL)
1901 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1902 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
1903 (void) memset(pixels,0,(size_t) bmp_info.image_size);
1904 switch (bmp_info.bits_per_pixel)
1905 {
1906 case 1:
1907 {
1908 size_t
1909 bit,
1910 byte;
1911
1912 /*
1913 Convert PseudoClass image to a BMP monochrome image.
1914 */
1915 for (y=0; y < (ssize_t) image->rows; y++)
1916 {
1917 ssize_t
1918 offset;
1919
1920 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1921 if (p == (const Quantum *) NULL)
1922 break;
1923 q=pixels+(image->rows-y-1)*bytes_per_line;
1924 bit=0;
1925 byte=0;
1926 for (x=0; x < (ssize_t) image->columns; x++)
1927 {
1928 byte<<=1;
1929 byte|=GetPixelIndex(image,p) != 0 ? 0x01 : 0x00;
1930 bit++;
1931 if (bit == 8)
1932 {
1933 *q++=(unsigned char) byte;
1934 bit=0;
1935 byte=0;
1936 }
1937 p+=GetPixelChannels(image);
1938 }
1939 if (bit != 0)
1940 {
1941 *q++=(unsigned char) (byte << (8-bit));
1942 x++;
1943 }
1944 offset=(ssize_t) (image->columns+7)/8;
1945 for (x=offset; x < (ssize_t) bytes_per_line; x++)
1946 *q++=0x00;
1947 if (image->previous == (Image *) NULL)
1948 {
1949 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1950 image->rows);
1951 if (status == MagickFalse)
1952 break;
1953 }
1954 }
1955 break;
1956 }
1957 case 4:
1958 {
1959 unsigned int
1960 byte,
1961 nibble;
1962
1963 ssize_t
1964 offset;
1965
1966 /*
1967 Convert PseudoClass image to a BMP monochrome image.
1968 */
1969 for (y=0; y < (ssize_t) image->rows; y++)
1970 {
1971 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1972 if (p == (const Quantum *) NULL)
1973 break;
1974 q=pixels+(image->rows-y-1)*bytes_per_line;
1975 nibble=0;
1976 byte=0;
1977 for (x=0; x < (ssize_t) image->columns; x++)
1978 {
1979 byte<<=4;
1980 byte|=((unsigned int) GetPixelIndex(image,p) & 0x0f);
1981 nibble++;
1982 if (nibble == 2)
1983 {
1984 *q++=(unsigned char) byte;
1985 nibble=0;
1986 byte=0;
1987 }
1988 p+=GetPixelChannels(image);
1989 }
1990 if (nibble != 0)
1991 {
1992 *q++=(unsigned char) (byte << 4);
1993 x++;
1994 }
1995 offset=(ssize_t) (image->columns+1)/2;
1996 for (x=offset; x < (ssize_t) bytes_per_line; x++)
1997 *q++=0x00;
1998 if (image->previous == (Image *) NULL)
1999 {
2000 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2001 image->rows);
2002 if (status == MagickFalse)
2003 break;
2004 }
2005 }
2006 break;
2007 }
2008 case 8:
2009 {
2010 /*
2011 Convert PseudoClass packet to BMP pixel.
2012 */
2013 for (y=0; y < (ssize_t) image->rows; y++)
2014 {
2015 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2016 if (p == (const Quantum *) NULL)
2017 break;
2018 q=pixels+(image->rows-y-1)*bytes_per_line;
2019 for (x=0; x < (ssize_t) image->columns; x++)
2020 {
2021 *q++=(unsigned char) GetPixelIndex(image,p);
2022 p+=GetPixelChannels(image);
2023 }
2024 for ( ; x < (ssize_t) bytes_per_line; x++)
2025 *q++=0x00;
2026 if (image->previous == (Image *) NULL)
2027 {
2028 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2029 image->rows);
2030 if (status == MagickFalse)
2031 break;
2032 }
2033 }
2034 break;
2035 }
2036 case 16:
2037 {
2038 /*
2039 Convert DirectClass packet to BMP BGR888.
2040 */
2041 for (y=0; y < (ssize_t) image->rows; y++)
2042 {
2043 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2044 if (p == (const Quantum *) NULL)
2045 break;
2046 q=pixels+(image->rows-y-1)*bytes_per_line;
2047 for (x=0; x < (ssize_t) image->columns; x++)
2048 {
2049 unsigned short
2050 pixel;
2051
2052 pixel=0;
2053 if (bmp_subtype == ARGB4444)
2054 {
2055 pixel=(unsigned short) (ScaleQuantumToAny(
2056 GetPixelAlpha(image,p),15) << 12);
2057 pixel|=(unsigned short) (ScaleQuantumToAny(
2058 GetPixelRed(image,p),15) << 8);
2059 pixel|=(unsigned short) (ScaleQuantumToAny(
2060 GetPixelGreen(image,p),15) << 4);
2061 pixel|=(unsigned short) (ScaleQuantumToAny(
2062 GetPixelBlue(image,p),15));
2063 }
2064 else if (bmp_subtype == RGB565)
2065 {
2066 pixel=(unsigned short) (ScaleQuantumToAny(
2067 GetPixelRed(image,p),31) << 11);
2068 pixel|=(unsigned short) (ScaleQuantumToAny(
2069 GetPixelGreen(image,p),63) << 5);
2070 pixel|=(unsigned short) (ScaleQuantumToAny(
2071 GetPixelBlue(image,p),31));
2072 }
2073 else
2074 {
2075 if (bmp_subtype == ARGB1555)
2076 pixel=(unsigned short) (ScaleQuantumToAny(
2077 GetPixelAlpha(image,p),1) << 15);
2078 pixel|=(unsigned short) (ScaleQuantumToAny(
2079 GetPixelRed(image,p),31) << 10);
2080 pixel|=(unsigned short) (ScaleQuantumToAny(
2081 GetPixelGreen(image,p),31) << 5);
2082 pixel|=(unsigned short) (ScaleQuantumToAny(
2083 GetPixelBlue(image,p),31));
2084 }
2085 *((unsigned short *) q)=pixel;
2086 q+=2;
2087 p+=GetPixelChannels(image);
2088 }
2089 for (x=2L*(ssize_t) image->columns; x < (ssize_t) bytes_per_line; x++)
2090 *q++=0x00;
2091 if (image->previous == (Image *) NULL)
2092 {
2093 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2094 image->rows);
2095 if (status == MagickFalse)
2096 break;
2097 }
2098 }
2099 break;
2100 }
2101 case 24:
2102 {
2103 /*
2104 Convert DirectClass packet to BMP BGR888.
2105 */
2106 for (y=0; y < (ssize_t) image->rows; y++)
2107 {
2108 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2109 if (p == (const Quantum *) NULL)
2110 break;
2111 q=pixels+(image->rows-y-1)*bytes_per_line;
2112 for (x=0; x < (ssize_t) image->columns; x++)
2113 {
2114 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
2115 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
2116 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
2117 p+=GetPixelChannels(image);
2118 }
2119 for (x=3L*(ssize_t) image->columns; x < (ssize_t) bytes_per_line; x++)
2120 *q++=0x00;
2121 if (image->previous == (Image *) NULL)
2122 {
2123 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2124 image->rows);
2125 if (status == MagickFalse)
2126 break;
2127 }
2128 }
2129 break;
2130 }
2131 case 32:
2132 {
2133 /*
2134 Convert DirectClass packet to ARGB8888 pixel.
2135 */
2136 for (y=0; y < (ssize_t) image->rows; y++)
2137 {
2138 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2139 if (p == (const Quantum *) NULL)
2140 break;
2141 q=pixels+(image->rows-y-1)*bytes_per_line;
2142 for (x=0; x < (ssize_t) image->columns; x++)
2143 {
2144 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
2145 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
2146 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
2147 *q++=ScaleQuantumToChar(GetPixelAlpha(image,p));
2148 p+=GetPixelChannels(image);
2149 }
2150 if (image->previous == (Image *) NULL)
2151 {
2152 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2153 image->rows);
2154 if (status == MagickFalse)
2155 break;
2156 }
2157 }
2158 break;
2159 }
2160 }
2161 if ((type > 2) && (bmp_info.bits_per_pixel == 8))
2162 if (image_info->compression != NoCompression)
2163 {
2164 MemoryInfo
2165 *rle_info;
2166
2167 /*
2168 Convert run-length encoded raster pixels.
2169 */
2170 rle_info=AcquireVirtualMemory((size_t) (2*(bytes_per_line+2)+2),
2171 (image->rows+2)*sizeof(*pixels));
2172 if (rle_info == (MemoryInfo *) NULL)
2173 {
2174 pixel_info=RelinquishVirtualMemory(pixel_info);
2175 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2176 }
2177 bmp_data=(unsigned char *) GetVirtualMemoryBlob(rle_info);
2178 bmp_info.file_size-=bmp_info.image_size;
2179 bmp_info.image_size=(unsigned int) EncodeImage(image,bytes_per_line,
2180 pixels,bmp_data);
2181 bmp_info.file_size+=bmp_info.image_size;
2182 pixel_info=RelinquishVirtualMemory(pixel_info);
2183 pixel_info=rle_info;
2184 pixels=bmp_data;
2185 bmp_info.compression=BI_RLE8;
2186 }
2187 /*
2188 Write BMP for Windows, all versions, 14-byte header.
2189 */
2190 if (image->debug != MagickFalse)
2191 {
2192 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2193 " Writing BMP version %.20g datastream",(double) type);
2194 if (image->storage_class == DirectClass)
2195 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2196 " Storage class=DirectClass");
2197 else
2198 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2199 " Storage class=PseudoClass");
2200 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2201 " Image depth=%.20g",(double) image->depth);
2202 if (image->alpha_trait != UndefinedPixelTrait)
2203 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2204 " Matte=True");
2205 else
2206 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2207 " Matte=MagickFalse");
2208 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2209 " BMP bits_per_pixel=%.20g",(double) bmp_info.bits_per_pixel);
2210 switch ((int) bmp_info.compression)
2211 {
2212 case BI_RGB:
2213 {
2214 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2215 " Compression=BI_RGB");
2216 break;
2217 }
2218 case BI_RLE8:
2219 {
2220 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2221 " Compression=BI_RLE8");
2222 break;
2223 }
2224 case BI_BITFIELDS:
2225 {
2226 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2227 " Compression=BI_BITFIELDS");
2228 break;
2229 }
2230 default:
2231 {
2232 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2233 " Compression=UNKNOWN (%u)",bmp_info.compression);
2234 break;
2235 }
2236 }
2237 if (bmp_info.number_colors == 0)
2238 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2239 " Number_colors=unspecified");
2240 else
2241 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2242 " Number_colors=%u",bmp_info.number_colors);
2243 }
2244 profile_data=0;
2245 profile_size=0;
2246 profile_size_pad=0;
2247 if (profile != (StringInfo *) NULL)
2248 {
2249 profile_data=(MagickOffsetType) bmp_info.file_size-14; /* from head of BMP info header */
2250 profile_size=(MagickOffsetType) GetStringInfoLength(profile);
2251 if ((profile_size % 4) > 0)
2252 profile_size_pad=4-(profile_size%4);
2253 bmp_info.file_size+=profile_size+profile_size_pad;
2254 }
2255 (void) WriteBlob(image,2,(unsigned char *) "BM");
2256 (void) WriteBlobLSBLong(image,bmp_info.file_size);
2257 (void) WriteBlobLSBLong(image,bmp_info.ba_offset); /* always 0 */
2258 (void) WriteBlobLSBLong(image,bmp_info.offset_bits);
2259 if (type == 2)
2260 {
2261 /*
2262 Write 12-byte version 2 bitmap header.
2263 */
2264 (void) WriteBlobLSBLong(image,bmp_info.size);
2265 (void) WriteBlobLSBSignedShort(image,(signed short) bmp_info.width);
2266 (void) WriteBlobLSBSignedShort(image,(signed short) bmp_info.height);
2267 (void) WriteBlobLSBShort(image,bmp_info.planes);
2268 (void) WriteBlobLSBShort(image,bmp_info.bits_per_pixel);
2269 }
2270 else
2271 {
2272 /*
2273 Write 40-byte version 3+ bitmap header.
2274 */
2275 (void) WriteBlobLSBLong(image,bmp_info.size);
2276 (void) WriteBlobLSBSignedLong(image,(signed int) bmp_info.width);
2277 (void) WriteBlobLSBSignedLong(image,(signed int) bmp_info.height);
2278 (void) WriteBlobLSBShort(image,bmp_info.planes);
2279 (void) WriteBlobLSBShort(image,bmp_info.bits_per_pixel);
2280 (void) WriteBlobLSBLong(image,bmp_info.compression);
2281 (void) WriteBlobLSBLong(image,bmp_info.image_size);
2282 (void) WriteBlobLSBLong(image,bmp_info.x_pixels);
2283 (void) WriteBlobLSBLong(image,bmp_info.y_pixels);
2284 (void) WriteBlobLSBLong(image,bmp_info.number_colors);
2285 (void) WriteBlobLSBLong(image,bmp_info.colors_important);
2286 }
2287 if ((type > 3) && ((image->alpha_trait != UndefinedPixelTrait) ||
2288 (have_color_info != MagickFalse)))
2289 {
2290 /*
2291 Write the rest of the 108-byte BMP Version 4 header.
2292 */
2293 (void) WriteBlobLSBLong(image,bmp_info.red_mask);
2294 (void) WriteBlobLSBLong(image,bmp_info.green_mask);
2295 (void) WriteBlobLSBLong(image,bmp_info.blue_mask);
2296 (void) WriteBlobLSBLong(image,bmp_info.alpha_mask);
2297 if (profile != (StringInfo *) NULL)
2298 (void) WriteBlobLSBLong(image,0x4D424544U); /* PROFILE_EMBEDDED */
2299 else
2300 (void) WriteBlobLSBLong(image,0x73524742U); /* sRGB */
2301 (void) WriteBlobLSBLong(image,(unsigned int)
2302 (image->chromaticity.red_primary.x*0x40000000));
2303 (void) WriteBlobLSBLong(image,(unsigned int)
2304 (image->chromaticity.red_primary.y*0x40000000));
2305 (void) WriteBlobLSBLong(image,(unsigned int)
2306 ((1.000f-(image->chromaticity.red_primary.x+
2307 image->chromaticity.red_primary.y))*0x40000000));
2308 (void) WriteBlobLSBLong(image,(unsigned int)
2309 (image->chromaticity.green_primary.x*0x40000000));
2310 (void) WriteBlobLSBLong(image,(unsigned int)
2311 (image->chromaticity.green_primary.y*0x40000000));
2312 (void) WriteBlobLSBLong(image,(unsigned int)
2313 ((1.000f-(image->chromaticity.green_primary.x+
2314 image->chromaticity.green_primary.y))*0x40000000));
2315 (void) WriteBlobLSBLong(image,(unsigned int)
2316 (image->chromaticity.blue_primary.x*0x40000000));
2317 (void) WriteBlobLSBLong(image,(unsigned int)
2318 (image->chromaticity.blue_primary.y*0x40000000));
2319 (void) WriteBlobLSBLong(image,(unsigned int)
2320 ((1.000f-(image->chromaticity.blue_primary.x+
2321 image->chromaticity.blue_primary.y))*0x40000000));
2322 (void) WriteBlobLSBLong(image,(unsigned int)
2323 (bmp_info.gamma_scale.x*0x10000));
2324 (void) WriteBlobLSBLong(image,(unsigned int)
2325 (bmp_info.gamma_scale.y*0x10000));
2326 (void) WriteBlobLSBLong(image,(unsigned int)
2327 (bmp_info.gamma_scale.z*0x10000));
2328 if ((image->rendering_intent != UndefinedIntent) ||
2329 (profile != (StringInfo *) NULL))
2330 {
2331 ssize_t
2332 intent;
2333
2334 switch ((int) image->rendering_intent)
2335 {
2336 case SaturationIntent:
2337 {
2338 intent=LCS_GM_BUSINESS;
2339 break;
2340 }
2341 case RelativeIntent:
2342 {
2343 intent=LCS_GM_GRAPHICS;
2344 break;
2345 }
2346 case PerceptualIntent:
2347 {
2348 intent=LCS_GM_IMAGES;
2349 break;
2350 }
2351 case AbsoluteIntent:
2352 {
2353 intent=LCS_GM_ABS_COLORIMETRIC;
2354 break;
2355 }
2356 default:
2357 {
2358 intent=0;
2359 break;
2360 }
2361 }
2362 (void) WriteBlobLSBLong(image,(unsigned int) intent);
2363 (void) WriteBlobLSBLong(image,(unsigned int) profile_data);
2364 (void) WriteBlobLSBLong(image,(unsigned int)
2365 (profile_size+profile_size_pad));
2366 (void) WriteBlobLSBLong(image,0x00); /* reserved */
2367 }
2368 }
2369 if (image->storage_class == PseudoClass)
2370 {
2371 unsigned char
2372 *bmp_colormap;
2373
2374 /*
2375 Dump colormap to file.
2376 */
2377 if (image->debug != MagickFalse)
2378 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2379 " Colormap: %.20g entries",(double) image->colors);
2380 bmp_colormap=(unsigned char *) AcquireQuantumMemory((size_t) (1UL <<
2381 bmp_info.bits_per_pixel),4*sizeof(*bmp_colormap));
2382 if (bmp_colormap == (unsigned char *) NULL)
2383 {
2384 pixel_info=RelinquishVirtualMemory(pixel_info);
2385 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2386 }
2387 q=bmp_colormap;
2388 for (i=0; i < (ssize_t) MagickMin((ssize_t) image->colors,(ssize_t) bmp_info.number_colors); i++)
2389 {
2390 *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].blue));
2391 *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].green));
2392 *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].red));
2393 if (type > 2)
2394 *q++=(unsigned char) 0x0;
2395 }
2396 for ( ; i < (ssize_t) (1UL << bmp_info.bits_per_pixel); i++)
2397 {
2398 *q++=(unsigned char) 0x00;
2399 *q++=(unsigned char) 0x00;
2400 *q++=(unsigned char) 0x00;
2401 if (type > 2)
2402 *q++=(unsigned char) 0x00;
2403 }
2404 if (type <= 2)
2405 (void) WriteBlob(image,(size_t) (3*(1L << bmp_info.bits_per_pixel)),
2406 bmp_colormap);
2407 else
2408 (void) WriteBlob(image,(size_t) (4*(1L << bmp_info.bits_per_pixel)),
2409 bmp_colormap);
2410 bmp_colormap=(unsigned char *) RelinquishMagickMemory(bmp_colormap);
2411 }
2412 if (image->debug != MagickFalse)
2413 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2414 " Pixels: %u bytes",bmp_info.image_size);
2415 (void) WriteBlob(image,(size_t) bmp_info.image_size,pixels);
2416 if (profile != (StringInfo *) NULL)
2417 {
2418 if (image->debug != MagickFalse)
2419 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2420 " Profile: %g bytes",(double) profile_size+profile_size_pad);
2421 (void) WriteBlob(image,(size_t) profile_size,GetStringInfoDatum(profile));
2422 if (profile_size_pad > 0) /* padding for 4 bytes multiple */
2423 (void) WriteBlob(image,(size_t) profile_size_pad,"\0\0\0");
2424 }
2425 pixel_info=RelinquishVirtualMemory(pixel_info);
2426 if (GetNextImageInList(image) == (Image *) NULL)
2427 break;
2428 image=SyncNextImageInList(image);
2429 status=SetImageProgress(image,SaveImagesTag,scene++,imageListLength);
2430 if (status == MagickFalse)
2431 break;
2432 } while (image_info->adjoin != MagickFalse);
2433 (void) CloseBlob(image);
2434 return(MagickTrue);
2435 }
2436