2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Microsoft Windows Bitmap Image Format %
17 % Glenn Randers-Pehrson %
21 % Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization %
22 % dedicated to making software imaging solutions freely available. %
24 % You may not use this file except in compliance with the License. You may %
25 % obtain a copy of the License at %
27 % http://www.imagemagick.org/script/license.php %
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. %
35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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 "magick/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"
72 Macro definitions (from Windows wingdi.h).
78 #if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__MINGW32__) || defined(__MINGW64__)
86 #define BI_BITFIELDS 3
88 #undef LCS_CALIBRATED_RBG
89 #define LCS_CALIBRATED_RBG 0
92 #undef LCS_WINDOWS_COLOR_SPACE
93 #define LCS_WINDOWS_COLOR_SPACE 2
95 #define PROFILE_LINKED 3
96 #undef PROFILE_EMBEDDED
97 #define PROFILE_EMBEDDED 4
99 #undef LCS_GM_BUSINESS
100 #define LCS_GM_BUSINESS 1 /* Saturation */
101 #undef LCS_GM_GRAPHICS
102 #define LCS_GM_GRAPHICS 2 /* Relative */
104 #define LCS_GM_IMAGES 4 /* Perceptual */
105 #undef LCS_GM_ABS_COLORIMETRIC
106 #define LCS_GM_ABS_COLORIMETRIC 8 /* Absolute */
110 Typedef declarations.
112 typedef struct _BMPInfo
151 Forward declarations.
153 static MagickBooleanType
154 WriteBMPImage(const ImageInfo *,Image *,ExceptionInfo *);
157 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
161 % D e c o d e I m a g e %
165 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
167 % DecodeImage unpacks the packed image pixels into runlength-encoded
170 % The format of the DecodeImage method is:
172 % MagickBooleanType DecodeImage(Image *image,
173 % const size_t compression,unsigned char *pixels)
175 % A description of each parameter follows:
177 % o image: the address of a structure of type Image.
179 % o compression: Zero means uncompressed. A value of 1 means the
180 % compressed pixels are runlength encoded for a 256-color bitmap.
181 % A value of 2 means a 16-color bitmap. A value of 3 means bitfields
184 % o pixels: The address of a byte (8 bits) array of pixel data created by
185 % the decoding process.
189 static inline ssize_t MagickAbsoluteValue(const ssize_t x)
196 static inline size_t MagickMax(const size_t x,const size_t y)
203 static inline ssize_t MagickMin(const ssize_t x,const ssize_t y)
210 static MagickBooleanType DecodeImage(Image *image,const size_t compression,
211 unsigned char *pixels)
220 register unsigned char
230 assert(image != (Image *) NULL);
231 assert(image->signature == MagickSignature);
232 if (image->debug != MagickFalse)
233 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
234 assert(pixels != (unsigned char *) NULL);
235 (void) ResetMagickMemory(pixels,0,(size_t) image->columns*image->rows*
240 q=pixels+(size_t) image->columns*image->rows;
241 for (y=0; y < (ssize_t) image->rows; )
243 if ((p < pixels) || (p >= q))
245 count=ReadBlobByte(image);
253 count=(int) MagickMin((ssize_t) count,(ssize_t) (q-p));
254 byte=(unsigned char) ReadBlobByte(image);
255 if (compression == BI_RLE8)
257 for (i=0; i < (ssize_t) count; i++)
258 *p++=(unsigned char) byte;
262 for (i=0; i < (ssize_t) count; i++)
264 ((i & 0x01) != 0 ? (byte & 0x0f) : ((byte >> 4) & 0x0f));
273 count=ReadBlobByte(image);
285 p=pixels+y*image->columns;
293 x+=ReadBlobByte(image);
294 y+=ReadBlobByte(image);
295 p=pixels+y*image->columns+x;
303 count=(int) MagickMin((ssize_t) count,(ssize_t) (q-p));
304 if (compression == BI_RLE8)
305 for (i=0; i < (ssize_t) count; i++)
306 *p++=(unsigned char) ReadBlobByte(image);
308 for (i=0; i < (ssize_t) count; i++)
311 byte=(unsigned char) ReadBlobByte(image);
313 ((i & 0x01) != 0 ? (byte & 0x0f) : ((byte >> 4) & 0x0f));
319 if (compression == BI_RLE8)
321 if ((count & 0x01) != 0)
322 (void) ReadBlobByte(image);
325 if (((count & 0x03) == 1) || ((count & 0x03) == 2))
326 (void) ReadBlobByte(image);
331 if (SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,image->rows) == MagickFalse)
334 (void) ReadBlobByte(image); /* end of line */
335 (void) ReadBlobByte(image);
340 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
344 % E n c o d e I m a g e %
348 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
350 % EncodeImage compresses pixels using a runlength encoded format.
352 % The format of the EncodeImage method is:
354 % static MagickBooleanType EncodeImage(Image *image,
355 % const size_t bytes_per_line,const unsigned char *pixels,
356 % unsigned char *compressed_pixels)
358 % A description of each parameter follows:
360 % o image: The image.
362 % o bytes_per_line: the number of bytes in a scanline of compressed pixels
364 % o pixels: The address of a byte (8 bits) array of pixel data created by
365 % the compression process.
367 % o compressed_pixels: The address of a byte (8 bits) array of compressed
371 static size_t EncodeImage(Image *image,const size_t bytes_per_line,
372 const unsigned char *pixels,unsigned char *compressed_pixels)
377 register const unsigned char
384 register unsigned char
391 Runlength encode pixels.
393 assert(image != (Image *) NULL);
394 assert(image->signature == MagickSignature);
395 if (image->debug != MagickFalse)
396 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
397 assert(pixels != (const unsigned char *) NULL);
398 assert(compressed_pixels != (unsigned char *) NULL);
402 for (y=0; y < (ssize_t) image->rows; y++)
404 for (x=0; x < (ssize_t) bytes_per_line; x+=i)
409 for (i=1; ((x+i) < (ssize_t) bytes_per_line); i++)
410 if ((i == 255) || (*(p+i) != *p))
412 *q++=(unsigned char) i;
419 *q++=(unsigned char) 0x00;
420 *q++=(unsigned char) 0x00;
421 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
423 if (status == MagickFalse)
429 *q++=(unsigned char) 0x00;
430 *q++=(unsigned char) 0x01;
431 return((size_t) (q-compressed_pixels));
435 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
443 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
445 % IsBMP() returns MagickTrue if the image format type, identified by the
446 % magick string, is BMP.
448 % The format of the IsBMP method is:
450 % MagickBooleanType IsBMP(const unsigned char *magick,const size_t length)
452 % A description of each parameter follows:
454 % o magick: compare image format pattern against these bytes.
456 % o length: Specifies the length of the magick string.
459 static MagickBooleanType IsBMP(const unsigned char *magick,const size_t length)
463 if ((LocaleNCompare((char *) magick,"BA",2) == 0) ||
464 (LocaleNCompare((char *) magick,"BM",2) == 0) ||
465 (LocaleNCompare((char *) magick,"IC",2) == 0) ||
466 (LocaleNCompare((char *) magick,"PI",2) == 0) ||
467 (LocaleNCompare((char *) magick,"CI",2) == 0) ||
468 (LocaleNCompare((char *) magick,"CP",2) == 0))
474 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
478 % R e a d B M P I m a g e %
482 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
484 % ReadBMPImage() reads a Microsoft Windows bitmap image file, Version
485 % 2, 3 (for Windows or NT), or 4, and returns it. It allocates the memory
486 % necessary for the new Image structure and returns a pointer to the new
489 % The format of the ReadBMPImage method is:
491 % image=ReadBMPImage(image_info)
493 % A description of each parameter follows:
495 % o image_info: the image info.
497 % o exception: return any errors or warnings in this structure.
501 static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
529 register unsigned char
552 assert(image_info != (const ImageInfo *) NULL);
553 assert(image_info->signature == MagickSignature);
554 if (image_info->debug != MagickFalse)
555 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
556 image_info->filename);
557 assert(exception != (ExceptionInfo *) NULL);
558 assert(exception->signature == MagickSignature);
559 image=AcquireImage(image_info,exception);
560 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
561 if (status == MagickFalse)
563 image=DestroyImageList(image);
564 return((Image *) NULL);
567 Determine if this a BMP file.
569 (void) ResetMagickMemory(&bmp_info,0,sizeof(bmp_info));
570 bmp_info.ba_offset=0;
572 count=ReadBlob(image,2,magick);
586 Verify BMP identifier.
588 if (bmp_info.ba_offset == 0)
589 start_position=TellBlob(image)-2;
590 bmp_info.ba_offset=0;
591 while (LocaleNCompare((char *) magick,"BA",2) == 0)
593 bmp_info.file_size=ReadBlobLSBLong(image);
594 bmp_info.ba_offset=ReadBlobLSBLong(image);
595 bmp_info.offset_bits=ReadBlobLSBLong(image);
596 count=ReadBlob(image,2,magick);
600 if (image->debug != MagickFalse)
601 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Magick: %c%c",
602 magick[0],magick[1]);
603 if ((count == 0) || ((LocaleNCompare((char *) magick,"BM",2) != 0) &&
604 (LocaleNCompare((char *) magick,"CI",2) != 0)))
605 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
606 bmp_info.file_size=ReadBlobLSBLong(image);
607 (void) ReadBlobLSBLong(image);
608 bmp_info.offset_bits=ReadBlobLSBLong(image);
609 bmp_info.size=ReadBlobLSBLong(image);
610 if (image->debug != MagickFalse)
611 (void) LogMagickEvent(CoderEvent,GetMagickModule()," BMP size: %u",
613 if (bmp_info.size == 12)
618 bmp_info.width=(ssize_t) ((short) ReadBlobLSBShort(image));
619 bmp_info.height=(ssize_t) ((short) ReadBlobLSBShort(image));
620 bmp_info.planes=ReadBlobLSBShort(image);
621 bmp_info.bits_per_pixel=ReadBlobLSBShort(image);
624 bmp_info.number_colors=0;
625 bmp_info.compression=BI_RGB;
626 bmp_info.image_size=0;
627 bmp_info.alpha_mask=0;
628 if (image->debug != MagickFalse)
630 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
631 " Format: OS/2 Bitmap");
632 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
633 " Geometry: %.20gx%.20g",(double) bmp_info.width,(double)
640 Microsoft Windows BMP image file.
642 if (bmp_info.size < 40)
643 ThrowReaderException(CorruptImageError,"NonOS2HeaderSizeError");
644 bmp_info.width=(ssize_t) ((int) ReadBlobLSBLong(image));
645 bmp_info.height=(ssize_t) ((int) ReadBlobLSBLong(image));
646 bmp_info.planes=ReadBlobLSBShort(image);
647 bmp_info.bits_per_pixel=ReadBlobLSBShort(image);
648 bmp_info.compression=ReadBlobLSBLong(image);
649 bmp_info.image_size=ReadBlobLSBLong(image);
650 bmp_info.x_pixels=ReadBlobLSBLong(image);
651 bmp_info.y_pixels=ReadBlobLSBLong(image);
652 bmp_info.number_colors=ReadBlobLSBLong(image);
653 bmp_info.colors_important=ReadBlobLSBLong(image);
656 if (image->debug != MagickFalse)
658 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
659 " Format: MS Windows bitmap");
660 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
661 " Geometry: %.20gx%.20g",(double) bmp_info.width,(double)
663 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
664 " Bits per pixel: %.20g",(double) bmp_info.bits_per_pixel);
665 switch ((int) bmp_info.compression)
669 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
670 " Compression: BI_RGB");
675 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
676 " Compression: BI_RLE4");
681 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
682 " Compression: BI_RLE8");
687 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
688 " Compression: BI_BITFIELDS");
693 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
694 " Compression: BI_PNG");
699 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
700 " Compression: BI_JPEG");
705 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
706 " Compression: UNKNOWN (%u)",bmp_info.compression);
709 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
710 " Number of colors: %u",bmp_info.number_colors);
712 bmp_info.red_mask=ReadBlobLSBLong(image);
713 bmp_info.green_mask=ReadBlobLSBLong(image);
714 bmp_info.blue_mask=ReadBlobLSBLong(image);
715 if (bmp_info.size > 40)
722 Read color management information.
724 bmp_info.alpha_mask=ReadBlobLSBLong(image);
725 bmp_info.colorspace=(int) ReadBlobLSBLong(image);
727 Decode 2^30 fixed point formatted CIE primaries.
729 # define BMP_DENOM ((double) 0x40000000)
730 bmp_info.red_primary.x=(double) ReadBlobLSBLong(image)/BMP_DENOM;
731 bmp_info.red_primary.y=(double) ReadBlobLSBLong(image)/BMP_DENOM;
732 bmp_info.red_primary.z=(double) ReadBlobLSBLong(image)/BMP_DENOM;
733 bmp_info.green_primary.x=(double) ReadBlobLSBLong(image)/BMP_DENOM;
734 bmp_info.green_primary.y=(double) ReadBlobLSBLong(image)/BMP_DENOM;
735 bmp_info.green_primary.z=(double) ReadBlobLSBLong(image)/BMP_DENOM;
736 bmp_info.blue_primary.x=(double) ReadBlobLSBLong(image)/BMP_DENOM;
737 bmp_info.blue_primary.y=(double) ReadBlobLSBLong(image)/BMP_DENOM;
738 bmp_info.blue_primary.z=(double) ReadBlobLSBLong(image)/BMP_DENOM;
740 sum=bmp_info.red_primary.x+bmp_info.red_primary.y+
741 bmp_info.red_primary.z;
742 bmp_info.red_primary.x/=sum;
743 bmp_info.red_primary.y/=sum;
744 image->chromaticity.red_primary.x=bmp_info.red_primary.x;
745 image->chromaticity.red_primary.y=bmp_info.red_primary.y;
747 sum=bmp_info.green_primary.x+bmp_info.green_primary.y+
748 bmp_info.green_primary.z;
749 bmp_info.green_primary.x/=sum;
750 bmp_info.green_primary.y/=sum;
751 image->chromaticity.green_primary.x=bmp_info.green_primary.x;
752 image->chromaticity.green_primary.y=bmp_info.green_primary.y;
754 sum=bmp_info.blue_primary.x+bmp_info.blue_primary.y+
755 bmp_info.blue_primary.z;
756 bmp_info.blue_primary.x/=sum;
757 bmp_info.blue_primary.y/=sum;
758 image->chromaticity.blue_primary.x=bmp_info.blue_primary.x;
759 image->chromaticity.blue_primary.y=bmp_info.blue_primary.y;
762 Decode 16^16 fixed point formatted gamma_scales.
764 bmp_info.gamma_scale.x=(double) ReadBlobLSBLong(image)/0x10000;
765 bmp_info.gamma_scale.y=(double) ReadBlobLSBLong(image)/0x10000;
766 bmp_info.gamma_scale.z=(double) ReadBlobLSBLong(image)/0x10000;
768 Compute a single gamma from the BMP 3-channel gamma.
770 image->gamma=(bmp_info.gamma_scale.x+bmp_info.gamma_scale.y+
771 bmp_info.gamma_scale.z)/3.0;
774 if (bmp_info.size > 108)
780 Read BMP Version 5 color management information.
782 intent=ReadBlobLSBLong(image);
783 switch ((int) intent)
785 case LCS_GM_BUSINESS:
787 image->rendering_intent=SaturationIntent;
790 case LCS_GM_GRAPHICS:
792 image->rendering_intent=RelativeIntent;
797 image->rendering_intent=PerceptualIntent;
800 case LCS_GM_ABS_COLORIMETRIC:
802 image->rendering_intent=AbsoluteIntent;
806 profile_data=ReadBlobLSBLong(image);
807 profile_size=ReadBlobLSBLong(image);
810 (void) ReadBlobLSBLong(image); /* Reserved byte */
813 if ((MagickSizeType) bmp_info.file_size > GetBlobSize(image))
814 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
815 "LengthAndFilesizeDoNotMatch","`%s'",image->filename);
817 if ((MagickSizeType) bmp_info.file_size < GetBlobSize(image))
818 (void) ThrowMagickException(exception,GetMagickModule(),
819 CorruptImageWarning,"LengthAndFilesizeDoNotMatch","`%s'",
821 if (bmp_info.width <= 0)
822 ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize");
823 if (bmp_info.height == 0)
824 ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize");
825 if (bmp_info.planes != 1)
826 ThrowReaderException(CorruptImageError,"StaticPlanesValueNotEqualToOne");
827 if ((bmp_info.bits_per_pixel != 1) && (bmp_info.bits_per_pixel != 4) &&
828 (bmp_info.bits_per_pixel != 8) && (bmp_info.bits_per_pixel != 16) &&
829 (bmp_info.bits_per_pixel != 24) && (bmp_info.bits_per_pixel != 32))
830 ThrowReaderException(CorruptImageError,"UnrecognizedBitsPerPixel");
831 if (bmp_info.bits_per_pixel < 16 &&
832 bmp_info.number_colors > (1U << bmp_info.bits_per_pixel))
834 ThrowReaderException(CorruptImageError,
835 "UnrecognizedNumberOfColors");
837 if ((bmp_info.compression == 1) && (bmp_info.bits_per_pixel != 8))
838 ThrowReaderException(CorruptImageError,"UnrecognizedBitsPerPixel");
839 if ((bmp_info.compression == 2) && (bmp_info.bits_per_pixel != 4))
840 ThrowReaderException(CorruptImageError,"UnrecognizedBitsPerPixel");
841 if ((bmp_info.compression == 3) && (bmp_info.bits_per_pixel < 16))
842 ThrowReaderException(CorruptImageError,"UnrecognizedBitsPerPixel");
843 switch (bmp_info.compression)
851 ThrowReaderException(CoderError,"JPEGCompressNotSupported");
853 ThrowReaderException(CoderError,"PNGCompressNotSupported");
855 ThrowReaderException(CorruptImageError,"UnrecognizedImageCompression");
857 image->columns=(size_t) MagickAbsoluteValue(bmp_info.width);
858 image->rows=(size_t) MagickAbsoluteValue(bmp_info.height);
859 image->depth=bmp_info.bits_per_pixel <= 8 ? bmp_info.bits_per_pixel : 8;
860 image->alpha_trait=(bmp_info.alpha_mask != 0) &&
861 (bmp_info.compression == BI_BITFIELDS) ? BlendPixelTrait :
863 if (bmp_info.bits_per_pixel < 16)
868 image->storage_class=PseudoClass;
869 image->colors=bmp_info.number_colors;
871 if (image->colors == 0)
872 image->colors=one << bmp_info.bits_per_pixel;
874 if (image->storage_class == PseudoClass)
883 Read BMP raster colormap.
885 if (image->debug != MagickFalse)
886 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
887 " Reading colormap of %.20g colors",(double) image->colors);
888 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
889 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
890 bmp_colormap=(unsigned char *) AcquireQuantumMemory((size_t)
891 image->colors,4*sizeof(*bmp_colormap));
892 if (bmp_colormap == (unsigned char *) NULL)
893 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
894 if ((bmp_info.size == 12) || (bmp_info.size == 64))
898 offset=SeekBlob(image,start_position+14+bmp_info.size,SEEK_SET);
900 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
901 count=ReadBlob(image,packet_size*image->colors,bmp_colormap);
902 if (count != (ssize_t) (packet_size*image->colors))
903 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
905 for (i=0; i < (ssize_t) image->colors; i++)
907 image->colormap[i].blue=(MagickRealType) ScaleCharToQuantum(*p++);
908 image->colormap[i].green=(MagickRealType) ScaleCharToQuantum(*p++);
909 image->colormap[i].red=(MagickRealType) ScaleCharToQuantum(*p++);
910 if (packet_size == 4)
913 bmp_colormap=(unsigned char *) RelinquishMagickMemory(bmp_colormap);
915 image->resolution.x=(double) bmp_info.x_pixels/100.0;
916 image->resolution.y=(double) bmp_info.y_pixels/100.0;
917 image->units=PixelsPerCentimeterResolution;
918 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
919 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
924 offset=SeekBlob(image,start_position+bmp_info.offset_bits,SEEK_SET);
926 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
927 if (bmp_info.compression == BI_RLE4)
928 bmp_info.bits_per_pixel<<=1;
929 bytes_per_line=4*((image->columns*bmp_info.bits_per_pixel+31)/32);
930 length=(size_t) bytes_per_line*image->rows;
931 pixel_info=AcquireVirtualMemory((size_t) image->rows,
932 MagickMax(bytes_per_line,image->columns+256UL)*sizeof(*pixels));
933 if (pixel_info == (MemoryInfo *) NULL)
934 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
935 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
936 if ((bmp_info.compression == BI_RGB) ||
937 (bmp_info.compression == BI_BITFIELDS))
939 if (image->debug != MagickFalse)
940 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
941 " Reading pixels (%.20g bytes)",(double) length);
942 count=ReadBlob(image,length,pixels);
943 if (count != (ssize_t) length)
945 pixel_info=RelinquishVirtualMemory(pixel_info);
946 ThrowReaderException(CorruptImageError,
947 "InsufficientImageDataInFile");
953 Convert run-length encoded raster pixels.
955 status=DecodeImage(image,bmp_info.compression,pixels);
956 if (status == MagickFalse)
958 pixel_info=RelinquishVirtualMemory(pixel_info);
959 ThrowReaderException(CorruptImageError,
960 "UnableToRunlengthDecodeImage");
964 Convert BMP raster image to pixel packets.
966 if (bmp_info.compression == BI_RGB)
968 bmp_info.alpha_mask=image->alpha_trait == BlendPixelTrait ?
970 bmp_info.red_mask=0x00ff0000U;
971 bmp_info.green_mask=0x0000ff00U;
972 bmp_info.blue_mask=0x000000ffU;
973 if (bmp_info.bits_per_pixel == 16)
978 bmp_info.red_mask=0x00007c00U;
979 bmp_info.green_mask=0x000003e0U;
980 bmp_info.blue_mask=0x0000001fU;
983 if ((bmp_info.bits_per_pixel == 16) || (bmp_info.bits_per_pixel == 32))
989 Get shift and quantum bits info from bitfield masks.
991 (void) ResetMagickMemory(&shift,0,sizeof(shift));
992 (void) ResetMagickMemory(&quantum_bits,0,sizeof(quantum_bits));
993 if (bmp_info.red_mask != 0)
994 while (((bmp_info.red_mask << shift.red) & 0x80000000UL) == 0)
996 if (bmp_info.green_mask != 0)
997 while (((bmp_info.green_mask << shift.green) & 0x80000000UL) == 0)
999 if (bmp_info.blue_mask != 0)
1000 while (((bmp_info.blue_mask << shift.blue) & 0x80000000UL) == 0)
1002 if (bmp_info.alpha_mask != 0)
1003 while (((bmp_info.alpha_mask << shift.alpha) & 0x80000000UL) == 0)
1006 while (((bmp_info.red_mask << sample) & 0x80000000UL) != 0)
1008 quantum_bits.red=(MagickRealType) (sample-shift.red);
1010 while (((bmp_info.green_mask << sample) & 0x80000000UL) != 0)
1012 quantum_bits.green=(MagickRealType) (sample-shift.green);
1014 while (((bmp_info.blue_mask << sample) & 0x80000000UL) != 0)
1016 quantum_bits.blue=(MagickRealType) (sample-shift.blue);
1018 while (((bmp_info.alpha_mask << sample) & 0x80000000UL) != 0)
1020 quantum_bits.alpha=(MagickRealType) (sample-shift.alpha);
1022 switch (bmp_info.bits_per_pixel)
1027 Convert bitmap scanline.
1029 for (y=(ssize_t) image->rows-1; y >= 0; y--)
1031 p=pixels+(image->rows-y-1)*bytes_per_line;
1032 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1033 if (q == (Quantum *) NULL)
1035 for (x=0; x < ((ssize_t) image->columns-7); x+=8)
1037 for (bit=0; bit < 8; bit++)
1039 index=(Quantum) (((*p) & (0x80 >> bit)) != 0 ? 0x01 : 0x00);
1040 SetPixelIndex(image,index,q);
1041 q+=GetPixelChannels(image);
1045 if ((image->columns % 8) != 0)
1047 for (bit=0; bit < (image->columns % 8); bit++)
1049 index=(Quantum) (((*p) & (0x80 >> bit)) != 0 ? 0x01 : 0x00);
1050 SetPixelIndex(image,index,q);
1051 q+=GetPixelChannels(image);
1055 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1057 if (image->previous == (Image *) NULL)
1059 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1061 if (status == MagickFalse)
1065 (void) SyncImage(image,exception);
1071 Convert PseudoColor scanline.
1073 for (y=(ssize_t) image->rows-1; y >= 0; y--)
1075 p=pixels+(image->rows-y-1)*bytes_per_line;
1076 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1077 if (q == (Quantum *) NULL)
1079 for (x=0; x < ((ssize_t) image->columns-1); x+=2)
1081 index=ConstrainColormapIndex(image,(*p >> 4) & 0x0f,exception);
1082 SetPixelIndex(image,index,q);
1083 q+=GetPixelChannels(image);
1084 index=ConstrainColormapIndex(image,*p & 0x0f,exception);
1085 SetPixelIndex(image,index,q);
1086 q+=GetPixelChannels(image);
1089 if ((image->columns % 2) != 0)
1091 index=ConstrainColormapIndex(image,(*p >> 4) & 0xf,exception);
1092 SetPixelIndex(image,index,q);
1093 q+=GetPixelChannels(image);
1096 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1098 if (image->previous == (Image *) NULL)
1100 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1102 if (status == MagickFalse)
1106 (void) SyncImage(image,exception);
1112 Convert PseudoColor scanline.
1114 if ((bmp_info.compression == BI_RLE8) ||
1115 (bmp_info.compression == BI_RLE4))
1116 bytes_per_line=image->columns;
1117 for (y=(ssize_t) image->rows-1; y >= 0; y--)
1119 p=pixels+(image->rows-y-1)*bytes_per_line;
1120 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1121 if (q == (Quantum *) NULL)
1123 for (x=(ssize_t) image->columns; x != 0; --x)
1125 index=ConstrainColormapIndex(image,*p++,exception);
1126 SetPixelIndex(image,index,q);
1127 q+=GetPixelChannels(image);
1129 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1131 offset=(MagickOffsetType) (image->rows-y-1);
1132 if (image->previous == (Image *) NULL)
1134 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1136 if (status == MagickFalse)
1140 (void) SyncImage(image,exception);
1149 Convert bitfield encoded 16-bit PseudoColor scanline.
1151 if (bmp_info.compression != BI_RGB &&
1152 bmp_info.compression != BI_BITFIELDS)
1154 pixel_info=RelinquishVirtualMemory(pixel_info);
1155 ThrowReaderException(CorruptImageError,
1156 "UnrecognizedImageCompression");
1158 bytes_per_line=2*(image->columns+image->columns % 2);
1159 image->storage_class=DirectClass;
1160 for (y=(ssize_t) image->rows-1; y >= 0; y--)
1162 p=pixels+(image->rows-y-1)*bytes_per_line;
1163 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1164 if (q == (Quantum *) NULL)
1166 for (x=0; x < (ssize_t) image->columns; x++)
1168 pixel=(size_t) (*p++);
1170 red=((pixel & bmp_info.red_mask) << shift.red) >> 16;
1171 if (quantum_bits.red == 5)
1172 red|=((red & 0xe000) >> 5);
1173 if (quantum_bits.red <= 8)
1174 red|=((red & 0xff00) >> 8);
1175 green=((pixel & bmp_info.green_mask) << shift.green) >> 16;
1176 if (quantum_bits.green == 5)
1177 green|=((green & 0xe000) >> 5);
1178 if (quantum_bits.green == 6)
1179 green|=((green & 0xc000) >> 6);
1180 if (quantum_bits.green <= 8)
1181 green|=((green & 0xff00) >> 8);
1182 blue=((pixel & bmp_info.blue_mask) << shift.blue) >> 16;
1183 if (quantum_bits.blue == 5)
1184 blue|=((blue & 0xe000) >> 5);
1185 if (quantum_bits.blue <= 8)
1186 blue|=((blue & 0xff00) >> 8);
1187 opacity=((pixel & bmp_info.alpha_mask) << shift.alpha) >> 16;
1188 if (quantum_bits.alpha <= 8)
1189 opacity|=((opacity & 0xff00) >> 8);
1190 SetPixelRed(image,ScaleShortToQuantum((unsigned short) red),q);
1191 SetPixelGreen(image,ScaleShortToQuantum((unsigned short) green),q);
1192 SetPixelBlue(image,ScaleShortToQuantum((unsigned short) blue),q);
1193 SetPixelAlpha(image,OpaqueAlpha,q);
1194 if (image->alpha_trait == BlendPixelTrait)
1195 SetPixelAlpha(image,
1196 ScaleShortToQuantum((unsigned short) opacity),q);
1197 q+=GetPixelChannels(image);
1199 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1201 offset=(MagickOffsetType) (image->rows-y-1);
1202 if (image->previous == (Image *) NULL)
1204 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1206 if (status == MagickFalse)
1215 Convert DirectColor scanline.
1217 bytes_per_line=4*((image->columns*24+31)/32);
1218 for (y=(ssize_t) image->rows-1; y >= 0; y--)
1220 p=pixels+(image->rows-y-1)*bytes_per_line;
1221 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1222 if (q == (Quantum *) NULL)
1224 for (x=0; x < (ssize_t) image->columns; x++)
1226 SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
1227 SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
1228 SetPixelRed(image,ScaleCharToQuantum(*p++),q);
1229 SetPixelAlpha(image,OpaqueAlpha,q);
1230 q+=GetPixelChannels(image);
1232 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1234 offset=(MagickOffsetType) (image->rows-y-1);
1235 if (image->previous == (Image *) NULL)
1237 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1239 if (status == MagickFalse)
1248 Convert bitfield encoded DirectColor scanline.
1250 if ((bmp_info.compression != BI_RGB) &&
1251 (bmp_info.compression != BI_BITFIELDS))
1253 pixel_info=RelinquishVirtualMemory(pixel_info);
1254 ThrowReaderException(CorruptImageError,
1255 "UnrecognizedImageCompression");
1257 bytes_per_line=4*(image->columns);
1258 for (y=(ssize_t) image->rows-1; y >= 0; y--)
1263 p=pixels+(image->rows-y-1)*bytes_per_line;
1264 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1265 if (q == (Quantum *) NULL)
1267 for (x=0; x < (ssize_t) image->columns; x++)
1269 pixel=(size_t) (*p++);
1271 pixel|=(*p++ << 16);
1272 pixel|=(*p++ << 24);
1273 red=((pixel & bmp_info.red_mask) << shift.red) >> 16;
1274 if (quantum_bits.red == 8)
1276 green=((pixel & bmp_info.green_mask) << shift.green) >> 16;
1277 if (quantum_bits.green == 8)
1278 green|=(green >> 8);
1279 blue=((pixel & bmp_info.blue_mask) << shift.blue) >> 16;
1280 if (quantum_bits.blue == 8)
1282 opacity=((pixel & bmp_info.alpha_mask) << shift.alpha) >> 16;
1283 if (quantum_bits.alpha == 8)
1284 opacity|=(opacity >> 8);
1285 SetPixelRed(image,ScaleShortToQuantum((unsigned short) red),q);
1286 SetPixelGreen(image,ScaleShortToQuantum((unsigned short) green),q);
1287 SetPixelBlue(image,ScaleShortToQuantum((unsigned short) blue),q);
1288 SetPixelAlpha(image,OpaqueAlpha,q);
1289 if (image->alpha_trait == BlendPixelTrait)
1290 SetPixelAlpha(image,
1291 ScaleShortToQuantum((unsigned short) opacity),q);
1292 q+=GetPixelChannels(image);
1294 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1296 offset=(MagickOffsetType) (image->rows-y-1);
1297 if (image->previous == (Image *) NULL)
1299 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1301 if (status == MagickFalse)
1309 pixel_info=RelinquishVirtualMemory(pixel_info);
1310 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1313 pixel_info=RelinquishVirtualMemory(pixel_info);
1314 if (EOFBlob(image) != MagickFalse)
1316 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
1320 if (bmp_info.height < 0)
1326 Correct image orientation.
1328 flipped_image=FlipImage(image,exception);
1329 if (flipped_image != (Image *) NULL)
1331 DuplicateBlob(flipped_image,image);
1332 image=DestroyImage(image);
1333 image=flipped_image;
1337 Proceed to next image.
1339 if (image_info->number_scenes != 0)
1340 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1343 if (bmp_info.ba_offset != 0)
1345 offset=SeekBlob(image,(MagickOffsetType) bmp_info.ba_offset,SEEK_SET);
1347 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1349 count=ReadBlob(image,2,magick);
1350 if ((count == 2) && (IsBMP(magick,2) != MagickFalse))
1353 Acquire next image structure.
1355 AcquireNextImage(image_info,image,exception);
1356 if (GetNextImageInList(image) == (Image *) NULL)
1358 image=DestroyImageList(image);
1359 return((Image *) NULL);
1361 image=SyncNextImageInList(image);
1362 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
1363 GetBlobSize(image));
1364 if (status == MagickFalse)
1367 } while (IsBMP(magick,2) != MagickFalse);
1368 (void) CloseBlob(image);
1369 return(GetFirstImageInList(image));
1373 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1377 % R e g i s t e r B M P I m a g e %
1381 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1383 % RegisterBMPImage() adds attributes for the BMP image format to
1384 % the list of supported formats. The attributes include the image format
1385 % tag, a method to read and/or write the format, whether the format
1386 % supports the saving of more than one frame to the same file or blob,
1387 % whether the format supports native in-memory I/O, and a brief
1388 % description of the format.
1390 % The format of the RegisterBMPImage method is:
1392 % size_t RegisterBMPImage(void)
1395 ModuleExport size_t RegisterBMPImage(void)
1400 entry=SetMagickInfo("BMP");
1401 entry->decoder=(DecodeImageHandler *) ReadBMPImage;
1402 entry->encoder=(EncodeImageHandler *) WriteBMPImage;
1403 entry->magick=(IsImageFormatHandler *) IsBMP;
1404 entry->description=ConstantString("Microsoft Windows bitmap image");
1405 entry->module=ConstantString("BMP");
1406 entry->adjoin=MagickFalse;
1407 entry->seekable_stream=MagickTrue;
1408 (void) RegisterMagickInfo(entry);
1409 entry=SetMagickInfo("BMP2");
1410 entry->encoder=(EncodeImageHandler *) WriteBMPImage;
1411 entry->magick=(IsImageFormatHandler *) IsBMP;
1412 entry->description=ConstantString("Microsoft Windows bitmap image (V2)");
1413 entry->module=ConstantString("BMP");
1414 entry->adjoin=MagickFalse;
1415 entry->seekable_stream=MagickTrue;
1416 (void) RegisterMagickInfo(entry);
1417 entry=SetMagickInfo("BMP3");
1418 entry->encoder=(EncodeImageHandler *) WriteBMPImage;
1419 entry->magick=(IsImageFormatHandler *) IsBMP;
1420 entry->description=ConstantString("Microsoft Windows bitmap image (V3)");
1421 entry->module=ConstantString("BMP");
1422 entry->adjoin=MagickFalse;
1423 entry->seekable_stream=MagickTrue;
1424 (void) RegisterMagickInfo(entry);
1425 return(MagickImageCoderSignature);
1429 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1433 % U n r e g i s t e r B M P I m a g e %
1437 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1439 % UnregisterBMPImage() removes format registrations made by the
1440 % BMP module from the list of supported formats.
1442 % The format of the UnregisterBMPImage method is:
1444 % UnregisterBMPImage(void)
1447 ModuleExport void UnregisterBMPImage(void)
1449 (void) UnregisterMagickInfo("BMP");
1450 (void) UnregisterMagickInfo("BMP2");
1451 (void) UnregisterMagickInfo("BMP3");
1455 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1459 % W r i t e B M P I m a g e %
1463 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1465 % WriteBMPImage() writes an image in Microsoft Windows bitmap encoded
1466 % image format, version 3 for Windows or (if the image has a matte channel)
1469 % The format of the WriteBMPImage method is:
1471 % MagickBooleanType WriteBMPImage(const ImageInfo *image_info,
1472 % Image *image,ExceptionInfo *exception)
1474 % A description of each parameter follows.
1476 % o image_info: the image info.
1478 % o image: The image.
1480 % o exception: return any errors or warnings in this structure.
1483 static MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image,
1484 ExceptionInfo *exception)
1505 register const Quantum
1512 register unsigned char
1527 Open output image file.
1529 assert(image_info != (const ImageInfo *) NULL);
1530 assert(image_info->signature == MagickSignature);
1531 assert(image != (Image *) NULL);
1532 assert(image->signature == MagickSignature);
1533 if (image->debug != MagickFalse)
1534 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1535 assert(exception != (ExceptionInfo *) NULL);
1536 assert(exception->signature == MagickSignature);
1537 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1538 if (status == MagickFalse)
1541 if (LocaleCompare(image_info->magick,"BMP2") == 0)
1544 if (LocaleCompare(image_info->magick,"BMP3") == 0)
1547 value=GetImageOption(image_info,"bmp:format");
1549 if (value != (char *) NULL)
1551 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1552 " Format=%s",value);
1554 if (LocaleCompare(value,"bmp2") == 0)
1556 if (LocaleCompare(value,"bmp3") == 0)
1558 if (LocaleCompare(value,"bmp4") == 0)
1566 Initialize BMP raster file header.
1568 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
1569 (void) TransformImageColorspace(image,sRGBColorspace,exception);
1570 (void) ResetMagickMemory(&bmp_info,0,sizeof(bmp_info));
1571 bmp_info.file_size=14+12;
1573 bmp_info.file_size+=28;
1574 bmp_info.offset_bits=bmp_info.file_size;
1575 bmp_info.compression=BI_RGB;
1576 if ((image->storage_class == PseudoClass) && (image->colors > 256))
1577 (void) SetImageStorageClass(image,DirectClass,exception);
1578 if (image->storage_class != DirectClass)
1581 Colormapped BMP raster.
1583 bmp_info.bits_per_pixel=8;
1584 if (image->colors <= 2)
1585 bmp_info.bits_per_pixel=1;
1587 if (image->colors <= 16)
1588 bmp_info.bits_per_pixel=4;
1590 if (image->colors <= 256)
1591 bmp_info.bits_per_pixel=8;
1592 if (image_info->compression == RLECompression)
1593 bmp_info.bits_per_pixel=8;
1594 bmp_info.number_colors=1U << bmp_info.bits_per_pixel;
1595 if (image->alpha_trait == BlendPixelTrait)
1596 (void) SetImageStorageClass(image,DirectClass,exception);
1598 if ((size_t) bmp_info.number_colors < image->colors)
1599 (void) SetImageStorageClass(image,DirectClass,exception);
1602 bmp_info.file_size+=3*(1UL << bmp_info.bits_per_pixel);
1603 bmp_info.offset_bits+=3*(1UL << bmp_info.bits_per_pixel);
1606 bmp_info.file_size+=(1UL << bmp_info.bits_per_pixel);
1607 bmp_info.offset_bits+=(1UL << bmp_info.bits_per_pixel);
1611 if (image->storage_class == DirectClass)
1614 Full color BMP raster.
1616 bmp_info.number_colors=0;
1617 bmp_info.bits_per_pixel=(unsigned short)
1618 ((type > 3) && (image->alpha_trait == BlendPixelTrait) ? 32 : 24);
1619 bmp_info.compression=(unsigned int) ((type > 3) &&
1620 (image->alpha_trait == BlendPixelTrait) ? BI_BITFIELDS : BI_RGB);
1622 bytes_per_line=4*((image->columns*bmp_info.bits_per_pixel+31)/32);
1623 bmp_info.ba_offset=0;
1624 profile=GetImageProfile(image,"icc");
1625 have_color_info=(image->rendering_intent != UndefinedIntent) ||
1626 (profile != (StringInfo *) NULL) || (image->gamma != 0.0) ? MagickTrue :
1631 if ((type == 3) || ((image->alpha_trait != BlendPixelTrait) &&
1632 (have_color_info == MagickFalse)))
1644 if ((image->rendering_intent != UndefinedIntent) ||
1645 (profile != (StringInfo *) NULL))
1650 bmp_info.file_size+=extra_size;
1651 bmp_info.offset_bits+=extra_size;
1653 bmp_info.width=(ssize_t) image->columns;
1654 bmp_info.height=(ssize_t) image->rows;
1656 bmp_info.image_size=(unsigned int) (bytes_per_line*image->rows);
1657 bmp_info.file_size+=bmp_info.image_size;
1658 bmp_info.x_pixels=75*39;
1659 bmp_info.y_pixels=75*39;
1660 switch (image->units)
1662 case UndefinedResolution:
1663 case PixelsPerInchResolution:
1665 bmp_info.x_pixels=(unsigned int) (100.0*image->resolution.x/2.54);
1666 bmp_info.y_pixels=(unsigned int) (100.0*image->resolution.y/2.54);
1669 case PixelsPerCentimeterResolution:
1671 bmp_info.x_pixels=(unsigned int) (100.0*image->resolution.x);
1672 bmp_info.y_pixels=(unsigned int) (100.0*image->resolution.y);
1676 bmp_info.colors_important=bmp_info.number_colors;
1678 Convert MIFF to BMP raster pixels.
1680 pixel_info=AcquireVirtualMemory((size_t) bmp_info.image_size,
1682 if (pixel_info == (MemoryInfo *) NULL)
1683 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1684 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
1685 (void) ResetMagickMemory(pixels,0,(size_t) bmp_info.image_size);
1686 switch (bmp_info.bits_per_pixel)
1695 Convert PseudoClass image to a BMP monochrome image.
1697 for (y=0; y < (ssize_t) image->rows; y++)
1702 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1703 if (p == (const Quantum *) NULL)
1705 q=pixels+(image->rows-y-1)*bytes_per_line;
1708 for (x=0; x < (ssize_t) image->columns; x++)
1711 byte|=GetPixelIndex(image,p) != 0 ? 0x01 : 0x00;
1715 *q++=(unsigned char) byte;
1719 p+=GetPixelChannels(image);
1723 *q++=(unsigned char) (byte << (8-bit));
1726 offset=(ssize_t) (image->columns+7)/8;
1727 for (x=offset; x < (ssize_t) bytes_per_line; x++)
1729 if (image->previous == (Image *) NULL)
1731 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1733 if (status == MagickFalse)
1749 Convert PseudoClass image to a BMP monochrome image.
1751 for (y=0; y < (ssize_t) image->rows; y++)
1753 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1754 if (p == (const Quantum *) NULL)
1756 q=pixels+(image->rows-y-1)*bytes_per_line;
1759 for (x=0; x < (ssize_t) image->columns; x++)
1762 byte|=((size_t) GetPixelIndex(image,p) & 0x0f);
1766 *q++=(unsigned char) byte;
1770 p+=GetPixelChannels(image);
1774 *q++=(unsigned char) (byte << 4);
1777 offset=(ssize_t) (image->columns+1)/2;
1778 for (x=offset; x < (ssize_t) bytes_per_line; x++)
1780 if (image->previous == (Image *) NULL)
1782 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1784 if (status == MagickFalse)
1793 Convert PseudoClass packet to BMP pixel.
1795 for (y=0; y < (ssize_t) image->rows; y++)
1797 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1798 if (p == (const Quantum *) NULL)
1800 q=pixels+(image->rows-y-1)*bytes_per_line;
1801 for (x=0; x < (ssize_t) image->columns; x++)
1803 *q++=(unsigned char) GetPixelIndex(image,p);
1804 p+=GetPixelChannels(image);
1806 for ( ; x < (ssize_t) bytes_per_line; x++)
1808 if (image->previous == (Image *) NULL)
1810 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1812 if (status == MagickFalse)
1821 Convert DirectClass packet to BMP BGR888.
1823 for (y=0; y < (ssize_t) image->rows; y++)
1825 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1826 if (p == (const Quantum *) NULL)
1828 q=pixels+(image->rows-y-1)*bytes_per_line;
1829 for (x=0; x < (ssize_t) image->columns; x++)
1831 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
1832 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
1833 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
1834 p+=GetPixelChannels(image);
1836 for (x=3L*(ssize_t) image->columns; x < (ssize_t) bytes_per_line; x++)
1838 if (image->previous == (Image *) NULL)
1840 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1842 if (status == MagickFalse)
1851 Convert DirectClass packet to ARGB8888 pixel.
1853 for (y=0; y < (ssize_t) image->rows; y++)
1855 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1856 if (p == (const Quantum *) NULL)
1858 q=pixels+(image->rows-y-1)*bytes_per_line;
1859 for (x=0; x < (ssize_t) image->columns; x++)
1861 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
1862 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
1863 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
1864 *q++=ScaleQuantumToChar(GetPixelAlpha(image,p));
1865 p+=GetPixelChannels(image);
1867 if (image->previous == (Image *) NULL)
1869 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1871 if (status == MagickFalse)
1878 if ((type > 2) && (bmp_info.bits_per_pixel == 8))
1879 if (image_info->compression != NoCompression)
1885 Convert run-length encoded raster pixels.
1887 rle_info=AcquireVirtualMemory((size_t) (2*(bytes_per_line+2)+2),
1888 (image->rows+2)*sizeof(*pixels));
1889 if (rle_info == (MemoryInfo *) NULL)
1891 pixel_info=RelinquishVirtualMemory(pixel_info);
1892 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1894 bmp_data=(unsigned char *) GetVirtualMemoryBlob(rle_info);
1895 bmp_info.file_size-=bmp_info.image_size;
1896 bmp_info.image_size=(unsigned int) EncodeImage(image,bytes_per_line,
1898 bmp_info.file_size+=bmp_info.image_size;
1899 pixel_info=RelinquishVirtualMemory(pixel_info);
1900 pixel_info=rle_info;
1902 bmp_info.compression=BI_RLE8;
1905 Write BMP for Windows, all versions, 14-byte header.
1907 if (image->debug != MagickFalse)
1909 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1910 " Writing BMP version %.20g datastream",(double) type);
1911 if (image->storage_class == DirectClass)
1912 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1913 " Storage class=DirectClass");
1915 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1916 " Storage class=PseudoClass");
1917 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1918 " Image depth=%.20g",(double) image->depth);
1919 if (image->alpha_trait == BlendPixelTrait)
1920 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1923 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1924 " Matte=MagickFalse");
1925 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1926 " BMP bits_per_pixel=%.20g",(double) bmp_info.bits_per_pixel);
1927 switch ((int) bmp_info.compression)
1931 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1932 " Compression=BI_RGB");
1937 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1938 " Compression=BI_RLE8");
1943 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1944 " Compression=BI_BITFIELDS");
1949 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1950 " Compression=UNKNOWN (%u)",bmp_info.compression);
1954 if (bmp_info.number_colors == 0)
1955 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1956 " Number_colors=unspecified");
1958 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1959 " Number_colors=%u",bmp_info.number_colors);
1961 (void) WriteBlob(image,2,(unsigned char *) "BM");
1962 (void) WriteBlobLSBLong(image,bmp_info.file_size);
1963 (void) WriteBlobLSBLong(image,bmp_info.ba_offset); /* always 0 */
1964 (void) WriteBlobLSBLong(image,bmp_info.offset_bits);
1968 Write 12-byte version 2 bitmap header.
1970 (void) WriteBlobLSBLong(image,bmp_info.size);
1971 (void) WriteBlobLSBShort(image,(unsigned short) bmp_info.width);
1972 (void) WriteBlobLSBShort(image,(unsigned short) bmp_info.height);
1973 (void) WriteBlobLSBShort(image,bmp_info.planes);
1974 (void) WriteBlobLSBShort(image,bmp_info.bits_per_pixel);
1979 Write 40-byte version 3+ bitmap header.
1981 (void) WriteBlobLSBLong(image,bmp_info.size);
1982 (void) WriteBlobLSBLong(image,(unsigned int) bmp_info.width);
1983 (void) WriteBlobLSBLong(image,(unsigned int) bmp_info.height);
1984 (void) WriteBlobLSBShort(image,bmp_info.planes);
1985 (void) WriteBlobLSBShort(image,bmp_info.bits_per_pixel);
1986 (void) WriteBlobLSBLong(image,bmp_info.compression);
1987 (void) WriteBlobLSBLong(image,bmp_info.image_size);
1988 (void) WriteBlobLSBLong(image,bmp_info.x_pixels);
1989 (void) WriteBlobLSBLong(image,bmp_info.y_pixels);
1990 (void) WriteBlobLSBLong(image,bmp_info.number_colors);
1991 (void) WriteBlobLSBLong(image,bmp_info.colors_important);
1993 if ((type > 3) && ((image->alpha_trait == BlendPixelTrait) ||
1994 (have_color_info != MagickFalse)))
1997 Write the rest of the 108-byte BMP Version 4 header.
1999 (void) WriteBlobLSBLong(image,0x00ff0000U); /* Red mask */
2000 (void) WriteBlobLSBLong(image,0x0000ff00U); /* Green mask */
2001 (void) WriteBlobLSBLong(image,0x000000ffU); /* Blue mask */
2002 (void) WriteBlobLSBLong(image,0xff000000U); /* Alpha mask */
2003 (void) WriteBlobLSBLong(image,0x73524742U); /* sRGB */
2004 (void) WriteBlobLSBLong(image,(unsigned int)
2005 (image->chromaticity.red_primary.x*0x40000000));
2006 (void) WriteBlobLSBLong(image,(unsigned int)
2007 (image->chromaticity.red_primary.y*0x40000000));
2008 (void) WriteBlobLSBLong(image,(unsigned int)
2009 ((1.000f-(image->chromaticity.red_primary.x+
2010 image->chromaticity.red_primary.y))*0x40000000));
2011 (void) WriteBlobLSBLong(image,(unsigned int)
2012 (image->chromaticity.green_primary.x*0x40000000));
2013 (void) WriteBlobLSBLong(image,(unsigned int)
2014 (image->chromaticity.green_primary.y*0x40000000));
2015 (void) WriteBlobLSBLong(image,(unsigned int)
2016 ((1.000f-(image->chromaticity.green_primary.x+
2017 image->chromaticity.green_primary.y))*0x40000000));
2018 (void) WriteBlobLSBLong(image,(unsigned int)
2019 (image->chromaticity.blue_primary.x*0x40000000));
2020 (void) WriteBlobLSBLong(image,(unsigned int)
2021 (image->chromaticity.blue_primary.y*0x40000000));
2022 (void) WriteBlobLSBLong(image,(unsigned int)
2023 ((1.000f-(image->chromaticity.blue_primary.x+
2024 image->chromaticity.blue_primary.y))*0x40000000));
2025 (void) WriteBlobLSBLong(image,(unsigned int)
2026 (bmp_info.gamma_scale.x*0x10000));
2027 (void) WriteBlobLSBLong(image,(unsigned int)
2028 (bmp_info.gamma_scale.y*0x10000));
2029 (void) WriteBlobLSBLong(image,(unsigned int)
2030 (bmp_info.gamma_scale.z*0x10000));
2031 if ((image->rendering_intent != UndefinedIntent) ||
2032 (profile != (StringInfo *) NULL))
2037 switch ((int) image->rendering_intent)
2039 case SaturationIntent:
2041 intent=LCS_GM_BUSINESS;
2044 case RelativeIntent:
2046 intent=LCS_GM_GRAPHICS;
2049 case PerceptualIntent:
2051 intent=LCS_GM_IMAGES;
2054 case AbsoluteIntent:
2056 intent=LCS_GM_ABS_COLORIMETRIC;
2065 (void) WriteBlobLSBLong(image,(unsigned int) intent);
2066 (void) WriteBlobLSBLong(image,0x00); /* dummy profile data */
2067 (void) WriteBlobLSBLong(image,0x00); /* dummy profile length */
2068 (void) WriteBlobLSBLong(image,0x00); /* reserved */
2071 if (image->storage_class == PseudoClass)
2077 Dump colormap to file.
2079 if (image->debug != MagickFalse)
2080 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2081 " Colormap: %.20g entries",(double) image->colors);
2082 bmp_colormap=(unsigned char *) AcquireQuantumMemory((size_t) (1UL <<
2083 bmp_info.bits_per_pixel),4*sizeof(*bmp_colormap));
2084 if (bmp_colormap == (unsigned char *) NULL)
2085 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2087 for (i=0; i < (ssize_t) MagickMin((ssize_t) image->colors,(ssize_t) bmp_info.number_colors); i++)
2089 *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].blue));
2090 *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].green));
2091 *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].red));
2093 *q++=(unsigned char) 0x0;
2095 for ( ; i < (ssize_t) (1UL << bmp_info.bits_per_pixel); i++)
2097 *q++=(unsigned char) 0x00;
2098 *q++=(unsigned char) 0x00;
2099 *q++=(unsigned char) 0x00;
2101 *q++=(unsigned char) 0x00;
2104 (void) WriteBlob(image,(size_t) (3*(1L << bmp_info.bits_per_pixel)),
2107 (void) WriteBlob(image,(size_t) (4*(1L << bmp_info.bits_per_pixel)),
2109 bmp_colormap=(unsigned char *) RelinquishMagickMemory(bmp_colormap);
2111 if (image->debug != MagickFalse)
2112 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2113 " Pixels: %u bytes",bmp_info.image_size);
2114 (void) WriteBlob(image,(size_t) bmp_info.image_size,pixels);
2115 pixel_info=RelinquishVirtualMemory(pixel_info);
2116 if (GetNextImageInList(image) == (Image *) NULL)
2118 image=SyncNextImageInList(image);
2119 status=SetImageProgress(image,SaveImagesTag,scene++,
2120 GetImageListLength(image));
2121 if (status == MagickFalse)
2123 } while (image_info->adjoin != MagickFalse);
2124 (void) CloseBlob(image);