blob: 0da5ca997a80400d69e677697c4251563d4ecd9a [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
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% John Cristy %
17% Glenn Randers-Pehrson %
18% December 2001 %
19% %
20% %
cristy16af1cb2009-12-11 21:38:29 +000021% Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000022% 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% http://www.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 "magick/studio.h"
44#include "magick/blob.h"
45#include "magick/blob-private.h"
46#include "magick/cache.h"
cristy316d5172009-09-17 19:31:25 +000047#include "magick/colormap-private.h"
cristy3ed852e2009-09-05 21:47:34 +000048#include "magick/color-private.h"
cristye7e40552010-04-24 21:34:22 +000049#include "magick/colormap.h"
cristy3ed852e2009-09-05 21:47:34 +000050#include "magick/colorspace.h"
51#include "magick/exception.h"
52#include "magick/exception-private.h"
53#include "magick/image.h"
54#include "magick/image-private.h"
55#include "magick/list.h"
56#include "magick/log.h"
57#include "magick/magick.h"
58#include "magick/memory_.h"
59#include "magick/monitor.h"
60#include "magick/monitor-private.h"
61#include "magick/profile.h"
62#include "magick/quantum-private.h"
63#include "magick/static.h"
64#include "magick/string_.h"
65#include "magick/module.h"
66#include "magick/transform.h"
67
68/*
69 Macro definitions (from Windows wingdi.h).
70*/
71#undef BI_JPEG
72#define BI_JPEG 4
73#undef BI_PNG
74#define BI_PNG 5
cristy0157aea2010-04-24 21:12:18 +000075#if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__MINGW32__)
cristy3ed852e2009-09-05 21:47:34 +000076#define BI_RGB 0
77#define BI_RLE8 1
78#define BI_RLE4 2
79#define BI_BITFIELDS 3
80
81#define LCS_CALIBRATED_RBG 0
82#define LCS_sRGB 1
83#define LCS_WINDOWS_COLOR_SPACE 2
84#define PROFILE_LINKED 3
85#define PROFILE_EMBEDDED 4
86
87#define LCS_GM_BUSINESS 1 /* Saturation */
88#define LCS_GM_GRAPHICS 2 /* Relative */
89#define LCS_GM_IMAGES 4 /* Perceptual */
90#define LCS_GM_ABS_COLORIMETRIC 8 /* Absolute */
91#endif
92
93/*
94 Typedef declarations.
95*/
96typedef struct _BMPInfo
97{
98 unsigned int
99 file_size,
100 ba_offset,
101 offset_bits,
102 size;
103
104 long
105 width,
106 height;
107
108 unsigned short
109 planes,
110 bits_per_pixel;
111
112 unsigned int
113 compression,
114 image_size,
115 x_pixels,
116 y_pixels,
117 number_colors,
118 red_mask,
119 green_mask,
120 blue_mask,
121 alpha_mask,
122 colors_important;
123
124 int
125 colorspace;
126
127 PrimaryInfo
128 red_primary,
129 green_primary,
130 blue_primary,
131 gamma_scale;
132} BMPInfo;
133
134/*
135 Forward declarations.
136*/
137static MagickBooleanType
138 WriteBMPImage(const ImageInfo *,Image *);
139
140/*
141%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
142% %
143% %
144% %
145% D e c o d e I m a g e %
146% %
147% %
148% %
149%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
150%
151% DecodeImage unpacks the packed image pixels into runlength-encoded
152% pixel packets.
153%
154% The format of the DecodeImage method is:
155%
156% MagickBooleanType DecodeImage(Image *image,
157% const unsigned long compression,unsigned char *pixels)
158%
159% A description of each parameter follows:
160%
161% o image: the address of a structure of type Image.
162%
163% o compression: Zero means uncompressed. A value of 1 means the
164% compressed pixels are runlength encoded for a 256-color bitmap.
165% A value of 2 means a 16-color bitmap. A value of 3 means bitfields
166% encoding.
167%
168% o pixels: The address of a byte (8 bits) array of pixel data created by
169% the decoding process.
170%
171*/
172
173static inline long MagickAbsoluteValue(const long x)
174{
175 if (x < 0)
176 return(-x);
177 return(x);
178}
179
180static inline size_t MagickMax(const size_t x,const size_t y)
181{
182 if (x > y)
183 return(x);
184 return(y);
185}
186
187static inline long MagickMin(const long x,const long y)
188{
189 if (x < y)
190 return(x);
191 return(y);
192}
193
194static MagickBooleanType DecodeImage(Image *image,
195 const unsigned long compression,unsigned char *pixels)
196{
197 int
198 count;
199
200 long
201 y;
202
203 register long
204 i,
205 x;
206
207 register unsigned char
208 *p,
209 *q;
210
211 unsigned char
212 byte;
213
214 assert(image != (Image *) NULL);
215 assert(image->signature == MagickSignature);
216 if (image->debug != MagickFalse)
217 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
218 assert(pixels != (unsigned char *) NULL);
219 (void) ResetMagickMemory(pixels,0,(size_t) image->columns*image->rows*
220 sizeof(*pixels));
221 byte=0;
222 x=0;
223 p=pixels;
224 q=pixels+(size_t) image->columns*image->rows;
225 for (y=0; y < (long) image->rows; )
226 {
227 if ((p < pixels) || (p >= q))
228 break;
229 count=ReadBlobByte(image);
230 if (count == EOF)
231 break;
232 if (count != 0)
233 {
234 /*
235 Encoded mode.
236 */
237 count=MagickMin(count,(int) (q-p));
238 byte=(unsigned char) ReadBlobByte(image);
239 if (compression == BI_RLE8)
240 {
241 for (i=0; i < count; i++)
242 *p++=(unsigned char) byte;
243 }
244 else
245 {
246 for (i=0; i < count; i++)
247 *p++=(unsigned char)
248 ((i & 0x01) != 0 ? (byte & 0x0f) : ((byte >> 4) & 0x0f));
249 }
250 x+=count;
251 }
252 else
253 {
254 /*
255 Escape mode.
256 */
257 count=ReadBlobByte(image);
258 if (count == 0x01)
259 return(MagickTrue);
260 switch (count)
261 {
262 case 0x00:
263 {
264 /*
265 End of line.
266 */
267 x=0;
268 y++;
269 p=pixels+y*image->columns;
270 break;
271 }
272 case 0x02:
273 {
274 /*
275 Delta mode.
276 */
277 x+=ReadBlobByte(image);
278 y+=ReadBlobByte(image);
279 p=pixels+y*image->columns+x;
280 break;
281 }
282 default:
283 {
284 /*
285 Absolute mode.
286 */
287 count=MagickMin(count,(int) (q-p));
288 if (compression == BI_RLE8)
289 for (i=0; i < count; i++)
290 *p++=(unsigned char) ReadBlobByte(image);
291 else
292 for (i=0; i < count; i++)
293 {
294 if ((i & 0x01) == 0)
295 byte=(unsigned char) ReadBlobByte(image);
296 *p++=(unsigned char)
297 ((i & 0x01) != 0 ? (byte & 0x0f) : ((byte >> 4) & 0x0f));
298 }
299 x+=count;
300 /*
301 Read pad byte.
302 */
303 if (compression == BI_RLE8)
304 {
305 if ((count & 0x01) != 0)
306 (void) ReadBlobByte(image);
307 }
308 else
309 if (((count & 0x03) == 1) || ((count & 0x03) == 2))
310 (void) ReadBlobByte(image);
311 break;
312 }
313 }
314 }
315 if (SetImageProgress(image,LoadImageTag,y,image->rows) == MagickFalse)
316 break;
317 }
318 (void) ReadBlobByte(image); /* end of line */
319 (void) ReadBlobByte(image);
320 return(MagickTrue);
321}
322
323/*
324%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
325% %
326% %
327% %
328% E n c o d e I m a g e %
329% %
330% %
331% %
332%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
333%
334% EncodeImage compresses pixels using a runlength encoded format.
335%
336% The format of the EncodeImage method is:
337%
338% static MagickBooleanType EncodeImage(Image *image,
339% const unsigned long bytes_per_line,const unsigned char *pixels,
340% unsigned char *compressed_pixels)
341%
342% A description of each parameter follows:
343%
344% o image: The image.
345%
346% o bytes_per_line: the number of bytes in a scanline of compressed pixels
347%
348% o pixels: The address of a byte (8 bits) array of pixel data created by
349% the compression process.
350%
351% o compressed_pixels: The address of a byte (8 bits) array of compressed
352% pixel data.
353%
354*/
355static size_t EncodeImage(Image *image,const unsigned long bytes_per_line,
356 const unsigned char *pixels,unsigned char *compressed_pixels)
357{
358 long
359 y;
360
361 MagickBooleanType
362 status;
363
364 register const unsigned char
365 *p;
366
367 register long
368 i,
369 x;
370
371 register unsigned char
372 *q;
373
374 /*
375 Runlength encode pixels.
376 */
377 assert(image != (Image *) NULL);
378 assert(image->signature == MagickSignature);
379 if (image->debug != MagickFalse)
380 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
381 assert(pixels != (const unsigned char *) NULL);
382 assert(compressed_pixels != (unsigned char *) NULL);
383 p=pixels;
384 q=compressed_pixels;
385 i=0;
386 for (y=0; y < (long) image->rows; y++)
387 {
388 for (x=0; x < (long) bytes_per_line; x+=i)
389 {
390 /*
391 Determine runlength.
392 */
393 for (i=1; ((x+i) < (long) bytes_per_line); i++)
394 if ((i == 255) || (*(p+i) != *p))
395 break;
396 *q++=(unsigned char) i;
397 *q++=(*p);
398 p+=i;
399 }
400 /*
401 End of line.
402 */
403 *q++=(unsigned char) 0x00;
404 *q++=(unsigned char) 0x00;
405 status=SetImageProgress(image,SaveImageTag,y,image->rows);
406 if (status == MagickFalse)
407 break;
408 }
409 /*
410 End of bitmap.
411 */
412 *q++=(unsigned char) 0x00;
413 *q++=(unsigned char) 0x01;
414 return((size_t) (q-compressed_pixels));
415}
416
417/*
418%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
419% %
420% %
421% %
422% I s B M P %
423% %
424% %
425% %
426%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
427%
428% IsBMP() returns MagickTrue if the image format type, identified by the
429% magick string, is BMP.
430%
431% The format of the IsBMP method is:
432%
433% MagickBooleanType IsBMP(const unsigned char *magick,const size_t length)
434%
435% A description of each parameter follows:
436%
437% o magick: compare image format pattern against these bytes.
438%
439% o length: Specifies the length of the magick string.
440%
441*/
442static MagickBooleanType IsBMP(const unsigned char *magick,const size_t length)
443{
444 if (length < 2)
445 return(MagickFalse);
446 if ((LocaleNCompare((char *) magick,"BA",2) == 0) ||
447 (LocaleNCompare((char *) magick,"BM",2) == 0) ||
448 (LocaleNCompare((char *) magick,"IC",2) == 0) ||
449 (LocaleNCompare((char *) magick,"PI",2) == 0) ||
450 (LocaleNCompare((char *) magick,"CI",2) == 0) ||
451 (LocaleNCompare((char *) magick,"CP",2) == 0))
452 return(MagickTrue);
453 return(MagickFalse);
454}
455
456/*
457%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
458% %
459% %
460% %
461% R e a d B M P I m a g e %
462% %
463% %
464% %
465%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
466%
467% ReadBMPImage() reads a Microsoft Windows bitmap image file, Version
468% 2, 3 (for Windows or NT), or 4, and returns it. It allocates the memory
469% necessary for the new Image structure and returns a pointer to the new
470% image.
471%
472% The format of the ReadBMPImage method is:
473%
474% image=ReadBMPImage(image_info)
475%
476% A description of each parameter follows:
477%
478% o image_info: the image info.
479%
480% o exception: return any errors or warnings in this structure.
481%
482*/
483
484static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
485{
486 BMPInfo
487 bmp_info;
488
489 Image
490 *image;
491
492 IndexPacket
493 index;
494
495 long
496 y;
497
498 MagickBooleanType
499 status;
500
501 MagickOffsetType
502 offset,
503 start_position;
504
505 register IndexPacket
506 *indexes;
507
508 register long
509 x;
510
511 register PixelPacket
512 *q;
513
514 register long
515 i;
516
517 register unsigned char
518 *p;
519
520 ssize_t
521 count;
522
523 size_t
524 length;
525
526 unsigned char
527 magick[12],
528 *pixels;
529
530 unsigned long
531 bit,
532 blue,
533 bytes_per_line,
534 green,
535 opacity,
536 red;
537
538 /*
539 Open image file.
540 */
541 assert(image_info != (const ImageInfo *) NULL);
542 assert(image_info->signature == MagickSignature);
543 if (image_info->debug != MagickFalse)
544 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
545 image_info->filename);
546 assert(exception != (ExceptionInfo *) NULL);
547 assert(exception->signature == MagickSignature);
548 image=AcquireImage(image_info);
549 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
550 if (status == MagickFalse)
551 {
552 image=DestroyImageList(image);
553 return((Image *) NULL);
554 }
555 /*
556 Determine if this a BMP file.
557 */
558 (void) ResetMagickMemory(&bmp_info,0,sizeof(bmp_info));
559 bmp_info.ba_offset=0;
560 start_position=0;
561 count=ReadBlob(image,2,magick);
562 do
563 {
564 LongPixelPacket
565 shift;
566
567 PixelPacket
568 quantum_bits;
569
570 unsigned long
571 profile_data,
572 profile_size;
573
574 /*
575 Verify BMP identifier.
576 */
577 if (bmp_info.ba_offset == 0)
578 start_position=TellBlob(image)-2;
579 bmp_info.ba_offset=0;
580 while (LocaleNCompare((char *) magick,"BA",2) == 0)
581 {
582 bmp_info.file_size=ReadBlobLSBLong(image);
583 bmp_info.ba_offset=ReadBlobLSBLong(image);
584 bmp_info.offset_bits=ReadBlobLSBLong(image);
585 count=ReadBlob(image,2,magick);
586 if (count != 2)
587 break;
588 }
589 if (image->debug != MagickFalse)
590 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Magick: %c%c",
591 magick[0],magick[1]);
592 if ((count == 0) || ((LocaleNCompare((char *) magick,"BM",2) != 0) &&
593 (LocaleNCompare((char *) magick,"CI",2) != 0)))
594 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
595 bmp_info.file_size=ReadBlobLSBLong(image);
596 (void) ReadBlobLSBLong(image);
597 bmp_info.offset_bits=ReadBlobLSBLong(image);
598 bmp_info.size=ReadBlobLSBLong(image);
599 if (image->debug != MagickFalse)
600 (void) LogMagickEvent(CoderEvent,GetMagickModule()," BMP size: %u",
601 bmp_info.size);
602 if (bmp_info.size == 12)
603 {
604 /*
605 OS/2 BMP image file.
606 */
607 bmp_info.width=(short) ReadBlobLSBShort(image);
608 bmp_info.height=(short) ReadBlobLSBShort(image);
609 bmp_info.planes=ReadBlobLSBShort(image);
610 bmp_info.bits_per_pixel=ReadBlobLSBShort(image);
611 bmp_info.x_pixels=0;
612 bmp_info.y_pixels=0;
613 bmp_info.number_colors=0;
614 bmp_info.compression=BI_RGB;
615 bmp_info.image_size=0;
616 bmp_info.alpha_mask=0;
617 if (image->debug != MagickFalse)
618 {
619 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
620 " Format: OS/2 Bitmap");
621 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
622 " Geometry: %ldx%ld",bmp_info.width,bmp_info.height);
623 }
624 }
625 else
626 {
627 /*
628 Microsoft Windows BMP image file.
629 */
630 if (bmp_info.size < 40)
631 ThrowReaderException(CorruptImageError,"NonOS2HeaderSizeError");
632 bmp_info.width=(int) ReadBlobLSBLong(image);
633 bmp_info.height=(int) ReadBlobLSBLong(image);
634 bmp_info.planes=ReadBlobLSBShort(image);
635 bmp_info.bits_per_pixel=ReadBlobLSBShort(image);
636 bmp_info.compression=ReadBlobLSBLong(image);
637 bmp_info.image_size=ReadBlobLSBLong(image);
638 bmp_info.x_pixels=ReadBlobLSBLong(image);
639 bmp_info.y_pixels=ReadBlobLSBLong(image);
640 bmp_info.number_colors=ReadBlobLSBLong(image);
641 bmp_info.colors_important=ReadBlobLSBLong(image);
642 profile_data=0;
643 profile_size=0;
644 if (image->debug != MagickFalse)
645 {
646 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
647 " Format: MS Windows bitmap");
648 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
649 " Geometry: %ldx%ld",bmp_info.width,bmp_info.height);
650 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
651 " Bits per pixel: %d",bmp_info.bits_per_pixel);
652 switch ((int) bmp_info.compression)
653 {
654 case BI_RGB:
655 {
656 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
657 " Compression: BI_RGB");
658 break;
659 }
660 case BI_RLE4:
661 {
662 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
663 " Compression: BI_RLE4");
664 break;
665 }
666 case BI_RLE8:
667 {
668 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
669 " Compression: BI_RLE8");
670 break;
671 }
672 case BI_BITFIELDS:
673 {
674 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
675 " Compression: BI_BITFIELDS");
676 break;
677 }
678 case BI_PNG:
679 {
680 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
681 " Compression: BI_PNG");
682 break;
683 }
684 case BI_JPEG:
685 {
686 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
687 " Compression: BI_JPEG");
688 break;
689 }
690 default:
691 {
692 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
693 " Compression: UNKNOWN (%u)",bmp_info.compression);
694 }
695 }
696 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
697 " Number of colors: %u",bmp_info.number_colors);
698 }
699 bmp_info.red_mask=ReadBlobLSBLong(image);
700 bmp_info.green_mask=ReadBlobLSBLong(image);
701 bmp_info.blue_mask=ReadBlobLSBLong(image);
702 if (bmp_info.size > 40)
703 {
704 double
705 sum;
706
707 /*
708 Read color management information.
709 */
710 bmp_info.alpha_mask=ReadBlobLSBLong(image);
711 bmp_info.colorspace=(long) ReadBlobLSBLong(image);
712 /*
713 Decode 2^30 fixed point formatted CIE primaries.
714 */
715 bmp_info.red_primary.x=(double) ReadBlobLSBLong(image)/0x3ffffff;
716 bmp_info.red_primary.y=(double) ReadBlobLSBLong(image)/0x3ffffff;
717 bmp_info.red_primary.z=(double) ReadBlobLSBLong(image)/0x3ffffff;
718 bmp_info.green_primary.x=(double) ReadBlobLSBLong(image)/0x3ffffff;
719 bmp_info.green_primary.y=(double) ReadBlobLSBLong(image)/0x3ffffff;
720 bmp_info.green_primary.z=(double) ReadBlobLSBLong(image)/0x3ffffff;
721 bmp_info.blue_primary.x=(double) ReadBlobLSBLong(image)/0x3ffffff;
722 bmp_info.blue_primary.y=(double) ReadBlobLSBLong(image)/0x3ffffff;
723 bmp_info.blue_primary.z=(double) ReadBlobLSBLong(image)/0x3ffffff;
724 sum=bmp_info.red_primary.x+bmp_info.red_primary.x+
725 bmp_info.red_primary.z;
726 image->chromaticity.red_primary.x/=sum;
727 image->chromaticity.red_primary.y/=sum;
728 sum=bmp_info.green_primary.x+bmp_info.green_primary.x+
729 bmp_info.green_primary.z;
730 image->chromaticity.green_primary.x/=sum;
731 image->chromaticity.green_primary.y/=sum;
732 sum=bmp_info.blue_primary.x+bmp_info.blue_primary.x+
733 bmp_info.blue_primary.z;
734 image->chromaticity.blue_primary.x/=sum;
735 image->chromaticity.blue_primary.y/=sum;
736 /*
737 Decode 16^16 fixed point formatted gamma_scales.
738 */
739 bmp_info.gamma_scale.x=(double) ReadBlobLSBLong(image)/0xffff;
740 bmp_info.gamma_scale.y=(double) ReadBlobLSBLong(image)/0xffff;
741 bmp_info.gamma_scale.z=(double) ReadBlobLSBLong(image)/0xffff;
742 /*
743 Compute a single gamma from the BMP 3-channel gamma.
744 */
745 image->gamma=(bmp_info.gamma_scale.x+bmp_info.gamma_scale.y+
746 bmp_info.gamma_scale.z)/3.0;
747 }
748 if (bmp_info.size > 108)
749 {
750 unsigned long
751 intent;
752
753 /*
754 Read BMP Version 5 color management information.
755 */
756 intent=ReadBlobLSBLong(image);
757 switch ((int) intent)
758 {
759 case LCS_GM_BUSINESS:
760 {
761 image->rendering_intent=SaturationIntent;
762 break;
763 }
764 case LCS_GM_GRAPHICS:
765 {
766 image->rendering_intent=RelativeIntent;
767 break;
768 }
769 case LCS_GM_IMAGES:
770 {
771 image->rendering_intent=PerceptualIntent;
772 break;
773 }
774 case LCS_GM_ABS_COLORIMETRIC:
775 {
776 image->rendering_intent=AbsoluteIntent;
777 break;
778 }
779 }
780 profile_data=ReadBlobLSBLong(image);
781 profile_size=ReadBlobLSBLong(image);
782 (void) ReadBlobLSBLong(image); /* Reserved byte */
783 }
784 }
785 if ((bmp_info.compression != BI_RGB) &&
786 ((MagickSizeType) bmp_info.file_size != GetBlobSize(image)))
787 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
788 "LengthAndFilesizeDoNotMatch","`%s'",image->filename);
789 if (bmp_info.width <= 0)
790 ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize");
791 if (bmp_info.height == 0)
792 ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize");
793 if (bmp_info.planes != 1)
794 ThrowReaderException(CorruptImageError,"StaticPlanesValueNotEqualToOne");
795 if ((bmp_info.bits_per_pixel != 1) && (bmp_info.bits_per_pixel != 4) &&
796 (bmp_info.bits_per_pixel != 8) && (bmp_info.bits_per_pixel != 16) &&
797 (bmp_info.bits_per_pixel != 24) && (bmp_info.bits_per_pixel != 32))
798 ThrowReaderException(CorruptImageError,"UnrecognizedBitsPerPixel");
799 if (bmp_info.number_colors > (1U << bmp_info.bits_per_pixel))
800 {
801 if (bmp_info.bits_per_pixel < 24)
802 ThrowReaderException(CorruptImageError,"UnrecognizedNumberOfColors");
803 bmp_info.number_colors=0;
804 }
805 if (bmp_info.compression > 3)
806 ThrowReaderException(CorruptImageError,"UnrecognizedImageCompression");
807 if ((bmp_info.compression == 1) && (bmp_info.bits_per_pixel != 8))
808 ThrowReaderException(CorruptImageError,"UnrecognizedBitsPerPixel");
809 if ((bmp_info.compression == 2) && (bmp_info.bits_per_pixel != 4))
810 ThrowReaderException(CorruptImageError,"UnrecognizedBitsPerPixel");
811 if ((bmp_info.compression == 3) && (bmp_info.bits_per_pixel < 16))
812 ThrowReaderException(CorruptImageError,"UnrecognizedBitsPerPixel");
813 switch (bmp_info.compression)
814 {
815 case BI_RGB:
816 case BI_RLE8:
817 case BI_RLE4:
818 case BI_BITFIELDS:
819 break;
820 case BI_JPEG:
821 ThrowReaderException(CoderError,"JPEGCompressNotSupported");
822 case BI_PNG:
823 ThrowReaderException(CoderError,"PNGCompressNotSupported");
824 default:
825 ThrowReaderException(CorruptImageError,"UnrecognizedImageCompression");
826 }
827 image->columns=(unsigned long) MagickAbsoluteValue(bmp_info.width);
828 image->rows=(unsigned long) MagickAbsoluteValue(bmp_info.height);
829 image->depth=bmp_info.bits_per_pixel <= 8 ? bmp_info.bits_per_pixel : 8;
830 image->matte=bmp_info.alpha_mask != 0 ? MagickTrue : MagickFalse;
831 if ((bmp_info.number_colors != 0) || (bmp_info.bits_per_pixel < 16))
832 {
833 image->storage_class=PseudoClass;
834 image->colors=bmp_info.number_colors;
835 if (image->colors == 0)
836 image->colors=1L << bmp_info.bits_per_pixel;
837 }
838 if (image->storage_class == PseudoClass)
839 {
840 unsigned char
841 *bmp_colormap;
842
843 size_t
844 packet_size;
845
846 /*
847 Read BMP raster colormap.
848 */
849 if (image->debug != MagickFalse)
850 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
851 " Reading colormap of %ld colors",image->colors);
852 if (AcquireImageColormap(image,image->colors) == MagickFalse)
853 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
854 bmp_colormap=(unsigned char *) AcquireQuantumMemory((size_t)
855 image->colors,4*sizeof(*bmp_colormap));
856 if (bmp_colormap == (unsigned char *) NULL)
857 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
858 if ((bmp_info.size == 12) || (bmp_info.size == 64))
859 packet_size=3;
860 else
861 packet_size=4;
862 offset=SeekBlob(image,start_position+14+bmp_info.size,SEEK_SET);
863 if (offset < 0)
864 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
865 count=ReadBlob(image,packet_size*image->colors,bmp_colormap);
866 if (count != (ssize_t) (packet_size*image->colors))
867 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
868 p=bmp_colormap;
869 for (i=0; i < (long) image->colors; i++)
870 {
871 image->colormap[i].blue=ScaleCharToQuantum(*p++);
872 image->colormap[i].green=ScaleCharToQuantum(*p++);
873 image->colormap[i].red=ScaleCharToQuantum(*p++);
874 if (packet_size == 4)
875 p++;
876 }
877 bmp_colormap=(unsigned char *) RelinquishMagickMemory(bmp_colormap);
878 }
879 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
880 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
881 break;
882 /*
883 Read image data.
884 */
885 offset=SeekBlob(image,start_position+bmp_info.offset_bits,SEEK_SET);
886 if (offset < 0)
887 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
888 if (bmp_info.compression == BI_RLE4)
889 bmp_info.bits_per_pixel<<=1;
890 bytes_per_line=4*((image->columns*bmp_info.bits_per_pixel+31)/32);
891 length=(size_t) bytes_per_line*image->rows;
892 pixels=(unsigned char *) AcquireQuantumMemory((size_t) image->rows,
893 MagickMax(bytes_per_line,image->columns+256UL)*sizeof(*pixels));
894 if (pixels == (unsigned char *) NULL)
895 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
896 if ((bmp_info.compression == BI_RGB) ||
897 (bmp_info.compression == BI_BITFIELDS))
898 {
899 if (image->debug != MagickFalse)
900 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
901 " Reading pixels (%ld bytes)",(long) length);
902 count=ReadBlob(image,length,pixels);
903 if (count != (ssize_t) length)
904 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
905 }
906 else
907 {
908 /*
909 Convert run-length encoded raster pixels.
910 */
911 status=DecodeImage(image,bmp_info.compression,pixels);
912 if (status == MagickFalse)
913 ThrowReaderException(CorruptImageError,
914 "UnableToRunlengthDecodeImage");
915 }
916 /*
917 Initialize image structure.
918 */
919 image->x_resolution=(double) bmp_info.x_pixels/100.0;
920 image->y_resolution=(double) bmp_info.y_pixels/100.0;
921 image->units=PixelsPerCentimeterResolution;
922 /*
923 Convert BMP raster image to pixel packets.
924 */
925 if (bmp_info.compression == BI_RGB)
926 {
927 bmp_info.alpha_mask=0;
928 bmp_info.red_mask=0x00ff0000U;
929 bmp_info.green_mask=0x0000ff00U;
930 bmp_info.blue_mask=0x000000ffU;
931 if (bmp_info.bits_per_pixel == 16)
932 {
933 /*
934 RGB555.
935 */
936 bmp_info.red_mask=0x00007c00U;
937 bmp_info.green_mask=0x000003e0U;
938 bmp_info.blue_mask=0x0000001fU;
939 }
940 }
941 if ((bmp_info.bits_per_pixel == 16) || (bmp_info.bits_per_pixel == 32))
942 {
943 register unsigned long
944 sample;
945
946 /*
947 Get shift and quantum bits info from bitfield masks.
948 */
949 (void) ResetMagickMemory(&shift,0,sizeof(shift));
950 (void) ResetMagickMemory(&quantum_bits,0,sizeof(quantum_bits));
951 if (bmp_info.red_mask != 0)
952 while (((bmp_info.red_mask << shift.red) & 0x80000000UL) == 0)
953 shift.red++;
954 if (bmp_info.green_mask != 0)
955 while (((bmp_info.green_mask << shift.green) & 0x80000000UL) == 0)
956 shift.green++;
957 if (bmp_info.blue_mask != 0)
958 while (((bmp_info.blue_mask << shift.blue) & 0x80000000UL) == 0)
959 shift.blue++;
960 if (bmp_info.alpha_mask != 0)
961 while (((bmp_info.alpha_mask << shift.opacity) & 0x80000000UL) == 0)
962 shift.opacity++;
963 sample=shift.red;
964 while (((bmp_info.red_mask << sample) & 0x80000000UL) != 0)
965 sample++;
966 quantum_bits.red=(Quantum) (sample-shift.red);
967 sample=shift.green;
968 while (((bmp_info.green_mask << sample) & 0x80000000UL) != 0)
969 sample++;
970 quantum_bits.green=(Quantum) (sample-shift.green);
971 sample=shift.blue;
972 while (((bmp_info.blue_mask << sample) & 0x80000000UL) != 0)
973 sample++;
974 quantum_bits.blue=(Quantum) (sample-shift.blue);
975 sample=shift.opacity;
976 while (((bmp_info.alpha_mask << sample) & 0x80000000UL) != 0)
977 sample++;
978 quantum_bits.opacity=(Quantum) (sample-shift.opacity);
979 }
980 switch (bmp_info.bits_per_pixel)
981 {
982 case 1:
983 {
984 /*
985 Convert bitmap scanline.
986 */
987 for (y=(long) image->rows-1; y >= 0; y--)
988 {
989 p=pixels+(image->rows-y-1)*bytes_per_line;
990 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
991 if (q == (PixelPacket *) NULL)
992 break;
993 indexes=GetAuthenticIndexQueue(image);
994 for (x=0; x < ((long) image->columns-7); x+=8)
995 {
996 for (bit=0; bit < 8; bit++)
997 {
998 index=(IndexPacket) (((*p) & (0x80 >> bit)) != 0 ? 0x01 : 0x00);
999 indexes[x+bit]=index;
1000 *q++=image->colormap[(long) index];
1001 }
1002 p++;
1003 }
1004 if ((image->columns % 8) != 0)
1005 {
1006 for (bit=0; bit < (image->columns % 8); bit++)
1007 {
1008 index=(IndexPacket) (((*p) & (0x80 >> bit)) != 0 ? 0x01 : 0x00);
1009 indexes[x+bit]=index;
1010 *q++=image->colormap[(long) index];
1011 }
1012 p++;
1013 }
1014 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1015 break;
1016 if (image->previous == (Image *) NULL)
1017 {
1018 status=SetImageProgress(image,LoadImageTag,y,image->rows);
1019 if (status == MagickFalse)
1020 break;
1021 }
1022 }
1023 break;
1024 }
1025 case 4:
1026 {
1027 /*
1028 Convert PseudoColor scanline.
1029 */
1030 for (y=(long) image->rows-1; y >= 0; y--)
1031 {
1032 p=pixels+(image->rows-y-1)*bytes_per_line;
1033 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1034 if (q == (PixelPacket *) NULL)
1035 break;
1036 indexes=GetAuthenticIndexQueue(image);
1037 for (x=0; x < ((long) image->columns-1); x+=2)
1038 {
1039 index=ConstrainColormapIndex(image,(*p >> 4) & 0x0f);
1040 indexes[x]=index;
1041 *q++=image->colormap[(long) index];
1042 index=ConstrainColormapIndex(image,*p & 0x0f);
1043 indexes[x+1]=index;
1044 *q++=image->colormap[(long) index];
1045 p++;
1046 }
1047 if ((image->columns % 2) != 0)
1048 {
1049 index=ConstrainColormapIndex(image,(*p >> 4) & 0xf);
1050 indexes[x]=index;
1051 *q++=image->colormap[(long) index];
1052 p++;
1053 }
1054 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1055 break;
1056 if (image->previous == (Image *) NULL)
1057 {
1058 status=SetImageProgress(image,LoadImageTag,y,image->rows);
1059 if (status == MagickFalse)
1060 break;
1061 }
1062 }
1063 break;
1064 }
1065 case 8:
1066 {
1067 /*
1068 Convert PseudoColor scanline.
1069 */
1070 if ((bmp_info.compression == BI_RLE8) ||
1071 (bmp_info.compression == BI_RLE4))
1072 bytes_per_line=image->columns;
1073 for (y=(long) image->rows-1; y >= 0; y--)
1074 {
1075 p=pixels+(image->rows-y-1)*bytes_per_line;
1076 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1077 if (q == (PixelPacket *) NULL)
1078 break;
1079 indexes=GetAuthenticIndexQueue(image);
1080 for (x = (long)image->columns; x != 0; --x)
1081 {
1082 index=ConstrainColormapIndex(image,*p);
1083 *indexes++=index;
1084 *q=image->colormap[(long) index];
1085 p++;
1086 q++;
1087 }
1088 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1089 break;
1090 offset=(MagickOffsetType) (image->rows-y-1);
1091 if (image->previous == (Image *) NULL)
1092 {
1093 status=SetImageProgress(image,LoadImageTag,y,image->rows);
1094 if (status == MagickFalse)
1095 break;
1096 }
1097 }
1098 break;
1099 }
1100 case 16:
1101 {
1102 unsigned long
1103 pixel;
1104
1105 /*
1106 Convert bitfield encoded 16-bit PseudoColor scanline.
1107 */
1108 if (bmp_info.compression != BI_RGB &&
1109 bmp_info.compression != BI_BITFIELDS)
1110 ThrowReaderException(CorruptImageError,
1111 "UnrecognizedImageCompression");
1112 bytes_per_line=2*(image->columns+image->columns % 2);
1113 image->storage_class=DirectClass;
1114 for (y=(long) image->rows-1; y >= 0; y--)
1115 {
1116 p=pixels+(image->rows-y-1)*bytes_per_line;
1117 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1118 if (q == (PixelPacket *) NULL)
1119 break;
1120 for (x=0; x < (long) image->columns; x++)
1121 {
1122 pixel=(unsigned long) (*p++);
1123 pixel|=(*p++) << 8;
1124 red=((pixel & bmp_info.red_mask) << shift.red) >> 16;
1125 if (quantum_bits.red == 5)
1126 red|=((red & 0xe000) >> 5);
1127 if (quantum_bits.red <= 8)
1128 red|=((red & 0xff00) >> 8);
1129 green=((pixel & bmp_info.green_mask) << shift.green) >> 16;
1130 if (quantum_bits.green == 5)
1131 green|=((green & 0xe000) >> 5);
1132 if (quantum_bits.green == 6)
1133 green|=((green & 0xc000) >> 6);
1134 if (quantum_bits.green <= 8)
1135 green|=((green & 0xff00) >> 8);
1136 blue=((pixel & bmp_info.blue_mask) << shift.blue) >> 16;
1137 if (quantum_bits.blue == 5)
1138 blue|=((blue & 0xe000) >> 5);
1139 if (quantum_bits.blue <= 8)
1140 blue|=((blue & 0xff00) >> 8);
1141 opacity=((pixel & bmp_info.alpha_mask) << shift.opacity) >> 16;
1142 if (quantum_bits.opacity <= 8)
1143 opacity|=((opacity & 0xff00) >> 8);
1144 q->red=ScaleShortToQuantum((unsigned short) red);
1145 q->green=ScaleShortToQuantum((unsigned short) green);
1146 q->blue=ScaleShortToQuantum((unsigned short) blue);
cristyce70c172010-01-07 17:15:30 +00001147 SetOpacityPixelComponent(q,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00001148 if (image->matte != MagickFalse)
cristyce8c2772010-02-26 23:43:26 +00001149 q->opacity=ScaleShortToQuantum((unsigned short) (65535-opacity));
cristy3ed852e2009-09-05 21:47:34 +00001150 q++;
1151 }
1152 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1153 break;
1154 offset=(MagickOffsetType) (image->rows-y-1);
1155 if (image->previous == (Image *) NULL)
1156 {
1157 status=SetImageProgress(image,LoadImageTag,y,image->rows);
1158 if (status == MagickFalse)
1159 break;
1160 }
1161 }
1162 break;
1163 }
1164 case 24:
1165 {
1166 /*
1167 Convert DirectColor scanline.
1168 */
1169 bytes_per_line=4*((image->columns*24+31)/32);
1170 for (y=(long) image->rows-1; y >= 0; y--)
1171 {
1172 p=pixels+(image->rows-y-1)*bytes_per_line;
1173 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1174 if (q == (PixelPacket *) NULL)
1175 break;
1176 for (x=0; x < (long) image->columns; x++)
1177 {
1178 q->blue=ScaleCharToQuantum(*p++);
1179 q->green=ScaleCharToQuantum(*p++);
1180 q->red=ScaleCharToQuantum(*p++);
1181 q++;
1182 }
1183 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1184 break;
1185 offset=(MagickOffsetType) (image->rows-y-1);
1186 if (image->previous == (Image *) NULL)
1187 {
1188 status=SetImageProgress(image,LoadImageTag,y,image->rows);
1189 if (status == MagickFalse)
1190 break;
1191 }
1192 }
1193 break;
1194 }
1195 case 32:
1196 {
1197 /*
1198 Convert bitfield encoded DirectColor scanline.
1199 */
1200 if ((bmp_info.compression != BI_RGB) &&
1201 (bmp_info.compression != BI_BITFIELDS))
1202 ThrowReaderException(CorruptImageError,
1203 "UnrecognizedImageCompression");
1204 bytes_per_line=4*(image->columns);
1205 for (y=(long) image->rows-1; y >= 0; y--)
1206 {
1207 unsigned long
1208 pixel;
1209
1210 p=pixels+(image->rows-y-1)*bytes_per_line;
1211 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1212 if (q == (PixelPacket *) NULL)
1213 break;
1214 for (x=0; x < (long) image->columns; x++)
1215 {
1216 pixel=(unsigned long) (*p++);
1217 pixel|=(*p++ << 8);
1218 pixel|=(*p++ << 16);
1219 pixel|=(*p++ << 24);
1220 red=((pixel & bmp_info.red_mask) << shift.red) >> 16;
1221 if (quantum_bits.red == 8)
1222 red|=(red >> 8);
1223 green=((pixel & bmp_info.green_mask) << shift.green) >> 16;
1224 if (quantum_bits.green == 8)
1225 green|=(green >> 8);
1226 blue=((pixel & bmp_info.blue_mask) << shift.blue) >> 16;
1227 if (quantum_bits.blue == 8)
1228 blue|=(blue >> 8);
1229 opacity=((pixel & bmp_info.alpha_mask) << shift.opacity) >> 16;
1230 if (quantum_bits.opacity == 8)
1231 opacity|=(opacity >> 8);
1232 q->red=ScaleShortToQuantum((unsigned short) red);
1233 q->green=ScaleShortToQuantum((unsigned short) green);
1234 q->blue=ScaleShortToQuantum((unsigned short) blue);
cristyce70c172010-01-07 17:15:30 +00001235 SetOpacityPixelComponent(q,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00001236 if (image->matte != MagickFalse)
cristy228ab742010-02-24 13:49:34 +00001237 q->opacity=ScaleShortToQuantum((unsigned short) (65535-opacity));
cristy3ed852e2009-09-05 21:47:34 +00001238 q++;
1239 }
1240 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1241 break;
1242 offset=(MagickOffsetType) (image->rows-y-1);
1243 if (image->previous == (Image *) NULL)
1244 {
1245 status=SetImageProgress(image,LoadImageTag,y,image->rows);
1246 if (status == MagickFalse)
1247 break;
1248 }
1249 }
1250 break;
1251 }
1252 default:
1253 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1254 }
1255 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1256 if (EOFBlob(image) != MagickFalse)
1257 {
1258 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
1259 image->filename);
1260 break;
1261 }
1262 if (bmp_info.height < 0)
1263 {
1264 Image
1265 *flipped_image;
1266
1267 /*
1268 Correct image orientation.
1269 */
1270 flipped_image=FlipImage(image,exception);
cristy65e3b002010-04-13 21:20:56 +00001271 if (flipped_image != (Image *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001272 {
cristy65e3b002010-04-13 21:20:56 +00001273 DuplicateBlob(flipped_image,image);
1274 image=DestroyImage(image);
1275 image=flipped_image;
cristy3ed852e2009-09-05 21:47:34 +00001276 }
cristy3ed852e2009-09-05 21:47:34 +00001277 }
1278 /*
1279 Proceed to next image.
1280 */
1281 if (image_info->number_scenes != 0)
1282 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1283 break;
1284 *magick='\0';
1285 if (bmp_info.ba_offset != 0)
1286 {
1287 offset=SeekBlob(image,(MagickOffsetType) bmp_info.ba_offset,SEEK_SET);
1288 if (offset < 0)
1289 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1290 }
1291 count=ReadBlob(image,2,magick);
1292 if ((count == 2) && (IsBMP(magick,2) != MagickFalse))
1293 {
1294 /*
1295 Acquire next image structure.
1296 */
1297 AcquireNextImage(image_info,image);
1298 if (GetNextImageInList(image) == (Image *) NULL)
1299 {
1300 image=DestroyImageList(image);
1301 return((Image *) NULL);
1302 }
1303 image=SyncNextImageInList(image);
1304 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
1305 GetBlobSize(image));
1306 if (status == MagickFalse)
1307 break;
1308 }
1309 } while (IsBMP(magick,2) != MagickFalse);
1310 (void) CloseBlob(image);
1311 return(GetFirstImageInList(image));
1312}
1313
1314/*
1315%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1316% %
1317% %
1318% %
1319% R e g i s t e r B M P I m a g e %
1320% %
1321% %
1322% %
1323%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1324%
1325% RegisterBMPImage() adds attributes for the BMP image format to
1326% the list of supported formats. The attributes include the image format
1327% tag, a method to read and/or write the format, whether the format
1328% supports the saving of more than one frame to the same file or blob,
1329% whether the format supports native in-memory I/O, and a brief
1330% description of the format.
1331%
1332% The format of the RegisterBMPImage method is:
1333%
1334% unsigned long RegisterBMPImage(void)
1335%
1336*/
1337ModuleExport unsigned long RegisterBMPImage(void)
1338{
1339 MagickInfo
1340 *entry;
1341
1342 entry=SetMagickInfo("BMP");
1343 entry->decoder=(DecodeImageHandler *) ReadBMPImage;
1344 entry->encoder=(EncodeImageHandler *) WriteBMPImage;
1345 entry->magick=(IsImageFormatHandler *) IsBMP;
cristy2e3d5242010-04-16 23:44:55 +00001346 entry->description=ConstantString("Microsoft Windows bitmap image");
cristy3ed852e2009-09-05 21:47:34 +00001347 entry->module=ConstantString("BMP");
1348 entry->adjoin=MagickFalse;
1349 entry->seekable_stream=MagickTrue;
1350 (void) RegisterMagickInfo(entry);
1351 entry=SetMagickInfo("BMP2");
1352 entry->encoder=(EncodeImageHandler *) WriteBMPImage;
1353 entry->magick=(IsImageFormatHandler *) IsBMP;
cristy2dd92ae2010-04-04 16:10:59 +00001354 entry->description=ConstantString("Microsoft Windows bitmap image (V2)");
cristy3ed852e2009-09-05 21:47:34 +00001355 entry->module=ConstantString("BMP");
1356 entry->adjoin=MagickFalse;
1357 entry->seekable_stream=MagickTrue;
1358 (void) RegisterMagickInfo(entry);
1359 entry=SetMagickInfo("BMP3");
1360 entry->encoder=(EncodeImageHandler *) WriteBMPImage;
1361 entry->magick=(IsImageFormatHandler *) IsBMP;
cristy2dd92ae2010-04-04 16:10:59 +00001362 entry->description=ConstantString("Microsoft Windows bitmap image (V3)");
cristy3ed852e2009-09-05 21:47:34 +00001363 entry->module=ConstantString("BMP");
1364 entry->adjoin=MagickFalse;
1365 entry->seekable_stream=MagickTrue;
1366 (void) RegisterMagickInfo(entry);
1367 return(MagickImageCoderSignature);
1368}
1369
1370/*
1371%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1372% %
1373% %
1374% %
1375% U n r e g i s t e r B M P I m a g e %
1376% %
1377% %
1378% %
1379%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1380%
1381% UnregisterBMPImage() removes format registrations made by the
1382% BMP module from the list of supported formats.
1383%
1384% The format of the UnregisterBMPImage method is:
1385%
1386% UnregisterBMPImage(void)
1387%
1388*/
1389ModuleExport void UnregisterBMPImage(void)
1390{
1391 (void) UnregisterMagickInfo("BMP");
1392 (void) UnregisterMagickInfo("BMP2");
1393 (void) UnregisterMagickInfo("BMP3");
1394}
1395
1396/*
1397%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1398% %
1399% %
1400% %
1401% W r i t e B M P I m a g e %
1402% %
1403% %
1404% %
1405%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1406%
1407% WriteBMPImage() writes an image in Microsoft Windows bitmap encoded
1408% image format, version 3 for Windows or (if the image has a matte channel)
1409% version 4.
1410%
1411% The format of the WriteBMPImage method is:
1412%
1413% MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image)
1414%
1415% A description of each parameter follows.
1416%
1417% o image_info: the image info.
1418%
1419% o image: The image.
1420%
1421*/
1422static MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image)
1423{
1424 BMPInfo
1425 bmp_info;
1426
1427 const StringInfo
1428 *profile;
1429
1430 long
1431 y;
1432
1433 MagickBooleanType
1434 have_color_info,
1435 status;
1436
1437 MagickOffsetType
1438 scene;
1439
1440 register const IndexPacket
1441 *indexes;
1442
1443 register const PixelPacket
1444 *p;
1445
1446 register long
1447 i,
1448 x;
1449
1450 register unsigned char
1451 *q;
1452
1453 unsigned char
1454 *bmp_data,
1455 *pixels;
1456
1457 unsigned long
1458 bytes_per_line,
1459 type;
1460
1461 /*
1462 Open output image file.
1463 */
1464 assert(image_info != (const ImageInfo *) NULL);
1465 assert(image_info->signature == MagickSignature);
1466 assert(image != (Image *) NULL);
1467 assert(image->signature == MagickSignature);
1468 if (image->debug != MagickFalse)
1469 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1470 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1471 if (status == MagickFalse)
1472 return(status);
1473 type=4;
1474 if (LocaleCompare(image_info->magick,"BMP2") == 0)
1475 type=2;
1476 else
1477 if (LocaleCompare(image_info->magick,"BMP3") == 0)
1478 type=3;
1479 scene=0;
1480 do
1481 {
1482 /*
1483 Initialize BMP raster file header.
1484 */
1485 if (image->colorspace != RGBColorspace)
1486 (void) TransformImageColorspace(image,RGBColorspace);
1487 (void) ResetMagickMemory(&bmp_info,0,sizeof(bmp_info));
1488 bmp_info.file_size=14+12;
1489 if (type > 2)
1490 bmp_info.file_size+=28;
1491 bmp_info.offset_bits=bmp_info.file_size;
1492 bmp_info.compression=BI_RGB;
1493 if ((image->storage_class == PseudoClass) && (image->colors > 256))
1494 (void) SetImageStorageClass(image,DirectClass);
1495 if (image->storage_class != DirectClass)
1496 {
1497 /*
1498 Colormapped BMP raster.
1499 */
1500 bmp_info.bits_per_pixel=8;
1501 if (image->colors <= 2)
1502 bmp_info.bits_per_pixel=1;
1503 else
1504 if (image->colors <= 16)
1505 bmp_info.bits_per_pixel=4;
1506 else
1507 if (image->colors <= 256)
1508 bmp_info.bits_per_pixel=8;
1509 if (image_info->compression == RLECompression)
1510 bmp_info.bits_per_pixel=8;
1511 bmp_info.number_colors=1U << bmp_info.bits_per_pixel;
1512 if (image->matte != MagickFalse)
1513 (void) SetImageStorageClass(image,DirectClass);
1514 else
1515 if ((unsigned long) bmp_info.number_colors < image->colors)
1516 (void) SetImageStorageClass(image,DirectClass);
1517 else
1518 {
1519 bmp_info.file_size+=3*(1UL << bmp_info.bits_per_pixel);
1520 bmp_info.offset_bits+=3*(1UL << bmp_info.bits_per_pixel);
1521 if (type > 2)
1522 {
1523 bmp_info.file_size+=(1UL << bmp_info.bits_per_pixel);
1524 bmp_info.offset_bits+=(1UL << bmp_info.bits_per_pixel);
1525 }
1526 }
1527 }
1528 if (image->storage_class == DirectClass)
1529 {
1530 /*
1531 Full color BMP raster.
1532 */
1533 bmp_info.number_colors=0;
1534 bmp_info.bits_per_pixel=(unsigned short)
1535 ((type > 3) && (image->matte != MagickFalse) ? 32 : 24);
1536 bmp_info.compression=(unsigned int) ((type > 3) &&
1537 (image->matte != MagickFalse) ? BI_BITFIELDS : BI_RGB);
1538 }
1539 bytes_per_line=4*((image->columns*bmp_info.bits_per_pixel+31)/32);
1540 bmp_info.ba_offset=0;
1541 profile=GetImageProfile(image,"icc");
1542 have_color_info=(image->rendering_intent != UndefinedIntent) ||
1543 (profile != (StringInfo *) NULL) || (image->gamma != 0.0) ? MagickTrue :
1544 MagickFalse;
1545 if (type == 2)
1546 bmp_info.size=12;
1547 else
1548 if ((type == 3) || ((image->matte == MagickFalse) &&
1549 (have_color_info == MagickFalse)))
1550 {
1551 type=3;
1552 bmp_info.size=40;
1553 }
1554 else
1555 {
1556 int
1557 extra_size;
1558
1559 bmp_info.size=108;
1560 extra_size=68;
1561 if ((image->rendering_intent != UndefinedIntent) ||
1562 (profile != (StringInfo *) NULL))
1563 {
1564 bmp_info.size=124;
1565 extra_size+=16;
1566 }
1567 bmp_info.file_size+=extra_size;
1568 bmp_info.offset_bits+=extra_size;
1569 }
1570 bmp_info.width=(long) image->columns;
1571 bmp_info.height=(long) image->rows;
1572 bmp_info.planes=1;
1573 bmp_info.image_size=(unsigned int) (bytes_per_line*image->rows);
1574 bmp_info.file_size+=bmp_info.image_size;
1575 bmp_info.x_pixels=75*39;
1576 bmp_info.y_pixels=75*39;
1577 switch (image->units)
1578 {
1579 case UndefinedResolution:
1580 case PixelsPerInchResolution:
1581 {
1582 bmp_info.x_pixels=(unsigned int) (100.0*image->x_resolution/2.54);
1583 bmp_info.y_pixels=(unsigned int) (100.0*image->y_resolution/2.54);
1584 break;
1585 }
1586 case PixelsPerCentimeterResolution:
1587 {
1588 bmp_info.x_pixels=(unsigned int) (100.0*image->x_resolution);
1589 bmp_info.y_pixels=(unsigned int) (100.0*image->y_resolution);
1590 break;
1591 }
1592 }
1593 bmp_info.colors_important=bmp_info.number_colors;
1594 /*
1595 Convert MIFF to BMP raster pixels.
1596 */
1597 pixels=(unsigned char *) AcquireQuantumMemory((size_t) bmp_info.image_size,
1598 sizeof(*pixels));
1599 if (pixels == (unsigned char *) NULL)
1600 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1601 (void) ResetMagickMemory(pixels,0,(size_t) bmp_info.image_size);
1602 switch (bmp_info.bits_per_pixel)
1603 {
1604 case 1:
1605 {
1606 unsigned long
1607 bit,
1608 byte;
1609
1610 /*
1611 Convert PseudoClass image to a BMP monochrome image.
1612 */
1613 for (y=0; y < (long) image->rows; y++)
1614 {
1615 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1616 if (p == (const PixelPacket *) NULL)
1617 break;
1618 indexes=GetVirtualIndexQueue(image);
1619 q=pixels+(image->rows-y-1)*bytes_per_line;
1620 bit=0;
1621 byte=0;
1622 for (x=0; x < (long) image->columns; x++)
1623 {
1624 byte<<=1;
1625 byte|=indexes[x] != 0 ? 0x01 : 0x00;
1626 bit++;
1627 if (bit == 8)
1628 {
1629 *q++=(unsigned char) byte;
1630 bit=0;
1631 byte=0;
1632 }
1633 }
1634 if (bit != 0)
1635 {
1636 *q++=(unsigned char) (byte << (8-bit));
1637 x++;
1638 }
1639 for (x=(long) (image->columns+7)/8; x < (long) bytes_per_line; x++)
1640 *q++=0x00;
1641 if (image->previous == (Image *) NULL)
1642 {
1643 status=SetImageProgress(image,SaveImageTag,y,image->rows);
1644 if (status == MagickFalse)
1645 break;
1646 }
1647 }
1648 break;
1649 }
1650 case 4:
1651 {
1652 unsigned long
1653 nibble,
1654 byte;
1655
1656 /*
1657 Convert PseudoClass image to a BMP monochrome image.
1658 */
1659 for (y=0; y < (long) image->rows; y++)
1660 {
1661 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1662 if (p == (const PixelPacket *) NULL)
1663 break;
1664 indexes=GetVirtualIndexQueue(image);
1665 q=pixels+(image->rows-y-1)*bytes_per_line;
1666 nibble=0;
1667 byte=0;
1668 for (x=0; x < (long) image->columns; x++)
1669 {
1670 byte<<=4;
1671 byte|=((unsigned long) indexes[x] & 0x0f);
1672 nibble++;
1673 if (nibble == 2)
1674 {
1675 *q++=(unsigned char) byte;
1676 nibble=0;
1677 byte=0;
1678 }
1679 }
1680 if (nibble != 0)
1681 {
1682 *q++=(unsigned char) (byte << 4);
1683 x++;
1684 }
1685 for (x=(long) (image->columns+1)/2; x < (long) bytes_per_line; x++)
1686 *q++=0x00;
1687 if (image->previous == (Image *) NULL)
1688 {
1689 status=SetImageProgress(image,SaveImageTag,y,image->rows);
1690 if (status == MagickFalse)
1691 break;
1692 }
1693 }
1694 break;
1695 }
1696 case 8:
1697 {
1698 /*
1699 Convert PseudoClass packet to BMP pixel.
1700 */
1701 for (y=0; y < (long) image->rows; y++)
1702 {
1703 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1704 if (p == (const PixelPacket *) NULL)
1705 break;
1706 indexes=GetVirtualIndexQueue(image);
1707 q=pixels+(image->rows-y-1)*bytes_per_line;
1708 for (x=0; x < (long) image->columns; x++)
1709 *q++=(unsigned char) indexes[x];
1710 for ( ; x < (long) bytes_per_line; x++)
1711 *q++=0x00;
1712 if (image->previous == (Image *) NULL)
1713 {
1714 status=SetImageProgress(image,SaveImageTag,y,image->rows);
1715 if (status == MagickFalse)
1716 break;
1717 }
1718 }
1719 break;
1720 }
1721 case 24:
1722 {
1723 /*
1724 Convert DirectClass packet to BMP BGR888.
1725 */
1726 for (y=0; y < (long) image->rows; y++)
1727 {
1728 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1729 if (p == (const PixelPacket *) NULL)
1730 break;
1731 q=pixels+(image->rows-y-1)*bytes_per_line;
1732 for (x=0; x < (long) image->columns; x++)
1733 {
cristyce70c172010-01-07 17:15:30 +00001734 *q++=ScaleQuantumToChar(GetBluePixelComponent(p));
1735 *q++=ScaleQuantumToChar(GetGreenPixelComponent(p));
1736 *q++=ScaleQuantumToChar(GetRedPixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +00001737 p++;
1738 }
1739 for (x=3L*(long) image->columns; x < (long) bytes_per_line; x++)
1740 *q++=0x00;
1741 if (image->previous == (Image *) NULL)
1742 {
1743 status=SetImageProgress(image,SaveImageTag,y,image->rows);
1744 if (status == MagickFalse)
1745 break;
1746 }
1747 }
1748 break;
1749 }
1750 case 32:
1751 {
1752 /*
1753 Convert DirectClass packet to ARGB8888 pixel.
1754 */
1755 for (y=0; y < (long) image->rows; y++)
1756 {
1757 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1758 if (p == (const PixelPacket *) NULL)
1759 break;
1760 q=pixels+(image->rows-y-1)*bytes_per_line;
1761 for (x=0; x < (long) image->columns; x++)
1762 {
cristyce70c172010-01-07 17:15:30 +00001763 *q++=ScaleQuantumToChar(GetBluePixelComponent(p));
1764 *q++=ScaleQuantumToChar(GetGreenPixelComponent(p));
1765 *q++=ScaleQuantumToChar(GetRedPixelComponent(p));
cristy228ab742010-02-24 13:49:34 +00001766 *q++=ScaleQuantumToChar(QuantumRange-GetOpacityPixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +00001767 p++;
1768 }
1769 if (image->previous == (Image *) NULL)
1770 {
1771 status=SetImageProgress(image,SaveImageTag,y,image->rows);
1772 if (status == MagickFalse)
1773 break;
1774 }
1775 }
1776 break;
1777 }
1778 }
1779 if ((type > 2) && (bmp_info.bits_per_pixel == 8))
1780 if (image_info->compression != NoCompression)
1781 {
1782 size_t
1783 length;
1784
1785 /*
1786 Convert run-length encoded raster pixels.
1787 */
1788 length=(size_t) (2*(bytes_per_line+2)*(image->rows+2)+2);
1789 bmp_data=(unsigned char *) NULL;
1790 if (~length >= bytes_per_line)
1791 bmp_data=(unsigned char *) AcquireQuantumMemory(length+
1792 bytes_per_line,sizeof(*bmp_data));
1793 if (bmp_data == (unsigned char *) NULL)
1794 {
1795 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1796 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1797 }
1798 bmp_info.file_size-=bmp_info.image_size;
1799 bmp_info.image_size=(unsigned int) EncodeImage(image,bytes_per_line,
1800 pixels,bmp_data);
1801 bmp_info.file_size+=bmp_info.image_size;
1802 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1803 pixels=bmp_data;
1804 bmp_info.compression=BI_RLE8;
1805 }
1806 /*
1807 Write BMP for Windows, all versions, 14-byte header.
1808 */
1809 if (image->debug != MagickFalse)
1810 {
1811 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1812 " Writing BMP version %ld datastream",type);
1813 if (image->storage_class == DirectClass)
1814 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1815 " Storage class=DirectClass");
1816 else
1817 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1818 " Storage class=PseudoClass");
1819 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1820 " Image depth=%lu",image->depth);
1821 if (image->matte != MagickFalse)
1822 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1823 " Matte=True");
1824 else
1825 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1826 " Matte=MagickFalse");
1827 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1828 " BMP bits_per_pixel=%d",bmp_info.bits_per_pixel);
1829 switch ((int) bmp_info.compression)
1830 {
1831 case BI_RGB:
1832 {
1833 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1834 " Compression=BI_RGB");
1835 break;
1836 }
1837 case BI_RLE8:
1838 {
1839 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1840 " Compression=BI_RLE8");
1841 break;
1842 }
1843 case BI_BITFIELDS:
1844 {
1845 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1846 " Compression=BI_BITFIELDS");
1847 break;
1848 }
1849 default:
1850 {
1851 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1852 " Compression=UNKNOWN (%u)",bmp_info.compression);
1853 break;
1854 }
1855 }
1856 if (bmp_info.number_colors == 0)
1857 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1858 " Number_colors=unspecified");
1859 else
1860 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1861 " Number_colors=%u",bmp_info.number_colors);
1862 }
1863 (void) WriteBlob(image,2,(unsigned char *) "BM");
1864 (void) WriteBlobLSBLong(image,bmp_info.file_size);
1865 (void) WriteBlobLSBLong(image,bmp_info.ba_offset); /* always 0 */
1866 (void) WriteBlobLSBLong(image,bmp_info.offset_bits);
1867 if (type == 2)
1868 {
1869 /*
1870 Write 12-byte version 2 bitmap header.
1871 */
1872 (void) WriteBlobLSBLong(image,bmp_info.size);
1873 (void) WriteBlobLSBShort(image,(unsigned short) bmp_info.width);
1874 (void) WriteBlobLSBShort(image,(unsigned short) bmp_info.height);
1875 (void) WriteBlobLSBShort(image,bmp_info.planes);
1876 (void) WriteBlobLSBShort(image,bmp_info.bits_per_pixel);
1877 }
1878 else
1879 {
1880 /*
1881 Write 40-byte version 3+ bitmap header.
1882 */
1883 (void) WriteBlobLSBLong(image,bmp_info.size);
1884 (void) WriteBlobLSBLong(image,(unsigned int) bmp_info.width);
1885 (void) WriteBlobLSBLong(image,(unsigned int) bmp_info.height);
1886 (void) WriteBlobLSBShort(image,bmp_info.planes);
1887 (void) WriteBlobLSBShort(image,bmp_info.bits_per_pixel);
1888 (void) WriteBlobLSBLong(image,bmp_info.compression);
1889 (void) WriteBlobLSBLong(image,bmp_info.image_size);
1890 (void) WriteBlobLSBLong(image,bmp_info.x_pixels);
1891 (void) WriteBlobLSBLong(image,bmp_info.y_pixels);
1892 (void) WriteBlobLSBLong(image,bmp_info.number_colors);
1893 (void) WriteBlobLSBLong(image,bmp_info.colors_important);
1894 }
1895 if ((type > 3) && ((image->matte != MagickFalse) ||
1896 (have_color_info != MagickFalse)))
1897 {
1898 /*
1899 Write the rest of the 108-byte BMP Version 4 header.
1900 */
1901 (void) WriteBlobLSBLong(image,0x00ff0000U); /* Red mask */
1902 (void) WriteBlobLSBLong(image,0x0000ff00U); /* Green mask */
1903 (void) WriteBlobLSBLong(image,0x000000ffU); /* Blue mask */
1904 (void) WriteBlobLSBLong(image,0xff000000U); /* Alpha mask */
1905 (void) WriteBlobLSBLong(image,0x00000001U); /* CSType==Calib. RGB */
1906 (void) WriteBlobLSBLong(image,(unsigned int)
1907 image->chromaticity.red_primary.x*0x3ffffff);
1908 (void) WriteBlobLSBLong(image,(unsigned int)
1909 image->chromaticity.red_primary.y*0x3ffffff);
1910 (void) WriteBlobLSBLong(image,(unsigned int)
1911 (1.000f-(image->chromaticity.red_primary.x+
1912 image->chromaticity.red_primary.y)*0x3ffffff));
1913 (void) WriteBlobLSBLong(image,(unsigned int)
1914 image->chromaticity.green_primary.x*0x3ffffff);
1915 (void) WriteBlobLSBLong(image,(unsigned int)
1916 image->chromaticity.green_primary.y*0x3ffffff);
1917 (void) WriteBlobLSBLong(image,(unsigned int)
1918 (1.000f-(image->chromaticity.green_primary.x+
1919 image->chromaticity.green_primary.y)*0x3ffffff));
1920 (void) WriteBlobLSBLong(image,(unsigned int)
1921 image->chromaticity.blue_primary.x*0x3ffffff);
1922 (void) WriteBlobLSBLong(image,(unsigned int)
1923 image->chromaticity.blue_primary.y*0x3ffffff);
1924 (void) WriteBlobLSBLong(image,(unsigned int)
1925 (1.000f-(image->chromaticity.blue_primary.x+
1926 image->chromaticity.blue_primary.y)*0x3ffffff));
1927 (void) WriteBlobLSBLong(image,(unsigned int)
1928 bmp_info.gamma_scale.x*0xffff);
1929 (void) WriteBlobLSBLong(image,(unsigned int)
1930 bmp_info.gamma_scale.y*0xffff);
1931 (void) WriteBlobLSBLong(image,(unsigned int)
1932 bmp_info.gamma_scale.z*0xffff);
1933 if ((image->rendering_intent != UndefinedIntent) ||
1934 (profile != (StringInfo *) NULL))
1935 {
1936 long
1937 intent;
1938
1939 switch ((int) image->rendering_intent)
1940 {
1941 case SaturationIntent:
1942 {
1943 intent=LCS_GM_BUSINESS;
1944 break;
1945 }
1946 case RelativeIntent:
1947 {
1948 intent=LCS_GM_GRAPHICS;
1949 break;
1950 }
1951 case PerceptualIntent:
1952 {
1953 intent=LCS_GM_IMAGES;
1954 break;
1955 }
1956 case AbsoluteIntent:
1957 {
1958 intent=LCS_GM_ABS_COLORIMETRIC;
1959 break;
1960 }
1961 default:
1962 {
1963 intent=0;
1964 break;
1965 }
1966 }
1967 (void) WriteBlobLSBLong(image,(unsigned int) intent);
1968 (void) WriteBlobLSBLong(image,0x00); /* dummy profile data */
1969 (void) WriteBlobLSBLong(image,0x00); /* dummy profile length */
1970 (void) WriteBlobLSBLong(image,0x00); /* reserved */
1971 }
1972 }
1973 if (image->storage_class == PseudoClass)
1974 {
1975 unsigned char
1976 *bmp_colormap;
1977
1978 /*
1979 Dump colormap to file.
1980 */
1981 if (image->debug != MagickFalse)
1982 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1983 " Colormap: %ld entries",image->colors);
1984 bmp_colormap=(unsigned char *) AcquireQuantumMemory((size_t) (1UL <<
1985 bmp_info.bits_per_pixel),4*sizeof(*bmp_colormap));
1986 if (bmp_colormap == (unsigned char *) NULL)
1987 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1988 q=bmp_colormap;
1989 for (i=0; i < (long) MagickMin((long) image->colors,(long) bmp_info.number_colors); i++)
1990 {
1991 *q++=ScaleQuantumToChar(image->colormap[i].blue);
1992 *q++=ScaleQuantumToChar(image->colormap[i].green);
1993 *q++=ScaleQuantumToChar(image->colormap[i].red);
1994 if (type > 2)
1995 *q++=(unsigned char) 0x0;
1996 }
1997 for ( ; i < (long) (1UL << bmp_info.bits_per_pixel); i++)
1998 {
1999 *q++=(unsigned char) 0x00;
2000 *q++=(unsigned char) 0x00;
2001 *q++=(unsigned char) 0x00;
2002 if (type > 2)
2003 *q++=(unsigned char) 0x00;
2004 }
2005 if (type <= 2)
2006 (void) WriteBlob(image,(size_t) (3*(1L << bmp_info.bits_per_pixel)),
2007 bmp_colormap);
2008 else
2009 (void) WriteBlob(image,(size_t) (4*(1L << bmp_info.bits_per_pixel)),
2010 bmp_colormap);
2011 bmp_colormap=(unsigned char *) RelinquishMagickMemory(bmp_colormap);
2012 }
2013 if (image->debug != MagickFalse)
2014 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2015 " Pixels: %u bytes",bmp_info.image_size);
2016 (void) WriteBlob(image,(size_t) bmp_info.image_size,pixels);
2017 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
2018 if (GetNextImageInList(image) == (Image *) NULL)
2019 break;
2020 image=SyncNextImageInList(image);
2021 status=SetImageProgress(image,SaveImagesTag,scene++,
2022 GetImageListLength(image));
2023 if (status == MagickFalse)
2024 break;
2025 } while (image_info->adjoin != MagickFalse);
2026 (void) CloseBlob(image);
2027 return(MagickTrue);
2028}