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-2021 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 ssize_t
210 i,
211 x;
212
213 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 const unsigned char
387 *p;
388
389 ssize_t
390 i,
391 x;
392
393 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 MagickSizeType
528 blob_size;
529
530 MemoryInfo
531 *pixel_info;
532
533 Quantum
534 index;
535
536 Quantum
537 *q;
538
539 ssize_t
540 i,
541 x;
542
543 unsigned char
544 *p;
545
546 size_t
547 bit,
548 bytes_per_line,
549 length;
550
551 ssize_t
552 count,
553 y;
554
555 unsigned char
556 magick[12],
557 *pixels;
558
559 unsigned int
560 blue,
561 green,
562 offset_bits,
563 red;
564
565 /*
566 Open image file.
567 */
568 assert(image_info != (const ImageInfo *) NULL);
569 assert(image_info->signature == MagickCoreSignature);
570 if (image_info->debug != MagickFalse)
571 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
572 image_info->filename);
573 assert(exception != (ExceptionInfo *) NULL);
574 assert(exception->signature == MagickCoreSignature);
575 image=AcquireImage(image_info,exception);
576 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
577 if (status == MagickFalse)
578 {
579 image=DestroyImageList(image);
580 return((Image *) NULL);
581 }
582 /*
583 Determine if this a BMP file.
584 */
585 (void) memset(&bmp_info,0,sizeof(bmp_info));
586 bmp_info.ba_offset=0;
587 start_position=0;
588 offset_bits=0;
589 count=ReadBlob(image,2,magick);
590 if (count != 2)
591 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
592 blob_size=GetBlobSize(image);
593 do
594 {
595 PixelInfo
596 quantum_bits;
597
598 PixelPacket
599 shift;
600
601 /*
602 Verify BMP identifier.
603 */
604 start_position=TellBlob(image)-2;
605 bmp_info.ba_offset=0;
606 while (LocaleNCompare((char *) magick,"BA",2) == 0)
607 {
608 bmp_info.file_size=ReadBlobLSBLong(image);
609 bmp_info.ba_offset=ReadBlobLSBLong(image);
610 bmp_info.offset_bits=ReadBlobLSBLong(image);
611 count=ReadBlob(image,2,magick);
612 if (count != 2)
613 break;
614 }
615 if (image->debug != MagickFalse)
616 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Magick: %c%c",
617 magick[0],magick[1]);
618 if ((count != 2) || ((LocaleNCompare((char *) magick,"BM",2) != 0) &&
619 (LocaleNCompare((char *) magick,"CI",2) != 0)))
620 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
621 bmp_info.file_size=ReadBlobLSBLong(image);
622 (void) ReadBlobLSBLong(image);
623 bmp_info.offset_bits=ReadBlobLSBLong(image);
624 bmp_info.size=ReadBlobLSBLong(image);
625 if (image->debug != MagickFalse)
626 (void) LogMagickEvent(CoderEvent,GetMagickModule()," BMP size: %u",
627 bmp_info.size);
628 profile_data=0;
629 profile_size=0;
630 if (bmp_info.size == 12)
631 {
632 /*
633 OS/2 BMP image file.
634 */
635 (void) CopyMagickString(image->magick,"BMP2",MagickPathExtent);
636 bmp_info.width=(ssize_t) ((short) ReadBlobLSBShort(image));
637 bmp_info.height=(ssize_t) ((short) ReadBlobLSBShort(image));
638 bmp_info.planes=ReadBlobLSBShort(image);
639 bmp_info.bits_per_pixel=ReadBlobLSBShort(image);
640 bmp_info.x_pixels=0;
641 bmp_info.y_pixels=0;
642 bmp_info.number_colors=0;
643 bmp_info.compression=BI_RGB;
644 bmp_info.image_size=0;
645 bmp_info.alpha_mask=0;
646 if (image->debug != MagickFalse)
647 {
648 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
649 " Format: OS/2 Bitmap");
650 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
651 " Geometry: %.20gx%.20g",(double) bmp_info.width,(double)
652 bmp_info.height);
653 }
654 }
655 else
656 {
657 /*
658 Microsoft Windows BMP image file.
659 */
660 bmp_info.width=(ssize_t) ReadBlobLSBSignedLong(image);
661 bmp_info.height=(ssize_t) ReadBlobLSBSignedLong(image);
662 bmp_info.planes=ReadBlobLSBShort(image);
663 bmp_info.bits_per_pixel=ReadBlobLSBShort(image);
664 bmp_info.compression=ReadBlobLSBLong(image);
665 if (bmp_info.size > 16)
666 {
667 bmp_info.image_size=ReadBlobLSBLong(image);
668 bmp_info.x_pixels=ReadBlobLSBLong(image);
669 bmp_info.y_pixels=ReadBlobLSBLong(image);
670 bmp_info.number_colors=ReadBlobLSBLong(image);
671 if ((MagickSizeType) bmp_info.number_colors > blob_size)
672 ThrowReaderException(CorruptImageError,
673 "InsufficientImageDataInFile");
674 bmp_info.colors_important=ReadBlobLSBLong(image);
675 }
676 if (image->debug != MagickFalse)
677 {
678 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
679 " Format: MS Windows bitmap");
680 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
681 " Geometry: %.20gx%.20g",(double) bmp_info.width,(double)
682 bmp_info.height);
683 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
684 " Bits per pixel: %.20g",(double) bmp_info.bits_per_pixel);
685 switch (bmp_info.compression)
686 {
687 case BI_RGB:
688 {
689 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
690 " Compression: BI_RGB");
691 break;
692 }
693 case BI_RLE4:
694 {
695 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
696 " Compression: BI_RLE4");
697 break;
698 }
699 case BI_RLE8:
700 {
701 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
702 " Compression: BI_RLE8");
703 break;
704 }
705 case BI_BITFIELDS:
706 {
707 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
708 " Compression: BI_BITFIELDS");
709 break;
710 }
711 case BI_PNG:
712 {
713 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
714 " Compression: BI_PNG");
715 break;
716 }
717 case BI_JPEG:
718 {
719 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
720 " Compression: BI_JPEG");
721 break;
722 }
723 default:
724 {
725 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
726 " Compression: UNKNOWN (%u)",bmp_info.compression);
727 }
728 }
729 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
730 " Number of colors: %u",bmp_info.number_colors);
731 }
732 if ((bmp_info.size > 40) || (bmp_info.compression == BI_BITFIELDS))
733 {
734 bmp_info.red_mask=ReadBlobLSBLong(image);
735 bmp_info.green_mask=ReadBlobLSBLong(image);
736 bmp_info.blue_mask=ReadBlobLSBLong(image);
737 }
738 if (bmp_info.size > 40)
739 {
740 double
741 gamma;
742
743 /*
744 Read color management information.
745 */
746 bmp_info.alpha_mask=ReadBlobLSBLong(image);
747 bmp_info.colorspace=ReadBlobLSBSignedLong(image);
748 /*
749 Decode 2^30 fixed point formatted CIE primaries.
750 */
751 # define BMP_DENOM ((double) 0x40000000)
752 bmp_info.red_primary.x=(double) ReadBlobLSBLong(image)/BMP_DENOM;
753 bmp_info.red_primary.y=(double) ReadBlobLSBLong(image)/BMP_DENOM;
754 bmp_info.red_primary.z=(double) ReadBlobLSBLong(image)/BMP_DENOM;
755 bmp_info.green_primary.x=(double) ReadBlobLSBLong(image)/BMP_DENOM;
756 bmp_info.green_primary.y=(double) ReadBlobLSBLong(image)/BMP_DENOM;
757 bmp_info.green_primary.z=(double) ReadBlobLSBLong(image)/BMP_DENOM;
758 bmp_info.blue_primary.x=(double) ReadBlobLSBLong(image)/BMP_DENOM;
759 bmp_info.blue_primary.y=(double) ReadBlobLSBLong(image)/BMP_DENOM;
760 bmp_info.blue_primary.z=(double) ReadBlobLSBLong(image)/BMP_DENOM;
761
762 gamma=bmp_info.red_primary.x+bmp_info.red_primary.y+
763 bmp_info.red_primary.z;
764 gamma=PerceptibleReciprocal(gamma);
765 bmp_info.red_primary.x*=gamma;
766 bmp_info.red_primary.y*=gamma;
767 image->chromaticity.red_primary.x=bmp_info.red_primary.x;
768 image->chromaticity.red_primary.y=bmp_info.red_primary.y;
769
770 gamma=bmp_info.green_primary.x+bmp_info.green_primary.y+
771 bmp_info.green_primary.z;
772 gamma=PerceptibleReciprocal(gamma);
773 bmp_info.green_primary.x*=gamma;
774 bmp_info.green_primary.y*=gamma;
775 image->chromaticity.green_primary.x=bmp_info.green_primary.x;
776 image->chromaticity.green_primary.y=bmp_info.green_primary.y;
777
778 gamma=bmp_info.blue_primary.x+bmp_info.blue_primary.y+
779 bmp_info.blue_primary.z;
780 gamma=PerceptibleReciprocal(gamma);
781 bmp_info.blue_primary.x*=gamma;
782 bmp_info.blue_primary.y*=gamma;
783 image->chromaticity.blue_primary.x=bmp_info.blue_primary.x;
784 image->chromaticity.blue_primary.y=bmp_info.blue_primary.y;
785
786 /*
787 Decode 16^16 fixed point formatted gamma_scales.
788 */
789 bmp_info.gamma_scale.x=(double) ReadBlobLSBLong(image)/0x10000;
790 bmp_info.gamma_scale.y=(double) ReadBlobLSBLong(image)/0x10000;
791 bmp_info.gamma_scale.z=(double) ReadBlobLSBLong(image)/0x10000;
792 /*
793 Compute a single gamma from the BMP 3-channel gamma.
794 */
795 image->gamma=(bmp_info.gamma_scale.x+bmp_info.gamma_scale.y+
796 bmp_info.gamma_scale.z)/3.0;
797 }
798 else
799 (void) CopyMagickString(image->magick,"BMP3",MagickPathExtent);
800
801 if (bmp_info.size > 108)
802 {
803 size_t
804 intent;
805
806 /*
807 Read BMP Version 5 color management information.
808 */
809 intent=ReadBlobLSBLong(image);
810 switch ((int) intent)
811 {
812 case LCS_GM_BUSINESS:
813 {
814 image->rendering_intent=SaturationIntent;
815 break;
816 }
817 case LCS_GM_GRAPHICS:
818 {
819 image->rendering_intent=RelativeIntent;
820 break;
821 }
822 case LCS_GM_IMAGES:
823 {
824 image->rendering_intent=PerceptualIntent;
825 break;
826 }
827 case LCS_GM_ABS_COLORIMETRIC:
828 {
829 image->rendering_intent=AbsoluteIntent;
830 break;
831 }
832 }
833 profile_data=(MagickOffsetType)ReadBlobLSBLong(image);
834 profile_size=(MagickOffsetType)ReadBlobLSBLong(image);
835 (void) ReadBlobLSBLong(image); /* Reserved byte */
836 }
837 }
838 if ((MagickSizeType) bmp_info.file_size != blob_size)
839 {
840 const char
841 *option;
842
843 option=GetImageOption(image_info,"bmp:ignore-filesize");
844 if (IsStringTrue(option) == MagickFalse)
845 (void) ThrowMagickException(exception,GetMagickModule(),
846 CorruptImageError,"LengthAndFilesizeDoNotMatch","`%s'",
847 image->filename);
848 }
849 if (bmp_info.width <= 0)
850 ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize");
851 if (bmp_info.height == 0)
852 ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize");
853 if (bmp_info.planes != 1)
854 ThrowReaderException(CorruptImageError,"StaticPlanesValueNotEqualToOne");
855 if ((bmp_info.bits_per_pixel != 1) && (bmp_info.bits_per_pixel != 4) &&
856 (bmp_info.bits_per_pixel != 8) && (bmp_info.bits_per_pixel != 16) &&
857 (bmp_info.bits_per_pixel != 24) && (bmp_info.bits_per_pixel != 32))
858 ThrowReaderException(CorruptImageError,"UnsupportedBitsPerPixel");
859 if (bmp_info.bits_per_pixel < 16 &&
860 bmp_info.number_colors > (1U << bmp_info.bits_per_pixel))
861 ThrowReaderException(CorruptImageError,"UnrecognizedNumberOfColors");
862 if ((bmp_info.compression == BI_RLE8) && (bmp_info.bits_per_pixel != 8))
863 ThrowReaderException(CorruptImageError,"UnsupportedBitsPerPixel");
864 if ((bmp_info.compression == BI_RLE4) && (bmp_info.bits_per_pixel != 4))
865 ThrowReaderException(CorruptImageError,"UnsupportedBitsPerPixel");
866 if ((bmp_info.compression == BI_BITFIELDS) && (bmp_info.bits_per_pixel < 16))
867 ThrowReaderException(CorruptImageError,"UnsupportedBitsPerPixel");
868 switch (bmp_info.compression)
869 {
870 case BI_RGB:
871 image->compression=NoCompression;
872 break;
873 case BI_RLE8:
874 case BI_RLE4:
875 image->compression=RLECompression;
876 break;
877 case BI_BITFIELDS:
878 break;
879 case BI_JPEG:
880 ThrowReaderException(CoderError,"JPEGCompressNotSupported");
881 case BI_PNG:
882 ThrowReaderException(CoderError,"PNGCompressNotSupported");
883 default:
884 ThrowReaderException(CorruptImageError,"UnrecognizedImageCompression");
885 }
886 image->columns=(size_t) MagickAbsoluteValue(bmp_info.width);
887 image->rows=(size_t) MagickAbsoluteValue(bmp_info.height);
888 image->depth=bmp_info.bits_per_pixel <= 8 ? bmp_info.bits_per_pixel : 8;
889 image->alpha_trait=((bmp_info.alpha_mask != 0) &&
890 (bmp_info.compression == BI_BITFIELDS)) ? BlendPixelTrait :
891 UndefinedPixelTrait;
892 if (bmp_info.bits_per_pixel < 16)
893 {
894 size_t
895 one;
896
897 image->storage_class=PseudoClass;
898 image->colors=bmp_info.number_colors;
899 one=1;
900 if (image->colors == 0)
901 image->colors=one << bmp_info.bits_per_pixel;
902 }
903 image->resolution.x=(double) bmp_info.x_pixels/100.0;
904 image->resolution.y=(double) bmp_info.y_pixels/100.0;
905 image->units=PixelsPerCentimeterResolution;
906 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
907 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
908 break;
909 status=SetImageExtent(image,image->columns,image->rows,exception);
910 if (status == MagickFalse)
911 return(DestroyImageList(image));
912 if (image->storage_class == PseudoClass)
913 {
914 unsigned char
915 *bmp_colormap;
916
917 size_t
918 packet_size;
919
920 /*
921 Read BMP raster colormap.
922 */
923 if (image->debug != MagickFalse)
924 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
925 " Reading colormap of %.20g colors",(double) image->colors);
926 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
927 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
928 bmp_colormap=(unsigned char *) AcquireQuantumMemory((size_t)
929 image->colors,4*sizeof(*bmp_colormap));
930 if (bmp_colormap == (unsigned char *) NULL)
931 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
932 if ((bmp_info.size == 12) || (bmp_info.size == 64))
933 packet_size=3;
934 else
935 packet_size=4;
936 offset=SeekBlob(image,start_position+14+bmp_info.size,SEEK_SET);
937 if (offset < 0)
938 {
939 bmp_colormap=(unsigned char *) RelinquishMagickMemory(bmp_colormap);
940 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
941 }
942 count=ReadBlob(image,packet_size*image->colors,bmp_colormap);
943 if (count != (ssize_t) (packet_size*image->colors))
944 {
945 bmp_colormap=(unsigned char *) RelinquishMagickMemory(bmp_colormap);
946 ThrowReaderException(CorruptImageError,
947 "InsufficientImageDataInFile");
948 }
949 p=bmp_colormap;
950 for (i=0; i < (ssize_t) image->colors; i++)
951 {
952 image->colormap[i].blue=(MagickRealType) ScaleCharToQuantum(*p++);
953 image->colormap[i].green=(MagickRealType) ScaleCharToQuantum(*p++);
954 image->colormap[i].red=(MagickRealType) ScaleCharToQuantum(*p++);
955 if (packet_size == 4)
956 p++;
957 }
958 bmp_colormap=(unsigned char *) RelinquishMagickMemory(bmp_colormap);
959 }
960 /*
961 Read image data.
962 */
963 if (bmp_info.offset_bits == offset_bits)
964 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
965 offset_bits=bmp_info.offset_bits;
966 offset=SeekBlob(image,start_position+bmp_info.offset_bits,SEEK_SET);
967 if (offset < 0)
968 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
969 if (bmp_info.compression == BI_RLE4)
970 bmp_info.bits_per_pixel<<=1;
971 bytes_per_line=4*((image->columns*bmp_info.bits_per_pixel+31)/32);
972 length=(size_t) bytes_per_line*image->rows;
973 if ((MagickSizeType) (length/256) > blob_size)
974 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
975 if ((bmp_info.compression == BI_RGB) ||
976 (bmp_info.compression == BI_BITFIELDS))
977 {
978 pixel_info=AcquireVirtualMemory(image->rows,
979 MagickMax(bytes_per_line,image->columns+256UL)*sizeof(*pixels));
980 if (pixel_info == (MemoryInfo *) NULL)
981 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
982 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
983 if (image->debug != MagickFalse)
984 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
985 " Reading pixels (%.20g bytes)",(double) length);
986 count=ReadBlob(image,length,pixels);
987 if (count != (ssize_t) length)
988 {
989 pixel_info=RelinquishVirtualMemory(pixel_info);
990 ThrowReaderException(CorruptImageError,
991 "InsufficientImageDataInFile");
992 }
993 }
994 else
995 {
996 /*
997 Convert run-length encoded raster pixels.
998 */
999 pixel_info=AcquireVirtualMemory(image->rows,
1000 MagickMax(bytes_per_line,image->columns+256UL)*sizeof(*pixels));
1001 if (pixel_info == (MemoryInfo *) NULL)
1002 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1003 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
1004 status=DecodeImage(image,bmp_info.compression,pixels,
1005 image->columns*image->rows);
1006 if (status == MagickFalse)
1007 {
1008 pixel_info=RelinquishVirtualMemory(pixel_info);
1009 ThrowReaderException(CorruptImageError,
1010 "UnableToRunlengthDecodeImage");
1011 }
1012 }
1013 /*
1014 Convert BMP raster image to pixel packets.
1015 */
1016 if (bmp_info.compression == BI_RGB)
1017 {
1018 /*
1019 We should ignore the alpha value in BMP3 files but there have been
1020 reports about 32 bit files with alpha. We do a quick check to see if
1021 the alpha channel contains a value that is not zero (default value).
1022 If we find a non zero value we asume the program that wrote the file
1023 wants to use the alpha channel.
1024 */
1025 if ((image->alpha_trait == UndefinedPixelTrait) &&
1026 (bmp_info.size == 40) && (bmp_info.bits_per_pixel == 32))
1027 {
1028 bytes_per_line=4*(image->columns);
1029 for (y=(ssize_t) image->rows-1; y >= 0; y--)
1030 {
1031 p=pixels+(image->rows-y-1)*bytes_per_line;
1032 for (x=0; x < (ssize_t) image->columns; x++)
1033 {
1034 if (*(p+3) != 0)
1035 {
1036 image->alpha_trait=BlendPixelTrait;
1037 y=-1;
1038 break;
1039 }
1040 p+=4;
1041 }
1042 }
1043 }
1044 bmp_info.alpha_mask=image->alpha_trait != UndefinedPixelTrait ?
1045 0xff000000U : 0U;
1046 bmp_info.red_mask=0x00ff0000U;
1047 bmp_info.green_mask=0x0000ff00U;
1048 bmp_info.blue_mask=0x000000ffU;
1049 if (bmp_info.bits_per_pixel == 16)
1050 {
1051 /*
1052 RGB555.
1053 */
1054 bmp_info.red_mask=0x00007c00U;
1055 bmp_info.green_mask=0x000003e0U;
1056 bmp_info.blue_mask=0x0000001fU;
1057 }
1058 }
1059 (void) memset(&shift,0,sizeof(shift));
1060 (void) memset(&quantum_bits,0,sizeof(quantum_bits));
1061 if ((bmp_info.bits_per_pixel == 16) || (bmp_info.bits_per_pixel == 32))
1062 {
1063 unsigned int
1064 sample;
1065
1066 /*
1067 Get shift and quantum bits info from bitfield masks.
1068 */
1069 if (bmp_info.red_mask != 0)
1070 while (((bmp_info.red_mask << shift.red) & 0x80000000UL) == 0)
1071 {
1072 shift.red++;
1073 if (shift.red >= 32U)
1074 break;
1075 }
1076 if (bmp_info.green_mask != 0)
1077 while (((bmp_info.green_mask << shift.green) & 0x80000000UL) == 0)
1078 {
1079 shift.green++;
1080 if (shift.green >= 32U)
1081 break;
1082 }
1083 if (bmp_info.blue_mask != 0)
1084 while (((bmp_info.blue_mask << shift.blue) & 0x80000000UL) == 0)
1085 {
1086 shift.blue++;
1087 if (shift.blue >= 32U)
1088 break;
1089 }
1090 if (bmp_info.alpha_mask != 0)
1091 while (((bmp_info.alpha_mask << shift.alpha) & 0x80000000UL) == 0)
1092 {
1093 shift.alpha++;
1094 if (shift.alpha >= 32U)
1095 break;
1096 }
1097 sample=shift.red;
1098 while (((bmp_info.red_mask << sample) & 0x80000000UL) != 0)
1099 {
1100 sample++;
1101 if (sample >= 32U)
1102 break;
1103 }
1104 quantum_bits.red=(MagickRealType) (sample-shift.red);
1105 sample=shift.green;
1106 while (((bmp_info.green_mask << sample) & 0x80000000UL) != 0)
1107 {
1108 sample++;
1109 if (sample >= 32U)
1110 break;
1111 }
1112 quantum_bits.green=(MagickRealType) (sample-shift.green);
1113 sample=shift.blue;
1114 while (((bmp_info.blue_mask << sample) & 0x80000000UL) != 0)
1115 {
1116 sample++;
1117 if (sample >= 32U)
1118 break;
1119 }
1120 quantum_bits.blue=(MagickRealType) (sample-shift.blue);
1121 sample=shift.alpha;
1122 while (((bmp_info.alpha_mask << sample) & 0x80000000UL) != 0)
1123 {
1124 sample++;
1125 if (sample >= 32U)
1126 break;
1127 }
1128 quantum_bits.alpha=(MagickRealType) (sample-shift.alpha);
1129 }
1130 switch (bmp_info.bits_per_pixel)
1131 {
1132 case 1:
1133 {
1134 /*
1135 Convert bitmap scanline.
1136 */
1137 for (y=(ssize_t) image->rows-1; y >= 0; y--)
1138 {
1139 p=pixels+(image->rows-y-1)*bytes_per_line;
1140 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1141 if (q == (Quantum *) NULL)
1142 break;
1143 for (x=0; x < ((ssize_t) image->columns-7); x+=8)
1144 {
1145 for (bit=0; bit < 8; bit++)
1146 {
1147 index=(Quantum) (((*p) & (0x80 >> bit)) != 0 ? 0x01 : 0x00);
1148 SetPixelIndex(image,index,q);
1149 q+=GetPixelChannels(image);
1150 }
1151 p++;
1152 }
1153 if ((image->columns % 8) != 0)
1154 {
1155 for (bit=0; bit < (image->columns % 8); bit++)
1156 {
1157 index=(Quantum) (((*p) & (0x80 >> bit)) != 0 ? 0x01 : 0x00);
1158 SetPixelIndex(image,index,q);
1159 q+=GetPixelChannels(image);
1160 }
1161 p++;
1162 }
1163 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1164 break;
1165 if (image->previous == (Image *) NULL)
1166 {
1167 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
1168 (image->rows-y),image->rows);
1169 if (status == MagickFalse)
1170 break;
1171 }
1172 }
1173 (void) SyncImage(image,exception);
1174 break;
1175 }
1176 case 4:
1177 {
1178 /*
1179 Convert PseudoColor scanline.
1180 */
1181 for (y=(ssize_t) image->rows-1; y >= 0; y--)
1182 {
1183 p=pixels+(image->rows-y-1)*bytes_per_line;
1184 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1185 if (q == (Quantum *) NULL)
1186 break;
1187 for (x=0; x < ((ssize_t) image->columns-1); x+=2)
1188 {
1189 ValidateColormapValue(image,(ssize_t) ((*p >> 4) & 0x0f),&index,
1190 exception);
1191 SetPixelIndex(image,index,q);
1192 q+=GetPixelChannels(image);
1193 ValidateColormapValue(image,(ssize_t) (*p & 0x0f),&index,exception);
1194 SetPixelIndex(image,index,q);
1195 q+=GetPixelChannels(image);
1196 p++;
1197 }
1198 if ((image->columns % 2) != 0)
1199 {
1200 ValidateColormapValue(image,(ssize_t) ((*p >> 4) & 0xf),&index,
1201 exception);
1202 SetPixelIndex(image,index,q);
1203 q+=GetPixelChannels(image);
1204 p++;
1205 x++;
1206 }
1207 if (x < (ssize_t) image->columns)
1208 break;
1209 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1210 break;
1211 if (image->previous == (Image *) NULL)
1212 {
1213 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
1214 (image->rows-y),image->rows);
1215 if (status == MagickFalse)
1216 break;
1217 }
1218 }
1219 (void) SyncImage(image,exception);
1220 break;
1221 }
1222 case 8:
1223 {
1224 /*
1225 Convert PseudoColor scanline.
1226 */
1227 if ((bmp_info.compression == BI_RLE8) ||
1228 (bmp_info.compression == BI_RLE4))
1229 bytes_per_line=image->columns;
1230 for (y=(ssize_t) image->rows-1; y >= 0; y--)
1231 {
1232 p=pixels+(image->rows-y-1)*bytes_per_line;
1233 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1234 if (q == (Quantum *) NULL)
1235 break;
1236 for (x=(ssize_t) image->columns; x != 0; --x)
1237 {
1238 ValidateColormapValue(image,(ssize_t) *p++,&index,exception);
1239 SetPixelIndex(image,index,q);
1240 q+=GetPixelChannels(image);
1241 }
1242 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1243 break;
1244 offset=(MagickOffsetType) (image->rows-y-1);
1245 if (image->previous == (Image *) NULL)
1246 {
1247 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
1248 (image->rows-y),image->rows);
1249 if (status == MagickFalse)
1250 break;
1251 }
1252 }
1253 (void) SyncImage(image,exception);
1254 break;
1255 }
1256 case 16:
1257 {
1258 unsigned int
1259 alpha,
1260 pixel;
1261
1262 /*
1263 Convert bitfield encoded 16-bit PseudoColor scanline.
1264 */
1265 if ((bmp_info.compression != BI_RGB) &&
1266 (bmp_info.compression != BI_BITFIELDS))
1267 {
1268 pixel_info=RelinquishVirtualMemory(pixel_info);
1269 ThrowReaderException(CorruptImageError,
1270 "UnrecognizedImageCompression");
1271 }
1272 bytes_per_line=2*(image->columns+image->columns % 2);
1273 image->storage_class=DirectClass;
1274 for (y=(ssize_t) image->rows-1; y >= 0; y--)
1275 {
1276 p=pixels+(image->rows-y-1)*bytes_per_line;
1277 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1278 if (q == (Quantum *) NULL)
1279 break;
1280 for (x=0; x < (ssize_t) image->columns; x++)
1281 {
1282 pixel=(unsigned int) (*p++);
1283 pixel|=(*p++) << 8;
1284 red=((pixel & bmp_info.red_mask) << shift.red) >> 16;
1285 if (quantum_bits.red == 5)
1286 red|=((red & 0xe000) >> 5);
1287 if (quantum_bits.red <= 8)
1288 red|=((red & 0xff00) >> 8);
1289 green=((pixel & bmp_info.green_mask) << shift.green) >> 16;
1290 if (quantum_bits.green == 5)
1291 green|=((green & 0xe000) >> 5);
1292 if (quantum_bits.green == 6)
1293 green|=((green & 0xc000) >> 6);
1294 if (quantum_bits.green <= 8)
1295 green|=((green & 0xff00) >> 8);
1296 blue=((pixel & bmp_info.blue_mask) << shift.blue) >> 16;
1297 if (quantum_bits.blue == 5)
1298 blue|=((blue & 0xe000) >> 5);
1299 if (quantum_bits.blue <= 8)
1300 blue|=((blue & 0xff00) >> 8);
1301 SetPixelRed(image,ScaleShortToQuantum((unsigned short) red),q);
1302 SetPixelGreen(image,ScaleShortToQuantum((unsigned short) green),q);
1303 SetPixelBlue(image,ScaleShortToQuantum((unsigned short) blue),q);
1304 SetPixelAlpha(image,OpaqueAlpha,q);
1305 if (image->alpha_trait != UndefinedPixelTrait)
1306 {
1307 alpha=((pixel & bmp_info.alpha_mask) << shift.alpha) >> 16;
1308 if (quantum_bits.alpha <= 8)
1309 alpha|=((alpha & 0xff00) >> 8);
1310 SetPixelAlpha(image,ScaleShortToQuantum(
1311 (unsigned short) alpha),q);
1312 }
1313 q+=GetPixelChannels(image);
1314 }
1315 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1316 break;
1317 offset=(MagickOffsetType) (image->rows-y-1);
1318 if (image->previous == (Image *) NULL)
1319 {
1320 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
1321 (image->rows-y),image->rows);
1322 if (status == MagickFalse)
1323 break;
1324 }
1325 }
1326 break;
1327 }
1328 case 24:
1329 {
1330 /*
1331 Convert DirectColor scanline.
1332 */
1333 bytes_per_line=4*((image->columns*24+31)/32);
1334 for (y=(ssize_t) image->rows-1; y >= 0; y--)
1335 {
1336 p=pixels+(image->rows-y-1)*bytes_per_line;
1337 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1338 if (q == (Quantum *) NULL)
1339 break;
1340 for (x=0; x < (ssize_t) image->columns; x++)
1341 {
1342 SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
1343 SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
1344 SetPixelRed(image,ScaleCharToQuantum(*p++),q);
1345 SetPixelAlpha(image,OpaqueAlpha,q);
1346 q+=GetPixelChannels(image);
1347 }
1348 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1349 break;
1350 offset=(MagickOffsetType) (image->rows-y-1);
1351 if (image->previous == (Image *) NULL)
1352 {
1353 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
1354 (image->rows-y),image->rows);
1355 if (status == MagickFalse)
1356 break;
1357 }
1358 }
1359 break;
1360 }
1361 case 32:
1362 {
1363 /*
1364 Convert bitfield encoded DirectColor scanline.
1365 */
1366 if ((bmp_info.compression != BI_RGB) &&
1367 (bmp_info.compression != BI_BITFIELDS))
1368 {
1369 pixel_info=RelinquishVirtualMemory(pixel_info);
1370 ThrowReaderException(CorruptImageError,
1371 "UnrecognizedImageCompression");
1372 }
1373 bytes_per_line=4*(image->columns);
1374 for (y=(ssize_t) image->rows-1; y >= 0; y--)
1375 {
1376 unsigned int
1377 alpha,
1378 pixel;
1379
1380 p=pixels+(image->rows-y-1)*bytes_per_line;
1381 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1382 if (q == (Quantum *) NULL)
1383 break;
1384 for (x=0; x < (ssize_t) image->columns; x++)
1385 {
1386 pixel=(unsigned int) (*p++);
1387 pixel|=((unsigned int) *p++ << 8);
1388 pixel|=((unsigned int) *p++ << 16);
1389 pixel|=((unsigned int) *p++ << 24);
1390 red=((pixel & bmp_info.red_mask) << shift.red) >> 16;
1391 if (quantum_bits.red == 8)
1392 red|=(red >> 8);
1393 green=((pixel & bmp_info.green_mask) << shift.green) >> 16;
1394 if (quantum_bits.green == 8)
1395 green|=(green >> 8);
1396 blue=((pixel & bmp_info.blue_mask) << shift.blue) >> 16;
1397 if (quantum_bits.blue == 8)
1398 blue|=(blue >> 8);
1399 SetPixelRed(image,ScaleShortToQuantum((unsigned short) red),q);
1400 SetPixelGreen(image,ScaleShortToQuantum((unsigned short) green),q);
1401 SetPixelBlue(image,ScaleShortToQuantum((unsigned short) blue),q);
1402 SetPixelAlpha(image,OpaqueAlpha,q);
1403 if (image->alpha_trait != UndefinedPixelTrait)
1404 {
1405 alpha=((pixel & bmp_info.alpha_mask) << shift.alpha) >> 16;
1406 if (quantum_bits.alpha == 8)
1407 alpha|=(alpha >> 8);
1408 SetPixelAlpha(image,ScaleShortToQuantum(
1409 (unsigned short) alpha),q);
1410 }
1411 q+=GetPixelChannels(image);
1412 }
1413 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1414 break;
1415 offset=(MagickOffsetType) (image->rows-y-1);
1416 if (image->previous == (Image *) NULL)
1417 {
1418 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
1419 (image->rows-y),image->rows);
1420 if (status == MagickFalse)
1421 break;
1422 }
1423 }
1424 break;
1425 }
1426 default:
1427 {
1428 pixel_info=RelinquishVirtualMemory(pixel_info);
1429 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1430 }
1431 }
1432 pixel_info=RelinquishVirtualMemory(pixel_info);
1433 if (y > 0)
1434 break;
1435 if (EOFBlob(image) != MagickFalse)
1436 {
1437 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
1438 image->filename);
1439 break;
1440 }
1441 if (bmp_info.height < 0)
1442 {
1443 Image
1444 *flipped_image;
1445
1446 /*
1447 Correct image orientation.
1448 */
1449 flipped_image=FlipImage(image,exception);
1450 if (flipped_image != (Image *) NULL)
1451 {
1452 DuplicateBlob(flipped_image,image);
1453 ReplaceImageInList(&image, flipped_image);
1454 image=flipped_image;
1455 }
1456 }
1457 /*
1458 Read embeded ICC profile
1459 */
1460 if ((bmp_info.colorspace == 0x4D424544L) && (profile_data > 0) &&
1461 (profile_size > 0))
1462 {
1463 StringInfo
1464 *profile;
1465
1466 unsigned char
1467 *datum;
1468
1469 offset=start_position+14+profile_data;
1470 if ((offset < TellBlob(image)) ||
1471 (SeekBlob(image,offset,SEEK_SET) != offset) ||
1472 (blob_size < (MagickSizeType) (offset+profile_size)))
1473 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1474 profile=AcquireStringInfo((size_t) profile_size);
1475 if (profile == (StringInfo *) NULL)
1476 ThrowReaderException(CorruptImageError,"MemoryAllocationFailed");
1477 datum=GetStringInfoDatum(profile);
1478 if (ReadBlob(image,(size_t) profile_size,datum) == (ssize_t) profile_size)
1479 {
1480 MagickOffsetType
1481 profile_size_orig;
1482
1483 /*
1484 Trimming padded bytes.
1485 */
1486 profile_size_orig=(MagickOffsetType) datum[0] << 24;
1487 profile_size_orig|=(MagickOffsetType) datum[1] << 16;
1488 profile_size_orig|=(MagickOffsetType) datum[2] << 8;
1489 profile_size_orig|=(MagickOffsetType) datum[3];
1490 if (profile_size_orig < profile_size)
1491 SetStringInfoLength(profile,(size_t) profile_size_orig);
1492 if (image->debug != MagickFalse)
1493 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1494 "Profile: ICC, %u bytes",(unsigned int) profile_size_orig);
1495 (void) SetImageProfile(image,"icc",profile,exception);
1496 }
1497 profile=DestroyStringInfo(profile);
1498 }
1499 /*
1500 Proceed to next image.
1501 */
1502 if (image_info->number_scenes != 0)
1503 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1504 break;
1505 offset=(MagickOffsetType) bmp_info.ba_offset;
1506 if (offset != 0)
1507 if ((offset < TellBlob(image)) ||
1508 (SeekBlob(image,offset,SEEK_SET) != offset))
1509 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1510 *magick='\0';
1511 count=ReadBlob(image,2,magick);
1512 if ((count == 2) && (IsBMP(magick,2) != MagickFalse))
1513 {
1514 /*
1515 Acquire next image structure.
1516 */
1517 AcquireNextImage(image_info,image,exception);
1518 if (GetNextImageInList(image) == (Image *) NULL)
1519 {
1520 status=MagickFalse;
1521 break;
1522 }
1523 image=SyncNextImageInList(image);
1524 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),blob_size);
1525 if (status == MagickFalse)
1526 break;
1527 }
1528 } while (IsBMP(magick,2) != MagickFalse);
1529 (void) CloseBlob(image);
1530 if (status == MagickFalse)
1531 return(DestroyImageList(image));
1532 return(GetFirstImageInList(image));
1533 }
1534
1535 /*
1536 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1537 % %
1538 % %
1539 % %
1540 % R e g i s t e r B M P I m a g e %
1541 % %
1542 % %
1543 % %
1544 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1545 %
1546 % RegisterBMPImage() adds attributes for the BMP image format to
1547 % the list of supported formats. The attributes include the image format
1548 % tag, a method to read and/or write the format, whether the format
1549 % supports the saving of more than one frame to the same file or blob,
1550 % whether the format supports native in-memory I/O, and a brief
1551 % description of the format.
1552 %
1553 % The format of the RegisterBMPImage method is:
1554 %
1555 % size_t RegisterBMPImage(void)
1556 %
1557 */
RegisterBMPImage(void)1558 ModuleExport size_t RegisterBMPImage(void)
1559 {
1560 MagickInfo
1561 *entry;
1562
1563 entry=AcquireMagickInfo("BMP","BMP","Microsoft Windows bitmap image");
1564 entry->decoder=(DecodeImageHandler *) ReadBMPImage;
1565 entry->encoder=(EncodeImageHandler *) WriteBMPImage;
1566 entry->magick=(IsImageFormatHandler *) IsBMP;
1567 entry->flags^=CoderAdjoinFlag;
1568 entry->flags|=CoderDecoderSeekableStreamFlag;
1569 (void) RegisterMagickInfo(entry);
1570 entry=AcquireMagickInfo("BMP","BMP2","Microsoft Windows bitmap image (V2)");
1571 entry->decoder=(DecodeImageHandler *) ReadBMPImage;
1572 entry->encoder=(EncodeImageHandler *) WriteBMPImage;
1573 entry->magick=(IsImageFormatHandler *) IsBMP;
1574 entry->flags^=CoderAdjoinFlag;
1575 entry->flags|=CoderDecoderSeekableStreamFlag;
1576 (void) RegisterMagickInfo(entry);
1577 entry=AcquireMagickInfo("BMP","BMP3","Microsoft Windows bitmap image (V3)");
1578 entry->decoder=(DecodeImageHandler *) ReadBMPImage;
1579 entry->encoder=(EncodeImageHandler *) WriteBMPImage;
1580 entry->magick=(IsImageFormatHandler *) IsBMP;
1581 entry->flags^=CoderAdjoinFlag;
1582 entry->flags|=CoderDecoderSeekableStreamFlag;
1583 (void) RegisterMagickInfo(entry);
1584 return(MagickImageCoderSignature);
1585 }
1586
1587 /*
1588 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1589 % %
1590 % %
1591 % %
1592 % U n r e g i s t e r B M P I m a g e %
1593 % %
1594 % %
1595 % %
1596 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1597 %
1598 % UnregisterBMPImage() removes format registrations made by the
1599 % BMP module from the list of supported formats.
1600 %
1601 % The format of the UnregisterBMPImage method is:
1602 %
1603 % UnregisterBMPImage(void)
1604 %
1605 */
UnregisterBMPImage(void)1606 ModuleExport void UnregisterBMPImage(void)
1607 {
1608 (void) UnregisterMagickInfo("BMP");
1609 (void) UnregisterMagickInfo("BMP2");
1610 (void) UnregisterMagickInfo("BMP3");
1611 }
1612
1613 /*
1614 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1615 % %
1616 % %
1617 % %
1618 % W r i t e B M P I m a g e %
1619 % %
1620 % %
1621 % %
1622 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1623 %
1624 % WriteBMPImage() writes an image in Microsoft Windows bitmap encoded
1625 % image format, version 3 for Windows or (if the image has a matte channel)
1626 % version 4.
1627 %
1628 % The format of the WriteBMPImage method is:
1629 %
1630 % MagickBooleanType WriteBMPImage(const ImageInfo *image_info,
1631 % Image *image,ExceptionInfo *exception)
1632 %
1633 % A description of each parameter follows.
1634 %
1635 % o image_info: the image info.
1636 %
1637 % o image: The image.
1638 %
1639 % o exception: return any errors or warnings in this structure.
1640 %
1641 */
WriteBMPImage(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)1642 static MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image,
1643 ExceptionInfo *exception)
1644 {
1645 BMPInfo
1646 bmp_info;
1647
1648 BMPSubtype
1649 bmp_subtype;
1650
1651 const char
1652 *option;
1653
1654 const StringInfo
1655 *profile;
1656
1657 MagickBooleanType
1658 have_color_info,
1659 status;
1660
1661 MagickOffsetType
1662 scene;
1663
1664 MemoryInfo
1665 *pixel_info;
1666
1667 const Quantum
1668 *p;
1669
1670 ssize_t
1671 i,
1672 x;
1673
1674 unsigned char
1675 *q;
1676
1677 size_t
1678 bytes_per_line,
1679 imageListLength,
1680 type;
1681
1682 ssize_t
1683 y;
1684
1685 unsigned char
1686 *bmp_data,
1687 *pixels;
1688
1689 MagickOffsetType
1690 profile_data,
1691 profile_size,
1692 profile_size_pad;
1693
1694 /*
1695 Open output image file.
1696 */
1697 assert(image_info != (const ImageInfo *) NULL);
1698 assert(image_info->signature == MagickCoreSignature);
1699 assert(image != (Image *) NULL);
1700 assert(image->signature == MagickCoreSignature);
1701 if (image->debug != MagickFalse)
1702 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1703 assert(exception != (ExceptionInfo *) NULL);
1704 assert(exception->signature == MagickCoreSignature);
1705 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1706 if (status == MagickFalse)
1707 return(status);
1708 if (((image->columns << 3) != (size_t) ((int) (image->columns << 3))) ||
1709 ((image->rows << 3) != (size_t) ((int) (image->rows << 3))))
1710 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
1711 type=4;
1712 if (LocaleCompare(image_info->magick,"BMP2") == 0)
1713 type=2;
1714 else
1715 if (LocaleCompare(image_info->magick,"BMP3") == 0)
1716 type=3;
1717 option=GetImageOption(image_info,"bmp:format");
1718 if (option != (char *) NULL)
1719 {
1720 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1721 " Format=%s",option);
1722 if (LocaleCompare(option,"bmp2") == 0)
1723 type=2;
1724 if (LocaleCompare(option,"bmp3") == 0)
1725 type=3;
1726 if (LocaleCompare(option,"bmp4") == 0)
1727 type=4;
1728 }
1729 scene=0;
1730 imageListLength=GetImageListLength(image);
1731 do
1732 {
1733 /*
1734 Initialize BMP raster file header.
1735 */
1736 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
1737 (void) TransformImageColorspace(image,sRGBColorspace,exception);
1738 (void) memset(&bmp_info,0,sizeof(bmp_info));
1739 bmp_info.file_size=14+12;
1740 if (type > 2)
1741 bmp_info.file_size+=28;
1742 bmp_info.offset_bits=bmp_info.file_size;
1743 bmp_info.compression=BI_RGB;
1744 bmp_info.red_mask=0x00ff0000U;
1745 bmp_info.green_mask=0x0000ff00U;
1746 bmp_info.blue_mask=0x000000ffU;
1747 bmp_info.alpha_mask=0xff000000U;
1748 bmp_subtype=UndefinedSubtype;
1749 if ((image->storage_class == PseudoClass) && (image->colors > 256))
1750 (void) SetImageStorageClass(image,DirectClass,exception);
1751 if (image->storage_class != DirectClass)
1752 {
1753 /*
1754 Colormapped BMP raster.
1755 */
1756 bmp_info.bits_per_pixel=8;
1757 if (image->colors <= 2)
1758 bmp_info.bits_per_pixel=1;
1759 else
1760 if (image->colors <= 16)
1761 bmp_info.bits_per_pixel=4;
1762 else
1763 if (image->colors <= 256)
1764 bmp_info.bits_per_pixel=8;
1765 if (image_info->compression == RLECompression)
1766 bmp_info.bits_per_pixel=8;
1767 bmp_info.number_colors=1U << bmp_info.bits_per_pixel;
1768 if (image->alpha_trait != UndefinedPixelTrait)
1769 (void) SetImageStorageClass(image,DirectClass,exception);
1770 else
1771 if ((size_t) bmp_info.number_colors < image->colors)
1772 (void) SetImageStorageClass(image,DirectClass,exception);
1773 else
1774 {
1775 bmp_info.file_size+=3*(1UL << bmp_info.bits_per_pixel);
1776 bmp_info.offset_bits+=3*(1UL << bmp_info.bits_per_pixel);
1777 if (type > 2)
1778 {
1779 bmp_info.file_size+=(1UL << bmp_info.bits_per_pixel);
1780 bmp_info.offset_bits+=(1UL << bmp_info.bits_per_pixel);
1781 }
1782 }
1783 }
1784 if (image->storage_class == DirectClass)
1785 {
1786 /*
1787 Full color BMP raster.
1788 */
1789 bmp_info.number_colors=0;
1790 option=GetImageOption(image_info,"bmp:subtype");
1791 if (option != (const char *) NULL)
1792 {
1793 if (image->alpha_trait != UndefinedPixelTrait)
1794 {
1795 if (LocaleNCompare(option,"ARGB4444",8) == 0)
1796 {
1797 bmp_subtype=ARGB4444;
1798 bmp_info.red_mask=0x00000f00U;
1799 bmp_info.green_mask=0x000000f0U;
1800 bmp_info.blue_mask=0x0000000fU;
1801 bmp_info.alpha_mask=0x0000f000U;
1802 }
1803 else if (LocaleNCompare(option,"ARGB1555",8) == 0)
1804 {
1805 bmp_subtype=ARGB1555;
1806 bmp_info.red_mask=0x00007c00U;
1807 bmp_info.green_mask=0x000003e0U;
1808 bmp_info.blue_mask=0x0000001fU;
1809 bmp_info.alpha_mask=0x00008000U;
1810 }
1811 }
1812 else
1813 {
1814 if (LocaleNCompare(option,"RGB555",6) == 0)
1815 {
1816 bmp_subtype=RGB555;
1817 bmp_info.red_mask=0x00007c00U;
1818 bmp_info.green_mask=0x000003e0U;
1819 bmp_info.blue_mask=0x0000001fU;
1820 bmp_info.alpha_mask=0U;
1821 }
1822 else if (LocaleNCompare(option,"RGB565",6) == 0)
1823 {
1824 bmp_subtype=RGB565;
1825 bmp_info.red_mask=0x0000f800U;
1826 bmp_info.green_mask=0x000007e0U;
1827 bmp_info.blue_mask=0x0000001fU;
1828 bmp_info.alpha_mask=0U;
1829 }
1830 }
1831 }
1832 if (bmp_subtype != UndefinedSubtype)
1833 {
1834 bmp_info.bits_per_pixel=16;
1835 bmp_info.compression=BI_BITFIELDS;
1836 }
1837 else
1838 {
1839 bmp_info.bits_per_pixel=(unsigned short) ((type > 3) &&
1840 (image->alpha_trait != UndefinedPixelTrait) ? 32 : 24);
1841 bmp_info.compression=(unsigned int) ((type > 3) &&
1842 (image->alpha_trait != UndefinedPixelTrait) ? BI_BITFIELDS : BI_RGB);
1843 if ((type == 3) && (image->alpha_trait != UndefinedPixelTrait))
1844 {
1845 option=GetImageOption(image_info,"bmp3:alpha");
1846 if (IsStringTrue(option))
1847 bmp_info.bits_per_pixel=32;
1848 }
1849 }
1850 }
1851 bytes_per_line=4*((image->columns*bmp_info.bits_per_pixel+31)/32);
1852 bmp_info.ba_offset=0;
1853 profile=GetImageProfile(image,"icc");
1854 have_color_info=(image->rendering_intent != UndefinedIntent) ||
1855 (profile != (StringInfo *) NULL) || (image->gamma != 0.0) ? MagickTrue :
1856 MagickFalse;
1857 if (type == 2)
1858 bmp_info.size=12;
1859 else
1860 if ((type == 3) || ((image->alpha_trait == UndefinedPixelTrait) &&
1861 (have_color_info == MagickFalse)))
1862 {
1863 type=3;
1864 bmp_info.size=40;
1865 }
1866 else
1867 {
1868 int
1869 extra_size;
1870
1871 bmp_info.size=108;
1872 extra_size=68;
1873 if ((image->rendering_intent != UndefinedIntent) ||
1874 (profile != (StringInfo *) NULL))
1875 {
1876 bmp_info.size=124;
1877 extra_size+=16;
1878 }
1879 bmp_info.file_size+=extra_size;
1880 bmp_info.offset_bits+=extra_size;
1881 }
1882 if (((ssize_t) image->columns != (ssize_t) ((signed int) image->columns)) ||
1883 ((ssize_t) image->rows != (ssize_t) ((signed int) image->rows)))
1884 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
1885 bmp_info.width=(ssize_t) image->columns;
1886 bmp_info.height=(ssize_t) image->rows;
1887 bmp_info.planes=1;
1888 bmp_info.image_size=(unsigned int) (bytes_per_line*image->rows);
1889 bmp_info.file_size+=bmp_info.image_size;
1890 bmp_info.x_pixels=75*39;
1891 bmp_info.y_pixels=75*39;
1892 switch (image->units)
1893 {
1894 case UndefinedResolution:
1895 case PixelsPerInchResolution:
1896 {
1897 bmp_info.x_pixels=(unsigned int) (100.0*image->resolution.x/2.54);
1898 bmp_info.y_pixels=(unsigned int) (100.0*image->resolution.y/2.54);
1899 break;
1900 }
1901 case PixelsPerCentimeterResolution:
1902 {
1903 bmp_info.x_pixels=(unsigned int) (100.0*image->resolution.x);
1904 bmp_info.y_pixels=(unsigned int) (100.0*image->resolution.y);
1905 break;
1906 }
1907 }
1908 bmp_info.colors_important=bmp_info.number_colors;
1909 /*
1910 Convert MIFF to BMP raster pixels.
1911 */
1912 pixel_info=AcquireVirtualMemory(image->rows,MagickMax(bytes_per_line,
1913 image->columns+256UL)*sizeof(*pixels));
1914 if (pixel_info == (MemoryInfo *) NULL)
1915 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1916 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
1917 (void) memset(pixels,0,(size_t) bmp_info.image_size);
1918 switch (bmp_info.bits_per_pixel)
1919 {
1920 case 1:
1921 {
1922 size_t
1923 bit,
1924 byte;
1925
1926 /*
1927 Convert PseudoClass image to a BMP monochrome image.
1928 */
1929 for (y=0; y < (ssize_t) image->rows; y++)
1930 {
1931 ssize_t
1932 offset;
1933
1934 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1935 if (p == (const Quantum *) NULL)
1936 break;
1937 q=pixels+(image->rows-y-1)*bytes_per_line;
1938 bit=0;
1939 byte=0;
1940 for (x=0; x < (ssize_t) image->columns; x++)
1941 {
1942 byte<<=1;
1943 byte|=GetPixelIndex(image,p) != 0 ? 0x01 : 0x00;
1944 bit++;
1945 if (bit == 8)
1946 {
1947 *q++=(unsigned char) byte;
1948 bit=0;
1949 byte=0;
1950 }
1951 p+=GetPixelChannels(image);
1952 }
1953 if (bit != 0)
1954 {
1955 *q++=(unsigned char) (byte << (8-bit));
1956 x++;
1957 }
1958 offset=(ssize_t) (image->columns+7)/8;
1959 for (x=offset; x < (ssize_t) bytes_per_line; x++)
1960 *q++=0x00;
1961 if (image->previous == (Image *) NULL)
1962 {
1963 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1964 image->rows);
1965 if (status == MagickFalse)
1966 break;
1967 }
1968 }
1969 break;
1970 }
1971 case 4:
1972 {
1973 unsigned int
1974 byte,
1975 nibble;
1976
1977 ssize_t
1978 offset;
1979
1980 /*
1981 Convert PseudoClass image to a BMP monochrome image.
1982 */
1983 for (y=0; y < (ssize_t) image->rows; y++)
1984 {
1985 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1986 if (p == (const Quantum *) NULL)
1987 break;
1988 q=pixels+(image->rows-y-1)*bytes_per_line;
1989 nibble=0;
1990 byte=0;
1991 for (x=0; x < (ssize_t) image->columns; x++)
1992 {
1993 byte<<=4;
1994 byte|=((unsigned int) GetPixelIndex(image,p) & 0x0f);
1995 nibble++;
1996 if (nibble == 2)
1997 {
1998 *q++=(unsigned char) byte;
1999 nibble=0;
2000 byte=0;
2001 }
2002 p+=GetPixelChannels(image);
2003 }
2004 if (nibble != 0)
2005 {
2006 *q++=(unsigned char) (byte << 4);
2007 x++;
2008 }
2009 offset=(ssize_t) (image->columns+1)/2;
2010 for (x=offset; x < (ssize_t) bytes_per_line; x++)
2011 *q++=0x00;
2012 if (image->previous == (Image *) NULL)
2013 {
2014 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2015 image->rows);
2016 if (status == MagickFalse)
2017 break;
2018 }
2019 }
2020 break;
2021 }
2022 case 8:
2023 {
2024 /*
2025 Convert PseudoClass packet to BMP pixel.
2026 */
2027 for (y=0; y < (ssize_t) image->rows; y++)
2028 {
2029 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2030 if (p == (const Quantum *) NULL)
2031 break;
2032 q=pixels+(image->rows-y-1)*bytes_per_line;
2033 for (x=0; x < (ssize_t) image->columns; x++)
2034 {
2035 *q++=(unsigned char) ((ssize_t) GetPixelIndex(image,p));
2036 p+=GetPixelChannels(image);
2037 }
2038 for ( ; x < (ssize_t) bytes_per_line; x++)
2039 *q++=0x00;
2040 if (image->previous == (Image *) NULL)
2041 {
2042 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2043 image->rows);
2044 if (status == MagickFalse)
2045 break;
2046 }
2047 }
2048 break;
2049 }
2050 case 16:
2051 {
2052 /*
2053 Convert DirectClass packet to BMP BGR888.
2054 */
2055 for (y=0; y < (ssize_t) image->rows; y++)
2056 {
2057 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2058 if (p == (const Quantum *) NULL)
2059 break;
2060 q=pixels+(image->rows-y-1)*bytes_per_line;
2061 for (x=0; x < (ssize_t) image->columns; x++)
2062 {
2063 unsigned short
2064 pixel;
2065
2066 pixel=0;
2067 if (bmp_subtype == ARGB4444)
2068 {
2069 pixel=(unsigned short) (ScaleQuantumToAny(
2070 GetPixelAlpha(image,p),15) << 12);
2071 pixel|=(unsigned short) (ScaleQuantumToAny(
2072 GetPixelRed(image,p),15) << 8);
2073 pixel|=(unsigned short) (ScaleQuantumToAny(
2074 GetPixelGreen(image,p),15) << 4);
2075 pixel|=(unsigned short) (ScaleQuantumToAny(
2076 GetPixelBlue(image,p),15));
2077 }
2078 else if (bmp_subtype == RGB565)
2079 {
2080 pixel=(unsigned short) (ScaleQuantumToAny(
2081 GetPixelRed(image,p),31) << 11);
2082 pixel|=(unsigned short) (ScaleQuantumToAny(
2083 GetPixelGreen(image,p),63) << 5);
2084 pixel|=(unsigned short) (ScaleQuantumToAny(
2085 GetPixelBlue(image,p),31));
2086 }
2087 else
2088 {
2089 if (bmp_subtype == ARGB1555)
2090 pixel=(unsigned short) (ScaleQuantumToAny(
2091 GetPixelAlpha(image,p),1) << 15);
2092 pixel|=(unsigned short) (ScaleQuantumToAny(
2093 GetPixelRed(image,p),31) << 10);
2094 pixel|=(unsigned short) (ScaleQuantumToAny(
2095 GetPixelGreen(image,p),31) << 5);
2096 pixel|=(unsigned short) (ScaleQuantumToAny(
2097 GetPixelBlue(image,p),31));
2098 }
2099 *((unsigned short *) q)=pixel;
2100 q+=2;
2101 p+=GetPixelChannels(image);
2102 }
2103 for (x=2L*(ssize_t) image->columns; x < (ssize_t) bytes_per_line; x++)
2104 *q++=0x00;
2105 if (image->previous == (Image *) NULL)
2106 {
2107 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2108 image->rows);
2109 if (status == MagickFalse)
2110 break;
2111 }
2112 }
2113 break;
2114 }
2115 case 24:
2116 {
2117 /*
2118 Convert DirectClass packet to BMP BGR888.
2119 */
2120 for (y=0; y < (ssize_t) image->rows; y++)
2121 {
2122 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2123 if (p == (const Quantum *) NULL)
2124 break;
2125 q=pixels+(image->rows-y-1)*bytes_per_line;
2126 for (x=0; x < (ssize_t) image->columns; x++)
2127 {
2128 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
2129 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
2130 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
2131 p+=GetPixelChannels(image);
2132 }
2133 for (x=3L*(ssize_t) image->columns; x < (ssize_t) bytes_per_line; x++)
2134 *q++=0x00;
2135 if (image->previous == (Image *) NULL)
2136 {
2137 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2138 image->rows);
2139 if (status == MagickFalse)
2140 break;
2141 }
2142 }
2143 break;
2144 }
2145 case 32:
2146 {
2147 /*
2148 Convert DirectClass packet to ARGB8888 pixel.
2149 */
2150 for (y=0; y < (ssize_t) image->rows; y++)
2151 {
2152 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2153 if (p == (const Quantum *) NULL)
2154 break;
2155 q=pixels+(image->rows-y-1)*bytes_per_line;
2156 for (x=0; x < (ssize_t) image->columns; x++)
2157 {
2158 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
2159 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
2160 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
2161 *q++=ScaleQuantumToChar(GetPixelAlpha(image,p));
2162 p+=GetPixelChannels(image);
2163 }
2164 if (image->previous == (Image *) NULL)
2165 {
2166 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2167 image->rows);
2168 if (status == MagickFalse)
2169 break;
2170 }
2171 }
2172 break;
2173 }
2174 }
2175 if ((type > 2) && (bmp_info.bits_per_pixel == 8))
2176 if (image_info->compression != NoCompression)
2177 {
2178 MemoryInfo
2179 *rle_info;
2180
2181 /*
2182 Convert run-length encoded raster pixels.
2183 */
2184 rle_info=AcquireVirtualMemory((size_t) (2*(bytes_per_line+2)+2),
2185 (image->rows+2)*sizeof(*pixels));
2186 if (rle_info == (MemoryInfo *) NULL)
2187 {
2188 pixel_info=RelinquishVirtualMemory(pixel_info);
2189 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2190 }
2191 bmp_data=(unsigned char *) GetVirtualMemoryBlob(rle_info);
2192 bmp_info.file_size-=bmp_info.image_size;
2193 bmp_info.image_size=(unsigned int) EncodeImage(image,bytes_per_line,
2194 pixels,bmp_data);
2195 bmp_info.file_size+=bmp_info.image_size;
2196 pixel_info=RelinquishVirtualMemory(pixel_info);
2197 pixel_info=rle_info;
2198 pixels=bmp_data;
2199 bmp_info.compression=BI_RLE8;
2200 }
2201 /*
2202 Write BMP for Windows, all versions, 14-byte header.
2203 */
2204 if (image->debug != MagickFalse)
2205 {
2206 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2207 " Writing BMP version %.20g datastream",(double) type);
2208 if (image->storage_class == DirectClass)
2209 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2210 " Storage class=DirectClass");
2211 else
2212 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2213 " Storage class=PseudoClass");
2214 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2215 " Image depth=%.20g",(double) image->depth);
2216 if (image->alpha_trait != UndefinedPixelTrait)
2217 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2218 " Matte=True");
2219 else
2220 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2221 " Matte=MagickFalse");
2222 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2223 " BMP bits_per_pixel=%.20g",(double) bmp_info.bits_per_pixel);
2224 switch ((int) bmp_info.compression)
2225 {
2226 case BI_RGB:
2227 {
2228 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2229 " Compression=BI_RGB");
2230 break;
2231 }
2232 case BI_RLE8:
2233 {
2234 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2235 " Compression=BI_RLE8");
2236 break;
2237 }
2238 case BI_BITFIELDS:
2239 {
2240 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2241 " Compression=BI_BITFIELDS");
2242 break;
2243 }
2244 default:
2245 {
2246 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2247 " Compression=UNKNOWN (%u)",bmp_info.compression);
2248 break;
2249 }
2250 }
2251 if (bmp_info.number_colors == 0)
2252 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2253 " Number_colors=unspecified");
2254 else
2255 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2256 " Number_colors=%u",bmp_info.number_colors);
2257 }
2258 profile_data=0;
2259 profile_size=0;
2260 profile_size_pad=0;
2261 if (profile != (StringInfo *) NULL)
2262 {
2263 profile_data=(MagickOffsetType) bmp_info.file_size-14; /* from head of BMP info header */
2264 profile_size=(MagickOffsetType) GetStringInfoLength(profile);
2265 if ((profile_size % 4) > 0)
2266 profile_size_pad=4-(profile_size%4);
2267 bmp_info.file_size+=profile_size+profile_size_pad;
2268 }
2269 (void) WriteBlob(image,2,(unsigned char *) "BM");
2270 (void) WriteBlobLSBLong(image,bmp_info.file_size);
2271 (void) WriteBlobLSBLong(image,bmp_info.ba_offset); /* always 0 */
2272 (void) WriteBlobLSBLong(image,bmp_info.offset_bits);
2273 if (type == 2)
2274 {
2275 /*
2276 Write 12-byte version 2 bitmap header.
2277 */
2278 (void) WriteBlobLSBLong(image,bmp_info.size);
2279 (void) WriteBlobLSBSignedShort(image,(signed short) bmp_info.width);
2280 (void) WriteBlobLSBSignedShort(image,(signed short) bmp_info.height);
2281 (void) WriteBlobLSBShort(image,bmp_info.planes);
2282 (void) WriteBlobLSBShort(image,bmp_info.bits_per_pixel);
2283 }
2284 else
2285 {
2286 /*
2287 Write 40-byte version 3+ bitmap header.
2288 */
2289 (void) WriteBlobLSBLong(image,bmp_info.size);
2290 (void) WriteBlobLSBSignedLong(image,(signed int) bmp_info.width);
2291 (void) WriteBlobLSBSignedLong(image,(signed int) bmp_info.height);
2292 (void) WriteBlobLSBShort(image,bmp_info.planes);
2293 (void) WriteBlobLSBShort(image,bmp_info.bits_per_pixel);
2294 (void) WriteBlobLSBLong(image,bmp_info.compression);
2295 (void) WriteBlobLSBLong(image,bmp_info.image_size);
2296 (void) WriteBlobLSBLong(image,bmp_info.x_pixels);
2297 (void) WriteBlobLSBLong(image,bmp_info.y_pixels);
2298 (void) WriteBlobLSBLong(image,bmp_info.number_colors);
2299 (void) WriteBlobLSBLong(image,bmp_info.colors_important);
2300 }
2301 if ((type > 3) && ((image->alpha_trait != UndefinedPixelTrait) ||
2302 (have_color_info != MagickFalse)))
2303 {
2304 /*
2305 Write the rest of the 108-byte BMP Version 4 header.
2306 */
2307 (void) WriteBlobLSBLong(image,bmp_info.red_mask);
2308 (void) WriteBlobLSBLong(image,bmp_info.green_mask);
2309 (void) WriteBlobLSBLong(image,bmp_info.blue_mask);
2310 (void) WriteBlobLSBLong(image,bmp_info.alpha_mask);
2311 if (profile != (StringInfo *) NULL)
2312 (void) WriteBlobLSBLong(image,0x4D424544U); /* PROFILE_EMBEDDED */
2313 else
2314 (void) WriteBlobLSBLong(image,0x73524742U); /* sRGB */
2315
2316 // bounds check, assign .0 if invalid value
2317 if (isgreater(image->chromaticity.red_primary.x, 1.0) ||
2318 !isgreater(image->chromaticity.red_primary.x, 0.0))
2319 image->chromaticity.red_primary.x = 0.0;
2320 if (isgreater(image->chromaticity.red_primary.y, 1.0) ||
2321 !isgreater(image->chromaticity.red_primary.y, 0.0))
2322 image->chromaticity.red_primary.y = 0.0;
2323 if (isgreater(image->chromaticity.green_primary.x, 1.0) ||
2324 !isgreater(image->chromaticity.green_primary.x, 0.0))
2325 image->chromaticity.green_primary.x = 0.0;
2326 if (isgreater(image->chromaticity.green_primary.y, 1.0) ||
2327 !isgreater(image->chromaticity.green_primary.y, 0.0))
2328 image->chromaticity.green_primary.y = 0.0;
2329 if (isgreater(image->chromaticity.blue_primary.x, 1.0) ||
2330 !isgreater(image->chromaticity.blue_primary.x, 0.0))
2331 image->chromaticity.blue_primary.x = 0.0;
2332 if (isgreater(image->chromaticity.blue_primary.y, 1.0) ||
2333 !isgreater(image->chromaticity.blue_primary.y, 0.0))
2334 image->chromaticity.blue_primary.y = 0.0;
2335 if (isgreater(bmp_info.gamma_scale.x, 1.0) ||
2336 !isgreater(bmp_info.gamma_scale.x, 0.0))
2337 bmp_info.gamma_scale.x = 0.0;
2338 if (isgreater(bmp_info.gamma_scale.y, 1.0) ||
2339 !isgreater(bmp_info.gamma_scale.y, 0.0))
2340 bmp_info.gamma_scale.y = 0.0;
2341 if (isgreater(bmp_info.gamma_scale.z, 1.0) ||
2342 !isgreater(bmp_info.gamma_scale.z, 0.0))
2343 bmp_info.gamma_scale.z = 0.0;
2344
2345 (void) WriteBlobLSBLong(image,(unsigned int)
2346 (image->chromaticity.red_primary.x*0x40000000));
2347 (void) WriteBlobLSBLong(image,(unsigned int)
2348 (image->chromaticity.red_primary.y*0x40000000));
2349 (void) WriteBlobLSBLong(image,(unsigned int)
2350 ((1.000f-(image->chromaticity.red_primary.x+
2351 image->chromaticity.red_primary.y))*0x40000000));
2352 (void) WriteBlobLSBLong(image,(unsigned int)
2353 (image->chromaticity.green_primary.x*0x40000000));
2354 (void) WriteBlobLSBLong(image,(unsigned int)
2355 (image->chromaticity.green_primary.y*0x40000000));
2356 (void) WriteBlobLSBLong(image,(unsigned int)
2357 ((1.000f-(image->chromaticity.green_primary.x+
2358 image->chromaticity.green_primary.y))*0x40000000));
2359 (void) WriteBlobLSBLong(image,(unsigned int)
2360 (image->chromaticity.blue_primary.x*0x40000000));
2361 (void) WriteBlobLSBLong(image,(unsigned int)
2362 (image->chromaticity.blue_primary.y*0x40000000));
2363 (void) WriteBlobLSBLong(image,(unsigned int)
2364 ((1.000f-(image->chromaticity.blue_primary.x+
2365 image->chromaticity.blue_primary.y))*0x40000000));
2366 (void) WriteBlobLSBLong(image,(unsigned int)
2367 (bmp_info.gamma_scale.x*0x10000));
2368 (void) WriteBlobLSBLong(image,(unsigned int)
2369 (bmp_info.gamma_scale.y*0x10000));
2370 (void) WriteBlobLSBLong(image,(unsigned int)
2371 (bmp_info.gamma_scale.z*0x10000));
2372 if ((image->rendering_intent != UndefinedIntent) ||
2373 (profile != (StringInfo *) NULL))
2374 {
2375 ssize_t
2376 intent;
2377
2378 switch ((int) image->rendering_intent)
2379 {
2380 case SaturationIntent:
2381 {
2382 intent=LCS_GM_BUSINESS;
2383 break;
2384 }
2385 case RelativeIntent:
2386 {
2387 intent=LCS_GM_GRAPHICS;
2388 break;
2389 }
2390 case PerceptualIntent:
2391 {
2392 intent=LCS_GM_IMAGES;
2393 break;
2394 }
2395 case AbsoluteIntent:
2396 {
2397 intent=LCS_GM_ABS_COLORIMETRIC;
2398 break;
2399 }
2400 default:
2401 {
2402 intent=0;
2403 break;
2404 }
2405 }
2406 (void) WriteBlobLSBLong(image,(unsigned int) intent);
2407 (void) WriteBlobLSBLong(image,(unsigned int) profile_data);
2408 (void) WriteBlobLSBLong(image,(unsigned int)
2409 (profile_size+profile_size_pad));
2410 (void) WriteBlobLSBLong(image,0x00); /* reserved */
2411 }
2412 }
2413 if (image->storage_class == PseudoClass)
2414 {
2415 unsigned char
2416 *bmp_colormap;
2417
2418 /*
2419 Dump colormap to file.
2420 */
2421 if (image->debug != MagickFalse)
2422 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2423 " Colormap: %.20g entries",(double) image->colors);
2424 bmp_colormap=(unsigned char *) AcquireQuantumMemory((size_t) (1UL <<
2425 bmp_info.bits_per_pixel),4*sizeof(*bmp_colormap));
2426 if (bmp_colormap == (unsigned char *) NULL)
2427 {
2428 pixel_info=RelinquishVirtualMemory(pixel_info);
2429 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2430 }
2431 q=bmp_colormap;
2432 for (i=0; i < (ssize_t) MagickMin((ssize_t) image->colors,(ssize_t) bmp_info.number_colors); i++)
2433 {
2434 *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].blue));
2435 *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].green));
2436 *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].red));
2437 if (type > 2)
2438 *q++=(unsigned char) 0x0;
2439 }
2440 for ( ; i < (ssize_t) (1UL << bmp_info.bits_per_pixel); i++)
2441 {
2442 *q++=(unsigned char) 0x00;
2443 *q++=(unsigned char) 0x00;
2444 *q++=(unsigned char) 0x00;
2445 if (type > 2)
2446 *q++=(unsigned char) 0x00;
2447 }
2448 if (type <= 2)
2449 (void) WriteBlob(image,(size_t) (3*(1L << bmp_info.bits_per_pixel)),
2450 bmp_colormap);
2451 else
2452 (void) WriteBlob(image,(size_t) (4*(1L << bmp_info.bits_per_pixel)),
2453 bmp_colormap);
2454 bmp_colormap=(unsigned char *) RelinquishMagickMemory(bmp_colormap);
2455 }
2456 if (image->debug != MagickFalse)
2457 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2458 " Pixels: %u bytes",bmp_info.image_size);
2459 (void) WriteBlob(image,(size_t) bmp_info.image_size,pixels);
2460 if (profile != (StringInfo *) NULL)
2461 {
2462 if (image->debug != MagickFalse)
2463 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2464 " Profile: %g bytes",(double) profile_size+profile_size_pad);
2465 (void) WriteBlob(image,(size_t) profile_size,GetStringInfoDatum(profile));
2466 if (profile_size_pad > 0) /* padding for 4 bytes multiple */
2467 (void) WriteBlob(image,(size_t) profile_size_pad,"\0\0\0");
2468 }
2469 pixel_info=RelinquishVirtualMemory(pixel_info);
2470 if (GetNextImageInList(image) == (Image *) NULL)
2471 break;
2472 image=SyncNextImageInList(image);
2473 status=SetImageProgress(image,SaveImagesTag,scene++,imageListLength);
2474 if (status == MagickFalse)
2475 break;
2476 } while (image_info->adjoin != MagickFalse);
2477 (void) CloseBlob(image);
2478 return(MagickTrue);
2479 }
2480