blob: 4f31b8123197c2f60721478e781284ebe032d74c [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 %
cristyde984cd2013-12-01 14:49:27 +000016% Cristy %
cristy3ed852e2009-09-05 21:47:34 +000017% Glenn Randers-Pehrson %
18% December 2001 %
19% %
20% %
cristyb56bb242014-11-25 17:12:48 +000021% Copyright 1999-2015 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*/
cristy4c08aed2011-07-01 19:47:50 +000043#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"
cristy510d06a2011-07-06 23:43:54 +000051#include "MagickCore/colorspace-private.h"
cristy4c08aed2011-07-01 19:47:50 +000052#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"
cristye462ed72013-08-13 12:20:40 +000062#include "MagickCore/option.h"
cristy4c08aed2011-07-01 19:47:50 +000063#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"
cristy3ed852e2009-09-05 21:47:34 +000070
71/*
72 Macro definitions (from Windows wingdi.h).
73*/
74#undef BI_JPEG
75#define BI_JPEG 4
76#undef BI_PNG
77#define BI_PNG 5
cristy07a3cca2012-12-10 13:09:10 +000078#if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__MINGW32__) || defined(__MINGW64__)
cristy3a99dcf2011-12-17 01:29:40 +000079#undef BI_RGB
cristy3ed852e2009-09-05 21:47:34 +000080#define BI_RGB 0
cristy3a99dcf2011-12-17 01:29:40 +000081#undef BI_RLE8
cristy3ed852e2009-09-05 21:47:34 +000082#define BI_RLE8 1
cristy3a99dcf2011-12-17 01:29:40 +000083#undef BI_RLE4
cristy3ed852e2009-09-05 21:47:34 +000084#define BI_RLE4 2
cristy3a99dcf2011-12-17 01:29:40 +000085#undef BI_BITFIELDS
cristy3ed852e2009-09-05 21:47:34 +000086#define BI_BITFIELDS 3
87
cristy3a99dcf2011-12-17 01:29:40 +000088#undef LCS_CALIBRATED_RBG
cristy3ed852e2009-09-05 21:47:34 +000089#define LCS_CALIBRATED_RBG 0
cristy3a99dcf2011-12-17 01:29:40 +000090#undef LCS_sRGB
cristy3ed852e2009-09-05 21:47:34 +000091#define LCS_sRGB 1
cristy3a99dcf2011-12-17 01:29:40 +000092#undef LCS_WINDOWS_COLOR_SPACE
cristy3ed852e2009-09-05 21:47:34 +000093#define LCS_WINDOWS_COLOR_SPACE 2
cristy3a99dcf2011-12-17 01:29:40 +000094#undef PROFILE_LINKED
cristy3ed852e2009-09-05 21:47:34 +000095#define PROFILE_LINKED 3
cristy3a99dcf2011-12-17 01:29:40 +000096#undef PROFILE_EMBEDDED
cristy3ed852e2009-09-05 21:47:34 +000097#define PROFILE_EMBEDDED 4
98
cristy3a99dcf2011-12-17 01:29:40 +000099#undef LCS_GM_BUSINESS
cristy3ed852e2009-09-05 21:47:34 +0000100#define LCS_GM_BUSINESS 1 /* Saturation */
cristy3a99dcf2011-12-17 01:29:40 +0000101#undef LCS_GM_GRAPHICS
cristy3ed852e2009-09-05 21:47:34 +0000102#define LCS_GM_GRAPHICS 2 /* Relative */
cristy3a99dcf2011-12-17 01:29:40 +0000103#undef LCS_GM_IMAGES
cristy3ed852e2009-09-05 21:47:34 +0000104#define LCS_GM_IMAGES 4 /* Perceptual */
cristy3a99dcf2011-12-17 01:29:40 +0000105#undef LCS_GM_ABS_COLORIMETRIC
cristy3ed852e2009-09-05 21:47:34 +0000106#define LCS_GM_ABS_COLORIMETRIC 8 /* Absolute */
107#endif
108
109/*
110 Typedef declarations.
111*/
112typedef struct _BMPInfo
113{
114 unsigned int
115 file_size,
116 ba_offset,
117 offset_bits,
118 size;
119
cristy7c242ea2013-06-21 17:19:53 +0000120 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000121 width,
122 height;
123
124 unsigned short
125 planes,
126 bits_per_pixel;
127
128 unsigned int
129 compression,
130 image_size,
131 x_pixels,
132 y_pixels,
133 number_colors,
134 red_mask,
135 green_mask,
136 blue_mask,
137 alpha_mask,
138 colors_important;
139
140 int
141 colorspace;
142
143 PrimaryInfo
144 red_primary,
145 green_primary,
146 blue_primary,
147 gamma_scale;
148} BMPInfo;
149
150/*
151 Forward declarations.
152*/
153static MagickBooleanType
cristy1e178e72011-08-28 19:44:34 +0000154 WriteBMPImage(const ImageInfo *,Image *,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000155
156/*
157%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
158% %
159% %
160% %
161% D e c o d e I m a g e %
162% %
163% %
164% %
165%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
166%
167% DecodeImage unpacks the packed image pixels into runlength-encoded
168% pixel packets.
169%
170% The format of the DecodeImage method is:
171%
172% MagickBooleanType DecodeImage(Image *image,
cristybb503372010-05-27 20:51:26 +0000173% const size_t compression,unsigned char *pixels)
cristy3ed852e2009-09-05 21:47:34 +0000174%
175% A description of each parameter follows:
176%
177% o image: the address of a structure of type Image.
178%
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
182% encoding.
183%
184% o pixels: The address of a byte (8 bits) array of pixel data created by
185% the decoding process.
186%
187*/
cristy4e82e512011-04-24 01:33:42 +0000188static MagickBooleanType DecodeImage(Image *image,const size_t compression,
189 unsigned char *pixels)
cristy3ed852e2009-09-05 21:47:34 +0000190{
cristy32e04a32013-06-16 00:48:49 +0000191 int
192 count;
193
cristybb503372010-05-27 20:51:26 +0000194 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000195 i,
196 x;
197
198 register unsigned char
199 *p,
200 *q;
201
cristy4e82e512011-04-24 01:33:42 +0000202 ssize_t
203 y;
204
cristy3ed852e2009-09-05 21:47:34 +0000205 unsigned char
206 byte;
207
208 assert(image != (Image *) NULL);
209 assert(image->signature == MagickSignature);
210 if (image->debug != MagickFalse)
211 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
212 assert(pixels != (unsigned char *) NULL);
213 (void) ResetMagickMemory(pixels,0,(size_t) image->columns*image->rows*
214 sizeof(*pixels));
215 byte=0;
216 x=0;
217 p=pixels;
218 q=pixels+(size_t) image->columns*image->rows;
cristybb503372010-05-27 20:51:26 +0000219 for (y=0; y < (ssize_t) image->rows; )
cristy3ed852e2009-09-05 21:47:34 +0000220 {
221 if ((p < pixels) || (p >= q))
222 break;
cristy32e04a32013-06-16 00:48:49 +0000223 count=ReadBlobByte(image);
224 if (count == EOF)
cristy3ed852e2009-09-05 21:47:34 +0000225 break;
226 if (count != 0)
227 {
228 /*
229 Encoded mode.
230 */
cristya321eb72013-06-23 10:42:37 +0000231 count=(int) MagickMin((ssize_t) count,(ssize_t) (q-p));
cristy3ed852e2009-09-05 21:47:34 +0000232 byte=(unsigned char) ReadBlobByte(image);
233 if (compression == BI_RLE8)
234 {
cristya321eb72013-06-23 10:42:37 +0000235 for (i=0; i < (ssize_t) count; i++)
cristy3ed852e2009-09-05 21:47:34 +0000236 *p++=(unsigned char) byte;
237 }
238 else
239 {
cristya321eb72013-06-23 10:42:37 +0000240 for (i=0; i < (ssize_t) count; i++)
cristy3ed852e2009-09-05 21:47:34 +0000241 *p++=(unsigned char)
242 ((i & 0x01) != 0 ? (byte & 0x0f) : ((byte >> 4) & 0x0f));
243 }
244 x+=count;
245 }
246 else
247 {
248 /*
249 Escape mode.
250 */
cristy32e04a32013-06-16 00:48:49 +0000251 count=ReadBlobByte(image);
cristy3ed852e2009-09-05 21:47:34 +0000252 if (count == 0x01)
253 return(MagickTrue);
254 switch (count)
255 {
256 case 0x00:
257 {
258 /*
259 End of line.
260 */
261 x=0;
262 y++;
263 p=pixels+y*image->columns;
264 break;
265 }
266 case 0x02:
267 {
268 /*
269 Delta mode.
270 */
271 x+=ReadBlobByte(image);
272 y+=ReadBlobByte(image);
273 p=pixels+y*image->columns+x;
274 break;
275 }
276 default:
277 {
278 /*
279 Absolute mode.
280 */
cristya321eb72013-06-23 10:42:37 +0000281 count=(int) MagickMin((ssize_t) count,(ssize_t) (q-p));
cristy3ed852e2009-09-05 21:47:34 +0000282 if (compression == BI_RLE8)
cristya321eb72013-06-23 10:42:37 +0000283 for (i=0; i < (ssize_t) count; i++)
cristy3ed852e2009-09-05 21:47:34 +0000284 *p++=(unsigned char) ReadBlobByte(image);
285 else
cristya321eb72013-06-23 10:42:37 +0000286 for (i=0; i < (ssize_t) count; i++)
cristy3ed852e2009-09-05 21:47:34 +0000287 {
288 if ((i & 0x01) == 0)
289 byte=(unsigned char) ReadBlobByte(image);
290 *p++=(unsigned char)
291 ((i & 0x01) != 0 ? (byte & 0x0f) : ((byte >> 4) & 0x0f));
292 }
293 x+=count;
294 /*
295 Read pad byte.
296 */
297 if (compression == BI_RLE8)
298 {
299 if ((count & 0x01) != 0)
300 (void) ReadBlobByte(image);
301 }
302 else
303 if (((count & 0x03) == 1) || ((count & 0x03) == 2))
304 (void) ReadBlobByte(image);
305 break;
306 }
307 }
308 }
cristya321eb72013-06-23 10:42:37 +0000309 if (SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,image->rows) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000310 break;
311 }
312 (void) ReadBlobByte(image); /* end of line */
313 (void) ReadBlobByte(image);
314 return(MagickTrue);
315}
316
317/*
318%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
319% %
320% %
321% %
322% E n c o d e I m a g e %
323% %
324% %
325% %
326%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
327%
328% EncodeImage compresses pixels using a runlength encoded format.
329%
330% The format of the EncodeImage method is:
331%
332% static MagickBooleanType EncodeImage(Image *image,
cristybb503372010-05-27 20:51:26 +0000333% const size_t bytes_per_line,const unsigned char *pixels,
cristy3ed852e2009-09-05 21:47:34 +0000334% unsigned char *compressed_pixels)
335%
336% A description of each parameter follows:
337%
338% o image: The image.
339%
340% o bytes_per_line: the number of bytes in a scanline of compressed pixels
341%
342% o pixels: The address of a byte (8 bits) array of pixel data created by
343% the compression process.
344%
345% o compressed_pixels: The address of a byte (8 bits) array of compressed
346% pixel data.
347%
348*/
cristybb503372010-05-27 20:51:26 +0000349static size_t EncodeImage(Image *image,const size_t bytes_per_line,
cristy3ed852e2009-09-05 21:47:34 +0000350 const unsigned char *pixels,unsigned char *compressed_pixels)
351{
cristy3ed852e2009-09-05 21:47:34 +0000352 MagickBooleanType
353 status;
354
355 register const unsigned char
356 *p;
357
cristybb503372010-05-27 20:51:26 +0000358 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000359 i,
360 x;
361
362 register unsigned char
363 *q;
364
cristy4e82e512011-04-24 01:33:42 +0000365 ssize_t
366 y;
367
cristy3ed852e2009-09-05 21:47:34 +0000368 /*
369 Runlength encode pixels.
370 */
371 assert(image != (Image *) NULL);
372 assert(image->signature == MagickSignature);
373 if (image->debug != MagickFalse)
374 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
375 assert(pixels != (const unsigned char *) NULL);
376 assert(compressed_pixels != (unsigned char *) NULL);
377 p=pixels;
378 q=compressed_pixels;
379 i=0;
cristybb503372010-05-27 20:51:26 +0000380 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000381 {
cristybb503372010-05-27 20:51:26 +0000382 for (x=0; x < (ssize_t) bytes_per_line; x+=i)
cristy3ed852e2009-09-05 21:47:34 +0000383 {
384 /*
385 Determine runlength.
386 */
cristybb503372010-05-27 20:51:26 +0000387 for (i=1; ((x+i) < (ssize_t) bytes_per_line); i++)
cristy3ed852e2009-09-05 21:47:34 +0000388 if ((i == 255) || (*(p+i) != *p))
389 break;
390 *q++=(unsigned char) i;
391 *q++=(*p);
392 p+=i;
393 }
394 /*
395 End of line.
396 */
397 *q++=(unsigned char) 0x00;
398 *q++=(unsigned char) 0x00;
cristycee97112010-05-28 00:44:52 +0000399 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
cristy4e82e512011-04-24 01:33:42 +0000400 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000401 if (status == MagickFalse)
402 break;
403 }
404 /*
405 End of bitmap.
406 */
407 *q++=(unsigned char) 0x00;
408 *q++=(unsigned char) 0x01;
409 return((size_t) (q-compressed_pixels));
410}
411
412/*
413%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
414% %
415% %
416% %
417% I s B M P %
418% %
419% %
420% %
421%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
422%
423% IsBMP() returns MagickTrue if the image format type, identified by the
424% magick string, is BMP.
425%
426% The format of the IsBMP method is:
427%
428% MagickBooleanType IsBMP(const unsigned char *magick,const size_t length)
429%
430% A description of each parameter follows:
431%
432% o magick: compare image format pattern against these bytes.
433%
434% o length: Specifies the length of the magick string.
435%
436*/
437static MagickBooleanType IsBMP(const unsigned char *magick,const size_t length)
438{
439 if (length < 2)
440 return(MagickFalse);
441 if ((LocaleNCompare((char *) magick,"BA",2) == 0) ||
442 (LocaleNCompare((char *) magick,"BM",2) == 0) ||
443 (LocaleNCompare((char *) magick,"IC",2) == 0) ||
444 (LocaleNCompare((char *) magick,"PI",2) == 0) ||
445 (LocaleNCompare((char *) magick,"CI",2) == 0) ||
446 (LocaleNCompare((char *) magick,"CP",2) == 0))
447 return(MagickTrue);
448 return(MagickFalse);
449}
450
451/*
452%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
453% %
454% %
455% %
456% R e a d B M P I m a g e %
457% %
458% %
459% %
460%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
461%
462% ReadBMPImage() reads a Microsoft Windows bitmap image file, Version
463% 2, 3 (for Windows or NT), or 4, and returns it. It allocates the memory
464% necessary for the new Image structure and returns a pointer to the new
465% image.
466%
467% The format of the ReadBMPImage method is:
468%
469% image=ReadBMPImage(image_info)
470%
471% A description of each parameter follows:
472%
473% o image_info: the image info.
474%
475% o exception: return any errors or warnings in this structure.
476%
477*/
478
479static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
480{
481 BMPInfo
482 bmp_info;
483
484 Image
485 *image;
486
cristy3ed852e2009-09-05 21:47:34 +0000487 MagickBooleanType
488 status;
489
490 MagickOffsetType
491 offset,
492 start_position;
493
cristya321eb72013-06-23 10:42:37 +0000494 MemoryInfo
cristy0553bd52013-06-30 15:53:50 +0000495 *pixel_info;
cristya321eb72013-06-23 10:42:37 +0000496
cristy4c08aed2011-07-01 19:47:50 +0000497 Quantum
498 index;
cristy3ed852e2009-09-05 21:47:34 +0000499
cristy4c08aed2011-07-01 19:47:50 +0000500 register Quantum
cristy3ed852e2009-09-05 21:47:34 +0000501 *q;
502
cristybb503372010-05-27 20:51:26 +0000503 register ssize_t
cristy0da03562011-04-23 23:23:21 +0000504 i,
505 x;
cristy3ed852e2009-09-05 21:47:34 +0000506
507 register unsigned char
508 *p;
509
cristybb503372010-05-27 20:51:26 +0000510 size_t
cristy3ed852e2009-09-05 21:47:34 +0000511 bit,
512 blue,
513 bytes_per_line,
514 green,
cristy0da03562011-04-23 23:23:21 +0000515 length,
cristy3ed852e2009-09-05 21:47:34 +0000516 red;
517
cristy0da03562011-04-23 23:23:21 +0000518 ssize_t
cristy4e82e512011-04-24 01:33:42 +0000519 count,
520 y;
cristy0da03562011-04-23 23:23:21 +0000521
522 unsigned char
523 magick[12],
524 *pixels;
525
cristy3ed852e2009-09-05 21:47:34 +0000526 /*
527 Open image file.
528 */
529 assert(image_info != (const ImageInfo *) NULL);
530 assert(image_info->signature == MagickSignature);
531 if (image_info->debug != MagickFalse)
532 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
533 image_info->filename);
534 assert(exception != (ExceptionInfo *) NULL);
535 assert(exception->signature == MagickSignature);
cristy9950d572011-10-01 18:22:35 +0000536 image=AcquireImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +0000537 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
538 if (status == MagickFalse)
539 {
540 image=DestroyImageList(image);
541 return((Image *) NULL);
542 }
543 /*
544 Determine if this a BMP file.
545 */
546 (void) ResetMagickMemory(&bmp_info,0,sizeof(bmp_info));
547 bmp_info.ba_offset=0;
548 start_position=0;
549 count=ReadBlob(image,2,magick);
cristy771c8842015-01-09 12:13:22 +0000550 if (count != 2)
551 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
cristy3ed852e2009-09-05 21:47:34 +0000552 do
553 {
cristy101ab702011-10-13 13:06:32 +0000554 PixelInfo
555 quantum_bits;
cristy3ed852e2009-09-05 21:47:34 +0000556
557 PixelPacket
cristy101ab702011-10-13 13:06:32 +0000558 shift;
cristy3ed852e2009-09-05 21:47:34 +0000559
cristybb503372010-05-27 20:51:26 +0000560 size_t
cristy3ed852e2009-09-05 21:47:34 +0000561 profile_data,
562 profile_size;
563
564 /*
565 Verify BMP identifier.
566 */
567 if (bmp_info.ba_offset == 0)
568 start_position=TellBlob(image)-2;
569 bmp_info.ba_offset=0;
570 while (LocaleNCompare((char *) magick,"BA",2) == 0)
571 {
572 bmp_info.file_size=ReadBlobLSBLong(image);
573 bmp_info.ba_offset=ReadBlobLSBLong(image);
574 bmp_info.offset_bits=ReadBlobLSBLong(image);
575 count=ReadBlob(image,2,magick);
576 if (count != 2)
577 break;
578 }
579 if (image->debug != MagickFalse)
580 (void) LogMagickEvent(CoderEvent,GetMagickModule()," Magick: %c%c",
581 magick[0],magick[1]);
cristy6af1e972015-01-06 12:46:27 +0000582 if ((count != 2) || ((LocaleNCompare((char *) magick,"BM",2) != 0) &&
cristy3ed852e2009-09-05 21:47:34 +0000583 (LocaleNCompare((char *) magick,"CI",2) != 0)))
584 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
585 bmp_info.file_size=ReadBlobLSBLong(image);
586 (void) ReadBlobLSBLong(image);
587 bmp_info.offset_bits=ReadBlobLSBLong(image);
588 bmp_info.size=ReadBlobLSBLong(image);
589 if (image->debug != MagickFalse)
590 (void) LogMagickEvent(CoderEvent,GetMagickModule()," BMP size: %u",
591 bmp_info.size);
592 if (bmp_info.size == 12)
593 {
594 /*
595 OS/2 BMP image file.
596 */
dirk5816af42014-09-14 08:53:21 +0000597 (void) CopyMagickString(image->magick,"BMP2",MaxTextExtent);
cristya321eb72013-06-23 10:42:37 +0000598 bmp_info.width=(ssize_t) ((short) ReadBlobLSBShort(image));
599 bmp_info.height=(ssize_t) ((short) ReadBlobLSBShort(image));
cristy3ed852e2009-09-05 21:47:34 +0000600 bmp_info.planes=ReadBlobLSBShort(image);
601 bmp_info.bits_per_pixel=ReadBlobLSBShort(image);
602 bmp_info.x_pixels=0;
603 bmp_info.y_pixels=0;
604 bmp_info.number_colors=0;
605 bmp_info.compression=BI_RGB;
606 bmp_info.image_size=0;
607 bmp_info.alpha_mask=0;
608 if (image->debug != MagickFalse)
609 {
610 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
611 " Format: OS/2 Bitmap");
612 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +0000613 " Geometry: %.20gx%.20g",(double) bmp_info.width,(double)
614 bmp_info.height);
cristy3ed852e2009-09-05 21:47:34 +0000615 }
616 }
617 else
618 {
619 /*
620 Microsoft Windows BMP image file.
621 */
622 if (bmp_info.size < 40)
623 ThrowReaderException(CorruptImageError,"NonOS2HeaderSizeError");
cristya321eb72013-06-23 10:42:37 +0000624 bmp_info.width=(ssize_t) ((int) ReadBlobLSBLong(image));
625 bmp_info.height=(ssize_t) ((int) ReadBlobLSBLong(image));
cristy3ed852e2009-09-05 21:47:34 +0000626 bmp_info.planes=ReadBlobLSBShort(image);
627 bmp_info.bits_per_pixel=ReadBlobLSBShort(image);
628 bmp_info.compression=ReadBlobLSBLong(image);
629 bmp_info.image_size=ReadBlobLSBLong(image);
630 bmp_info.x_pixels=ReadBlobLSBLong(image);
631 bmp_info.y_pixels=ReadBlobLSBLong(image);
632 bmp_info.number_colors=ReadBlobLSBLong(image);
633 bmp_info.colors_important=ReadBlobLSBLong(image);
634 profile_data=0;
635 profile_size=0;
636 if (image->debug != MagickFalse)
637 {
638 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
639 " Format: MS Windows bitmap");
640 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +0000641 " Geometry: %.20gx%.20g",(double) bmp_info.width,(double)
642 bmp_info.height);
cristy3ed852e2009-09-05 21:47:34 +0000643 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +0000644 " Bits per pixel: %.20g",(double) bmp_info.bits_per_pixel);
cristy3ed852e2009-09-05 21:47:34 +0000645 switch ((int) bmp_info.compression)
646 {
647 case BI_RGB:
648 {
649 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
650 " Compression: BI_RGB");
651 break;
652 }
653 case BI_RLE4:
654 {
655 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
656 " Compression: BI_RLE4");
657 break;
658 }
659 case BI_RLE8:
660 {
661 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
662 " Compression: BI_RLE8");
663 break;
664 }
665 case BI_BITFIELDS:
666 {
667 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
668 " Compression: BI_BITFIELDS");
669 break;
670 }
671 case BI_PNG:
672 {
673 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
674 " Compression: BI_PNG");
675 break;
676 }
677 case BI_JPEG:
678 {
679 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
680 " Compression: BI_JPEG");
681 break;
682 }
683 default:
684 {
685 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
686 " Compression: UNKNOWN (%u)",bmp_info.compression);
687 }
688 }
689 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
690 " Number of colors: %u",bmp_info.number_colors);
691 }
692 bmp_info.red_mask=ReadBlobLSBLong(image);
693 bmp_info.green_mask=ReadBlobLSBLong(image);
694 bmp_info.blue_mask=ReadBlobLSBLong(image);
695 if (bmp_info.size > 40)
696 {
glennrp34ea3d32012-11-22 03:57:24 +0000697
cristy3ed852e2009-09-05 21:47:34 +0000698 double
699 sum;
700
701 /*
702 Read color management information.
703 */
704 bmp_info.alpha_mask=ReadBlobLSBLong(image);
cristy6cff05d2010-09-02 11:22:46 +0000705 bmp_info.colorspace=(int) ReadBlobLSBLong(image);
cristy3ed852e2009-09-05 21:47:34 +0000706 /*
707 Decode 2^30 fixed point formatted CIE primaries.
708 */
glennrp34ea3d32012-11-22 03:57:24 +0000709# define BMP_DENOM ((double) 0x40000000)
710 bmp_info.red_primary.x=(double) ReadBlobLSBLong(image)/BMP_DENOM;
711 bmp_info.red_primary.y=(double) ReadBlobLSBLong(image)/BMP_DENOM;
712 bmp_info.red_primary.z=(double) ReadBlobLSBLong(image)/BMP_DENOM;
713 bmp_info.green_primary.x=(double) ReadBlobLSBLong(image)/BMP_DENOM;
714 bmp_info.green_primary.y=(double) ReadBlobLSBLong(image)/BMP_DENOM;
715 bmp_info.green_primary.z=(double) ReadBlobLSBLong(image)/BMP_DENOM;
716 bmp_info.blue_primary.x=(double) ReadBlobLSBLong(image)/BMP_DENOM;
717 bmp_info.blue_primary.y=(double) ReadBlobLSBLong(image)/BMP_DENOM;
718 bmp_info.blue_primary.z=(double) ReadBlobLSBLong(image)/BMP_DENOM;
719
glennrp44d4efc2012-11-22 03:50:51 +0000720 sum=bmp_info.red_primary.x+bmp_info.red_primary.y+
cristy3ed852e2009-09-05 21:47:34 +0000721 bmp_info.red_primary.z;
cristy4629d112012-11-22 02:25:54 +0000722 bmp_info.red_primary.x/=sum;
723 bmp_info.red_primary.y/=sum;
724 image->chromaticity.red_primary.x=bmp_info.red_primary.x;
725 image->chromaticity.red_primary.y=bmp_info.red_primary.y;
glennrp34ea3d32012-11-22 03:57:24 +0000726
glennrp44d4efc2012-11-22 03:50:51 +0000727 sum=bmp_info.green_primary.x+bmp_info.green_primary.y+
cristy3ed852e2009-09-05 21:47:34 +0000728 bmp_info.green_primary.z;
cristy4629d112012-11-22 02:25:54 +0000729 bmp_info.green_primary.x/=sum;
730 bmp_info.green_primary.y/=sum;
731 image->chromaticity.green_primary.x=bmp_info.green_primary.x;
732 image->chromaticity.green_primary.y=bmp_info.green_primary.y;
glennrp34ea3d32012-11-22 03:57:24 +0000733
glennrp44d4efc2012-11-22 03:50:51 +0000734 sum=bmp_info.blue_primary.x+bmp_info.blue_primary.y+
cristy3ed852e2009-09-05 21:47:34 +0000735 bmp_info.blue_primary.z;
cristy4629d112012-11-22 02:25:54 +0000736 bmp_info.blue_primary.x/=sum;
737 bmp_info.blue_primary.y/=sum;
738 image->chromaticity.blue_primary.x=bmp_info.blue_primary.x;
739 image->chromaticity.blue_primary.y=bmp_info.blue_primary.y;
glennrp34ea3d32012-11-22 03:57:24 +0000740
cristy3ed852e2009-09-05 21:47:34 +0000741 /*
742 Decode 16^16 fixed point formatted gamma_scales.
743 */
cristyc554cc82012-08-12 19:55:34 +0000744 bmp_info.gamma_scale.x=(double) ReadBlobLSBLong(image)/0x10000;
745 bmp_info.gamma_scale.y=(double) ReadBlobLSBLong(image)/0x10000;
746 bmp_info.gamma_scale.z=(double) ReadBlobLSBLong(image)/0x10000;
cristy3ed852e2009-09-05 21:47:34 +0000747 /*
748 Compute a single gamma from the BMP 3-channel gamma.
749 */
750 image->gamma=(bmp_info.gamma_scale.x+bmp_info.gamma_scale.y+
751 bmp_info.gamma_scale.z)/3.0;
752 }
dirk5816af42014-09-14 08:53:21 +0000753 else
754 (void) CopyMagickString(image->magick,"BMP3",MaxTextExtent);
glennrp34ea3d32012-11-22 03:57:24 +0000755
cristy3ed852e2009-09-05 21:47:34 +0000756 if (bmp_info.size > 108)
757 {
cristybb503372010-05-27 20:51:26 +0000758 size_t
cristy3ed852e2009-09-05 21:47:34 +0000759 intent;
760
761 /*
762 Read BMP Version 5 color management information.
763 */
764 intent=ReadBlobLSBLong(image);
765 switch ((int) intent)
766 {
767 case LCS_GM_BUSINESS:
768 {
769 image->rendering_intent=SaturationIntent;
770 break;
771 }
772 case LCS_GM_GRAPHICS:
773 {
774 image->rendering_intent=RelativeIntent;
775 break;
776 }
777 case LCS_GM_IMAGES:
778 {
779 image->rendering_intent=PerceptualIntent;
780 break;
781 }
782 case LCS_GM_ABS_COLORIMETRIC:
783 {
784 image->rendering_intent=AbsoluteIntent;
785 break;
786 }
787 }
788 profile_data=ReadBlobLSBLong(image);
789 profile_size=ReadBlobLSBLong(image);
cristyda16f162011-02-19 23:52:17 +0000790 (void) profile_data;
791 (void) profile_size;
cristy3ed852e2009-09-05 21:47:34 +0000792 (void) ReadBlobLSBLong(image); /* Reserved byte */
793 }
794 }
cristy59eefcf2011-02-01 15:54:38 +0000795 if ((MagickSizeType) bmp_info.file_size > GetBlobSize(image))
cristy3ed852e2009-09-05 21:47:34 +0000796 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
797 "LengthAndFilesizeDoNotMatch","`%s'",image->filename);
cristy59eefcf2011-02-01 15:54:38 +0000798 else
799 if ((MagickSizeType) bmp_info.file_size < GetBlobSize(image))
800 (void) ThrowMagickException(exception,GetMagickModule(),
801 CorruptImageWarning,"LengthAndFilesizeDoNotMatch","`%s'",
802 image->filename);
cristy3ed852e2009-09-05 21:47:34 +0000803 if (bmp_info.width <= 0)
804 ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize");
805 if (bmp_info.height == 0)
806 ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize");
807 if (bmp_info.planes != 1)
808 ThrowReaderException(CorruptImageError,"StaticPlanesValueNotEqualToOne");
809 if ((bmp_info.bits_per_pixel != 1) && (bmp_info.bits_per_pixel != 4) &&
810 (bmp_info.bits_per_pixel != 8) && (bmp_info.bits_per_pixel != 16) &&
811 (bmp_info.bits_per_pixel != 24) && (bmp_info.bits_per_pixel != 32))
812 ThrowReaderException(CorruptImageError,"UnrecognizedBitsPerPixel");
glennrpf5d7c9e2012-11-23 17:43:18 +0000813 if (bmp_info.bits_per_pixel < 16 &&
814 bmp_info.number_colors > (1U << bmp_info.bits_per_pixel))
cristyf8dcd772014-12-19 12:11:44 +0000815 ThrowReaderException(CorruptImageError,"UnrecognizedNumberOfColors");
cristy3ed852e2009-09-05 21:47:34 +0000816 if ((bmp_info.compression == 1) && (bmp_info.bits_per_pixel != 8))
817 ThrowReaderException(CorruptImageError,"UnrecognizedBitsPerPixel");
818 if ((bmp_info.compression == 2) && (bmp_info.bits_per_pixel != 4))
819 ThrowReaderException(CorruptImageError,"UnrecognizedBitsPerPixel");
820 if ((bmp_info.compression == 3) && (bmp_info.bits_per_pixel < 16))
821 ThrowReaderException(CorruptImageError,"UnrecognizedBitsPerPixel");
822 switch (bmp_info.compression)
823 {
824 case BI_RGB:
825 case BI_RLE8:
826 case BI_RLE4:
827 case BI_BITFIELDS:
828 break;
829 case BI_JPEG:
830 ThrowReaderException(CoderError,"JPEGCompressNotSupported");
831 case BI_PNG:
832 ThrowReaderException(CoderError,"PNGCompressNotSupported");
833 default:
834 ThrowReaderException(CorruptImageError,"UnrecognizedImageCompression");
835 }
cristy7c242ea2013-06-21 17:19:53 +0000836 image->columns=(size_t) MagickAbsoluteValue(bmp_info.width);
837 image->rows=(size_t) MagickAbsoluteValue(bmp_info.height);
cristy3ed852e2009-09-05 21:47:34 +0000838 image->depth=bmp_info.bits_per_pixel <= 8 ? bmp_info.bits_per_pixel : 8;
dirkc2dce492013-11-30 21:16:04 +0000839 image->alpha_trait=((bmp_info.alpha_mask != 0) &&
dirkf161fa42014-12-15 15:46:43 +0000840 (bmp_info.compression == BI_BITFIELDS)) ? BlendPixelTrait :
841 UndefinedPixelTrait;
glennrpf5d7c9e2012-11-23 17:43:18 +0000842 if (bmp_info.bits_per_pixel < 16)
cristy3ed852e2009-09-05 21:47:34 +0000843 {
cristy0b29b252010-05-30 01:59:46 +0000844 size_t
845 one;
846
cristy3ed852e2009-09-05 21:47:34 +0000847 image->storage_class=PseudoClass;
848 image->colors=bmp_info.number_colors;
cristy0b29b252010-05-30 01:59:46 +0000849 one=1;
cristy3ed852e2009-09-05 21:47:34 +0000850 if (image->colors == 0)
cristy0b29b252010-05-30 01:59:46 +0000851 image->colors=one << bmp_info.bits_per_pixel;
cristy3ed852e2009-09-05 21:47:34 +0000852 }
853 if (image->storage_class == PseudoClass)
854 {
855 unsigned char
856 *bmp_colormap;
857
858 size_t
859 packet_size;
860
861 /*
862 Read BMP raster colormap.
863 */
864 if (image->debug != MagickFalse)
865 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +0000866 " Reading colormap of %.20g colors",(double) image->colors);
cristy018f07f2011-09-04 21:15:19 +0000867 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000868 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
869 bmp_colormap=(unsigned char *) AcquireQuantumMemory((size_t)
870 image->colors,4*sizeof(*bmp_colormap));
871 if (bmp_colormap == (unsigned char *) NULL)
872 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
873 if ((bmp_info.size == 12) || (bmp_info.size == 64))
874 packet_size=3;
875 else
876 packet_size=4;
877 offset=SeekBlob(image,start_position+14+bmp_info.size,SEEK_SET);
878 if (offset < 0)
879 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
880 count=ReadBlob(image,packet_size*image->colors,bmp_colormap);
881 if (count != (ssize_t) (packet_size*image->colors))
882 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
883 p=bmp_colormap;
cristybb503372010-05-27 20:51:26 +0000884 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +0000885 {
cristya321eb72013-06-23 10:42:37 +0000886 image->colormap[i].blue=(MagickRealType) ScaleCharToQuantum(*p++);
887 image->colormap[i].green=(MagickRealType) ScaleCharToQuantum(*p++);
888 image->colormap[i].red=(MagickRealType) ScaleCharToQuantum(*p++);
cristy3ed852e2009-09-05 21:47:34 +0000889 if (packet_size == 4)
890 p++;
891 }
892 bmp_colormap=(unsigned char *) RelinquishMagickMemory(bmp_colormap);
893 }
cristy47b81c22012-03-29 14:19:09 +0000894 image->resolution.x=(double) bmp_info.x_pixels/100.0;
895 image->resolution.y=(double) bmp_info.y_pixels/100.0;
896 image->units=PixelsPerCentimeterResolution;
cristy3ed852e2009-09-05 21:47:34 +0000897 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
898 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
899 break;
cristyacabb842014-12-14 23:36:33 +0000900 status=SetImageExtent(image,image->columns,image->rows,exception);
901 if (status == MagickFalse)
902 return(DestroyImageList(image));
cristy3ed852e2009-09-05 21:47:34 +0000903 /*
904 Read image data.
905 */
cristycd20c152012-04-09 18:57:54 +0000906 offset=SeekBlob(image,start_position+bmp_info.offset_bits,SEEK_SET);
907 if (offset < 0)
908 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
cristy3ed852e2009-09-05 21:47:34 +0000909 if (bmp_info.compression == BI_RLE4)
910 bmp_info.bits_per_pixel<<=1;
911 bytes_per_line=4*((image->columns*bmp_info.bits_per_pixel+31)/32);
912 length=(size_t) bytes_per_line*image->rows;
cristy0553bd52013-06-30 15:53:50 +0000913 pixel_info=AcquireVirtualMemory((size_t) image->rows,
cristy7c242ea2013-06-21 17:19:53 +0000914 MagickMax(bytes_per_line,image->columns+256UL)*sizeof(*pixels));
cristy0553bd52013-06-30 15:53:50 +0000915 if (pixel_info == (MemoryInfo *) NULL)
cristy7c242ea2013-06-21 17:19:53 +0000916 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
cristy0553bd52013-06-30 15:53:50 +0000917 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +0000918 if ((bmp_info.compression == BI_RGB) ||
919 (bmp_info.compression == BI_BITFIELDS))
920 {
921 if (image->debug != MagickFalse)
922 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +0000923 " Reading pixels (%.20g bytes)",(double) length);
cristy7c242ea2013-06-21 17:19:53 +0000924 count=ReadBlob(image,length,pixels);
925 if (count != (ssize_t) length)
cristyde60ea72010-07-09 23:12:09 +0000926 {
cristy0553bd52013-06-30 15:53:50 +0000927 pixel_info=RelinquishVirtualMemory(pixel_info);
cristy7c242ea2013-06-21 17:19:53 +0000928 ThrowReaderException(CorruptImageError,
929 "InsufficientImageDataInFile");
cristyde60ea72010-07-09 23:12:09 +0000930 }
cristy3ed852e2009-09-05 21:47:34 +0000931 }
932 else
933 {
934 /*
935 Convert run-length encoded raster pixels.
936 */
937 status=DecodeImage(image,bmp_info.compression,pixels);
938 if (status == MagickFalse)
cristyde60ea72010-07-09 23:12:09 +0000939 {
cristy0553bd52013-06-30 15:53:50 +0000940 pixel_info=RelinquishVirtualMemory(pixel_info);
cristyde60ea72010-07-09 23:12:09 +0000941 ThrowReaderException(CorruptImageError,
942 "UnableToRunlengthDecodeImage");
943 }
cristy3ed852e2009-09-05 21:47:34 +0000944 }
945 /*
cristy3ed852e2009-09-05 21:47:34 +0000946 Convert BMP raster image to pixel packets.
947 */
948 if (bmp_info.compression == BI_RGB)
949 {
dirkf161fa42014-12-15 15:46:43 +0000950 /*
951 We should ignore the alpha value in BMP3 files but there have been
952 reports about 32 bit files with alpha. We do a quick check to see if
953 the alpha channel contains a value that is not zero (default value).
954 If we find a non zero value we asume the program that wrote the file
955 wants to use the alpha channel.
956 */
cristy17f11b02014-12-20 19:37:04 +0000957 if ((image->alpha_trait == UndefinedPixelTrait) && (bmp_info.size == 40) &&
dirkf161fa42014-12-15 15:46:43 +0000958 (bmp_info.bits_per_pixel == 32))
959 {
960 bytes_per_line=4*(image->columns);
961 for (y=(ssize_t) image->rows-1; y >= 0; y--)
962 {
963 p=pixels+(image->rows-y-1)*bytes_per_line;
964 for (x=0; x < (ssize_t) image->columns; x++)
965 {
966 if (*(p+3) != 0)
967 {
968 image->alpha_trait=BlendPixelTrait;
969 y=-1;
970 break;
971 }
972 p+=4;
973 }
974 }
975 }
cristy17f11b02014-12-20 19:37:04 +0000976 bmp_info.alpha_mask=image->alpha_trait != UndefinedPixelTrait ?
cristya321eb72013-06-23 10:42:37 +0000977 0xff000000U : 0U;
cristy3ed852e2009-09-05 21:47:34 +0000978 bmp_info.red_mask=0x00ff0000U;
979 bmp_info.green_mask=0x0000ff00U;
980 bmp_info.blue_mask=0x000000ffU;
981 if (bmp_info.bits_per_pixel == 16)
982 {
983 /*
984 RGB555.
985 */
986 bmp_info.red_mask=0x00007c00U;
987 bmp_info.green_mask=0x000003e0U;
988 bmp_info.blue_mask=0x0000001fU;
989 }
990 }
cristy58d4fe12015-02-07 11:53:05 +0000991 (void) ResetMagickMemory(&shift,0,sizeof(shift));
992 (void) ResetMagickMemory(&quantum_bits,0,sizeof(quantum_bits));
cristy3ed852e2009-09-05 21:47:34 +0000993 if ((bmp_info.bits_per_pixel == 16) || (bmp_info.bits_per_pixel == 32))
994 {
cristybb503372010-05-27 20:51:26 +0000995 register size_t
cristy3ed852e2009-09-05 21:47:34 +0000996 sample;
997
998 /*
999 Get shift and quantum bits info from bitfield masks.
1000 */
cristy3ed852e2009-09-05 21:47:34 +00001001 if (bmp_info.red_mask != 0)
1002 while (((bmp_info.red_mask << shift.red) & 0x80000000UL) == 0)
1003 shift.red++;
1004 if (bmp_info.green_mask != 0)
1005 while (((bmp_info.green_mask << shift.green) & 0x80000000UL) == 0)
1006 shift.green++;
1007 if (bmp_info.blue_mask != 0)
1008 while (((bmp_info.blue_mask << shift.blue) & 0x80000000UL) == 0)
1009 shift.blue++;
1010 if (bmp_info.alpha_mask != 0)
cristy4c08aed2011-07-01 19:47:50 +00001011 while (((bmp_info.alpha_mask << shift.alpha) & 0x80000000UL) == 0)
1012 shift.alpha++;
cristy3ed852e2009-09-05 21:47:34 +00001013 sample=shift.red;
1014 while (((bmp_info.red_mask << sample) & 0x80000000UL) != 0)
1015 sample++;
cristya321eb72013-06-23 10:42:37 +00001016 quantum_bits.red=(MagickRealType) (sample-shift.red);
cristy3ed852e2009-09-05 21:47:34 +00001017 sample=shift.green;
1018 while (((bmp_info.green_mask << sample) & 0x80000000UL) != 0)
1019 sample++;
cristya321eb72013-06-23 10:42:37 +00001020 quantum_bits.green=(MagickRealType) (sample-shift.green);
cristy3ed852e2009-09-05 21:47:34 +00001021 sample=shift.blue;
1022 while (((bmp_info.blue_mask << sample) & 0x80000000UL) != 0)
1023 sample++;
cristya321eb72013-06-23 10:42:37 +00001024 quantum_bits.blue=(MagickRealType) (sample-shift.blue);
cristy4c08aed2011-07-01 19:47:50 +00001025 sample=shift.alpha;
cristy3ed852e2009-09-05 21:47:34 +00001026 while (((bmp_info.alpha_mask << sample) & 0x80000000UL) != 0)
1027 sample++;
cristya321eb72013-06-23 10:42:37 +00001028 quantum_bits.alpha=(MagickRealType) (sample-shift.alpha);
cristy3ed852e2009-09-05 21:47:34 +00001029 }
1030 switch (bmp_info.bits_per_pixel)
1031 {
1032 case 1:
1033 {
1034 /*
1035 Convert bitmap scanline.
1036 */
cristybb503372010-05-27 20:51:26 +00001037 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +00001038 {
1039 p=pixels+(image->rows-y-1)*bytes_per_line;
1040 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +00001041 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001042 break;
cristybb503372010-05-27 20:51:26 +00001043 for (x=0; x < ((ssize_t) image->columns-7); x+=8)
cristy3ed852e2009-09-05 21:47:34 +00001044 {
1045 for (bit=0; bit < 8; bit++)
1046 {
cristy4c08aed2011-07-01 19:47:50 +00001047 index=(Quantum) (((*p) & (0x80 >> bit)) != 0 ? 0x01 : 0x00);
1048 SetPixelIndex(image,index,q);
cristyed231572011-07-14 02:18:59 +00001049 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001050 }
1051 p++;
1052 }
1053 if ((image->columns % 8) != 0)
1054 {
1055 for (bit=0; bit < (image->columns % 8); bit++)
1056 {
cristy4c08aed2011-07-01 19:47:50 +00001057 index=(Quantum) (((*p) & (0x80 >> bit)) != 0 ? 0x01 : 0x00);
1058 SetPixelIndex(image,index,q);
cristyed231572011-07-14 02:18:59 +00001059 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001060 }
1061 p++;
1062 }
1063 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1064 break;
1065 if (image->previous == (Image *) NULL)
1066 {
cristy8314a302014-12-08 16:05:32 +00001067 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
1068 (image->rows-y),image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001069 if (status == MagickFalse)
1070 break;
1071 }
1072 }
cristyea1a8aa2011-10-20 13:24:06 +00001073 (void) SyncImage(image,exception);
cristy3ed852e2009-09-05 21:47:34 +00001074 break;
1075 }
1076 case 4:
1077 {
1078 /*
1079 Convert PseudoColor scanline.
1080 */
cristybb503372010-05-27 20:51:26 +00001081 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +00001082 {
1083 p=pixels+(image->rows-y-1)*bytes_per_line;
1084 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +00001085 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001086 break;
cristybb503372010-05-27 20:51:26 +00001087 for (x=0; x < ((ssize_t) image->columns-1); x+=2)
cristy3ed852e2009-09-05 21:47:34 +00001088 {
dirkfcef1752014-12-29 21:43:36 +00001089 if (IsValidColormapIndex(image,(*p >> 4) & 0x0f,&index,exception)
1090 == MagickFalse)
1091 break;
cristy4c08aed2011-07-01 19:47:50 +00001092 SetPixelIndex(image,index,q);
cristyed231572011-07-14 02:18:59 +00001093 q+=GetPixelChannels(image);
dirkfcef1752014-12-29 21:43:36 +00001094 if (IsValidColormapIndex(image,*p & 0x0f,&index,exception) ==
1095 MagickFalse)
1096 break;
cristy4c08aed2011-07-01 19:47:50 +00001097 SetPixelIndex(image,index,q);
cristyed231572011-07-14 02:18:59 +00001098 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001099 p++;
1100 }
1101 if ((image->columns % 2) != 0)
1102 {
dirkfcef1752014-12-29 21:43:36 +00001103 if (IsValidColormapIndex(image,(*p >> 4) & 0xf,&index,exception)
1104 == MagickFalse)
1105 break;
cristy4c08aed2011-07-01 19:47:50 +00001106 SetPixelIndex(image,index,q);
cristyed231572011-07-14 02:18:59 +00001107 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001108 p++;
1109 }
dirkfcef1752014-12-29 21:43:36 +00001110 if (x < image->columns)
1111 break;
cristy3ed852e2009-09-05 21:47:34 +00001112 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1113 break;
1114 if (image->previous == (Image *) NULL)
1115 {
cristy8314a302014-12-08 16:05:32 +00001116 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
1117 (image->rows-y),image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001118 if (status == MagickFalse)
1119 break;
1120 }
1121 }
cristyea1a8aa2011-10-20 13:24:06 +00001122 (void) SyncImage(image,exception);
cristy3ed852e2009-09-05 21:47:34 +00001123 break;
1124 }
1125 case 8:
1126 {
1127 /*
1128 Convert PseudoColor scanline.
1129 */
1130 if ((bmp_info.compression == BI_RLE8) ||
1131 (bmp_info.compression == BI_RLE4))
1132 bytes_per_line=image->columns;
cristybb503372010-05-27 20:51:26 +00001133 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +00001134 {
1135 p=pixels+(image->rows-y-1)*bytes_per_line;
1136 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +00001137 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001138 break;
cristycaf45802012-06-16 18:28:54 +00001139 for (x=(ssize_t) image->columns; x != 0; --x)
cristy3ed852e2009-09-05 21:47:34 +00001140 {
dirkfcef1752014-12-29 21:43:36 +00001141 if (IsValidColormapIndex(image,*p++,&index,exception) ==
1142 MagickFalse)
1143 break;
cristy4c08aed2011-07-01 19:47:50 +00001144 SetPixelIndex(image,index,q);
cristyed231572011-07-14 02:18:59 +00001145 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001146 }
dirkfcef1752014-12-29 21:43:36 +00001147 if (x > 0)
1148 break;
cristy3ed852e2009-09-05 21:47:34 +00001149 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1150 break;
1151 offset=(MagickOffsetType) (image->rows-y-1);
1152 if (image->previous == (Image *) NULL)
1153 {
cristy8314a302014-12-08 16:05:32 +00001154 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
1155 (image->rows-y),image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001156 if (status == MagickFalse)
1157 break;
1158 }
1159 }
cristyea1a8aa2011-10-20 13:24:06 +00001160 (void) SyncImage(image,exception);
cristy3ed852e2009-09-05 21:47:34 +00001161 break;
1162 }
1163 case 16:
1164 {
cristybb503372010-05-27 20:51:26 +00001165 size_t
cristy3e03ba72014-12-09 12:19:30 +00001166 alpha,
cristy3ed852e2009-09-05 21:47:34 +00001167 pixel;
1168
1169 /*
1170 Convert bitfield encoded 16-bit PseudoColor scanline.
1171 */
1172 if (bmp_info.compression != BI_RGB &&
1173 bmp_info.compression != BI_BITFIELDS)
cristyde60ea72010-07-09 23:12:09 +00001174 {
cristy0553bd52013-06-30 15:53:50 +00001175 pixel_info=RelinquishVirtualMemory(pixel_info);
cristyde60ea72010-07-09 23:12:09 +00001176 ThrowReaderException(CorruptImageError,
1177 "UnrecognizedImageCompression");
1178 }
cristy3ed852e2009-09-05 21:47:34 +00001179 bytes_per_line=2*(image->columns+image->columns % 2);
1180 image->storage_class=DirectClass;
cristybb503372010-05-27 20:51:26 +00001181 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +00001182 {
1183 p=pixels+(image->rows-y-1)*bytes_per_line;
1184 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +00001185 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001186 break;
cristybb503372010-05-27 20:51:26 +00001187 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001188 {
cristybb503372010-05-27 20:51:26 +00001189 pixel=(size_t) (*p++);
cristy3ed852e2009-09-05 21:47:34 +00001190 pixel|=(*p++) << 8;
1191 red=((pixel & bmp_info.red_mask) << shift.red) >> 16;
1192 if (quantum_bits.red == 5)
1193 red|=((red & 0xe000) >> 5);
1194 if (quantum_bits.red <= 8)
1195 red|=((red & 0xff00) >> 8);
1196 green=((pixel & bmp_info.green_mask) << shift.green) >> 16;
1197 if (quantum_bits.green == 5)
1198 green|=((green & 0xe000) >> 5);
1199 if (quantum_bits.green == 6)
1200 green|=((green & 0xc000) >> 6);
1201 if (quantum_bits.green <= 8)
1202 green|=((green & 0xff00) >> 8);
1203 blue=((pixel & bmp_info.blue_mask) << shift.blue) >> 16;
1204 if (quantum_bits.blue == 5)
1205 blue|=((blue & 0xe000) >> 5);
1206 if (quantum_bits.blue <= 8)
1207 blue|=((blue & 0xff00) >> 8);
cristy4c08aed2011-07-01 19:47:50 +00001208 SetPixelRed(image,ScaleShortToQuantum((unsigned short) red),q);
1209 SetPixelGreen(image,ScaleShortToQuantum((unsigned short) green),q);
1210 SetPixelBlue(image,ScaleShortToQuantum((unsigned short) blue),q);
1211 SetPixelAlpha(image,OpaqueAlpha,q);
cristy17f11b02014-12-20 19:37:04 +00001212 if (image->alpha_trait != UndefinedPixelTrait)
dirkf161fa42014-12-15 15:46:43 +00001213 {
1214 alpha=((pixel & bmp_info.alpha_mask) << shift.alpha) >> 16;
1215 if (quantum_bits.alpha <= 8)
1216 alpha|=((alpha & 0xff00) >> 8);
1217 SetPixelAlpha(image,ScaleShortToQuantum(
1218 (unsigned short) alpha),q);
1219 }
cristyed231572011-07-14 02:18:59 +00001220 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001221 }
1222 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1223 break;
1224 offset=(MagickOffsetType) (image->rows-y-1);
1225 if (image->previous == (Image *) NULL)
1226 {
cristy8314a302014-12-08 16:05:32 +00001227 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
1228 (image->rows-y),image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001229 if (status == MagickFalse)
1230 break;
1231 }
1232 }
1233 break;
1234 }
1235 case 24:
1236 {
1237 /*
1238 Convert DirectColor scanline.
1239 */
1240 bytes_per_line=4*((image->columns*24+31)/32);
cristybb503372010-05-27 20:51:26 +00001241 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +00001242 {
1243 p=pixels+(image->rows-y-1)*bytes_per_line;
1244 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +00001245 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001246 break;
cristybb503372010-05-27 20:51:26 +00001247 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001248 {
cristy4c08aed2011-07-01 19:47:50 +00001249 SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
1250 SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
1251 SetPixelRed(image,ScaleCharToQuantum(*p++),q);
1252 SetPixelAlpha(image,OpaqueAlpha,q);
cristyed231572011-07-14 02:18:59 +00001253 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001254 }
1255 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1256 break;
1257 offset=(MagickOffsetType) (image->rows-y-1);
1258 if (image->previous == (Image *) NULL)
1259 {
cristy8314a302014-12-08 16:05:32 +00001260 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
1261 (image->rows-y),image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001262 if (status == MagickFalse)
1263 break;
1264 }
1265 }
1266 break;
1267 }
1268 case 32:
1269 {
1270 /*
1271 Convert bitfield encoded DirectColor scanline.
1272 */
1273 if ((bmp_info.compression != BI_RGB) &&
1274 (bmp_info.compression != BI_BITFIELDS))
cristyde60ea72010-07-09 23:12:09 +00001275 {
cristy0553bd52013-06-30 15:53:50 +00001276 pixel_info=RelinquishVirtualMemory(pixel_info);
cristyde60ea72010-07-09 23:12:09 +00001277 ThrowReaderException(CorruptImageError,
1278 "UnrecognizedImageCompression");
1279 }
cristy3ed852e2009-09-05 21:47:34 +00001280 bytes_per_line=4*(image->columns);
cristybb503372010-05-27 20:51:26 +00001281 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +00001282 {
cristybb503372010-05-27 20:51:26 +00001283 size_t
cristy3e03ba72014-12-09 12:19:30 +00001284 alpha,
cristy3ed852e2009-09-05 21:47:34 +00001285 pixel;
1286
1287 p=pixels+(image->rows-y-1)*bytes_per_line;
1288 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +00001289 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001290 break;
cristybb503372010-05-27 20:51:26 +00001291 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001292 {
cristybb503372010-05-27 20:51:26 +00001293 pixel=(size_t) (*p++);
cristyfa6de8c2014-05-18 16:34:44 +00001294 pixel|=((size_t) *p++ << 8);
1295 pixel|=((size_t) *p++ << 16);
1296 pixel|=((size_t) *p++ << 24);
cristy3ed852e2009-09-05 21:47:34 +00001297 red=((pixel & bmp_info.red_mask) << shift.red) >> 16;
1298 if (quantum_bits.red == 8)
1299 red|=(red >> 8);
1300 green=((pixel & bmp_info.green_mask) << shift.green) >> 16;
1301 if (quantum_bits.green == 8)
1302 green|=(green >> 8);
1303 blue=((pixel & bmp_info.blue_mask) << shift.blue) >> 16;
1304 if (quantum_bits.blue == 8)
1305 blue|=(blue >> 8);
cristy4c08aed2011-07-01 19:47:50 +00001306 SetPixelRed(image,ScaleShortToQuantum((unsigned short) red),q);
1307 SetPixelGreen(image,ScaleShortToQuantum((unsigned short) green),q);
1308 SetPixelBlue(image,ScaleShortToQuantum((unsigned short) blue),q);
dirk271dce62014-12-14 20:28:38 +00001309 SetPixelAlpha(image,OpaqueAlpha,q);
cristy17f11b02014-12-20 19:37:04 +00001310 if (image->alpha_trait != UndefinedPixelTrait)
dirkf161fa42014-12-15 15:46:43 +00001311 {
1312 alpha=((pixel & bmp_info.alpha_mask) << shift.alpha) >> 16;
1313 if (quantum_bits.alpha == 8)
1314 alpha|=(alpha >> 8);
1315 SetPixelAlpha(image,ScaleShortToQuantum(
1316 (unsigned short) alpha),q);
1317 }
cristyed231572011-07-14 02:18:59 +00001318 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001319 }
1320 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1321 break;
1322 offset=(MagickOffsetType) (image->rows-y-1);
1323 if (image->previous == (Image *) NULL)
1324 {
cristy8314a302014-12-08 16:05:32 +00001325 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
1326 (image->rows-y),image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001327 if (status == MagickFalse)
1328 break;
1329 }
1330 }
1331 break;
1332 }
1333 default:
cristyde60ea72010-07-09 23:12:09 +00001334 {
cristy0553bd52013-06-30 15:53:50 +00001335 pixel_info=RelinquishVirtualMemory(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +00001336 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
cristyde60ea72010-07-09 23:12:09 +00001337 }
cristy3ed852e2009-09-05 21:47:34 +00001338 }
cristy0553bd52013-06-30 15:53:50 +00001339 pixel_info=RelinquishVirtualMemory(pixel_info);
dirkfcef1752014-12-29 21:43:36 +00001340 if (y > 0)
1341 break;
cristy3ed852e2009-09-05 21:47:34 +00001342 if (EOFBlob(image) != MagickFalse)
1343 {
1344 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
1345 image->filename);
1346 break;
1347 }
1348 if (bmp_info.height < 0)
1349 {
1350 Image
1351 *flipped_image;
1352
1353 /*
1354 Correct image orientation.
1355 */
1356 flipped_image=FlipImage(image,exception);
cristy65e3b002010-04-13 21:20:56 +00001357 if (flipped_image != (Image *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001358 {
cristy65e3b002010-04-13 21:20:56 +00001359 DuplicateBlob(flipped_image,image);
1360 image=DestroyImage(image);
1361 image=flipped_image;
cristy3ed852e2009-09-05 21:47:34 +00001362 }
cristy3ed852e2009-09-05 21:47:34 +00001363 }
1364 /*
1365 Proceed to next image.
1366 */
1367 if (image_info->number_scenes != 0)
1368 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1369 break;
1370 *magick='\0';
1371 if (bmp_info.ba_offset != 0)
1372 {
1373 offset=SeekBlob(image,(MagickOffsetType) bmp_info.ba_offset,SEEK_SET);
1374 if (offset < 0)
1375 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1376 }
1377 count=ReadBlob(image,2,magick);
1378 if ((count == 2) && (IsBMP(magick,2) != MagickFalse))
1379 {
1380 /*
1381 Acquire next image structure.
1382 */
cristy9950d572011-10-01 18:22:35 +00001383 AcquireNextImage(image_info,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00001384 if (GetNextImageInList(image) == (Image *) NULL)
1385 {
1386 image=DestroyImageList(image);
1387 return((Image *) NULL);
1388 }
1389 image=SyncNextImageInList(image);
1390 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
1391 GetBlobSize(image));
1392 if (status == MagickFalse)
1393 break;
1394 }
1395 } while (IsBMP(magick,2) != MagickFalse);
1396 (void) CloseBlob(image);
1397 return(GetFirstImageInList(image));
1398}
1399
1400/*
1401%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1402% %
1403% %
1404% %
1405% R e g i s t e r B M P I m a g e %
1406% %
1407% %
1408% %
1409%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1410%
1411% RegisterBMPImage() adds attributes for the BMP image format to
1412% the list of supported formats. The attributes include the image format
1413% tag, a method to read and/or write the format, whether the format
1414% supports the saving of more than one frame to the same file or blob,
1415% whether the format supports native in-memory I/O, and a brief
1416% description of the format.
1417%
1418% The format of the RegisterBMPImage method is:
1419%
cristybb503372010-05-27 20:51:26 +00001420% size_t RegisterBMPImage(void)
cristy3ed852e2009-09-05 21:47:34 +00001421%
1422*/
cristybb503372010-05-27 20:51:26 +00001423ModuleExport size_t RegisterBMPImage(void)
cristy3ed852e2009-09-05 21:47:34 +00001424{
1425 MagickInfo
1426 *entry;
1427
1428 entry=SetMagickInfo("BMP");
1429 entry->decoder=(DecodeImageHandler *) ReadBMPImage;
1430 entry->encoder=(EncodeImageHandler *) WriteBMPImage;
1431 entry->magick=(IsImageFormatHandler *) IsBMP;
cristy2e3d5242010-04-16 23:44:55 +00001432 entry->description=ConstantString("Microsoft Windows bitmap image");
cristy3ed852e2009-09-05 21:47:34 +00001433 entry->module=ConstantString("BMP");
1434 entry->adjoin=MagickFalse;
1435 entry->seekable_stream=MagickTrue;
1436 (void) RegisterMagickInfo(entry);
1437 entry=SetMagickInfo("BMP2");
1438 entry->encoder=(EncodeImageHandler *) WriteBMPImage;
1439 entry->magick=(IsImageFormatHandler *) IsBMP;
cristy2dd92ae2010-04-04 16:10:59 +00001440 entry->description=ConstantString("Microsoft Windows bitmap image (V2)");
cristy3ed852e2009-09-05 21:47:34 +00001441 entry->module=ConstantString("BMP");
1442 entry->adjoin=MagickFalse;
1443 entry->seekable_stream=MagickTrue;
1444 (void) RegisterMagickInfo(entry);
1445 entry=SetMagickInfo("BMP3");
1446 entry->encoder=(EncodeImageHandler *) WriteBMPImage;
1447 entry->magick=(IsImageFormatHandler *) IsBMP;
cristy2dd92ae2010-04-04 16:10:59 +00001448 entry->description=ConstantString("Microsoft Windows bitmap image (V3)");
cristy3ed852e2009-09-05 21:47:34 +00001449 entry->module=ConstantString("BMP");
1450 entry->adjoin=MagickFalse;
1451 entry->seekable_stream=MagickTrue;
1452 (void) RegisterMagickInfo(entry);
1453 return(MagickImageCoderSignature);
1454}
1455
1456/*
1457%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1458% %
1459% %
1460% %
1461% U n r e g i s t e r B M P I m a g e %
1462% %
1463% %
1464% %
1465%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1466%
1467% UnregisterBMPImage() removes format registrations made by the
1468% BMP module from the list of supported formats.
1469%
1470% The format of the UnregisterBMPImage method is:
1471%
1472% UnregisterBMPImage(void)
1473%
1474*/
1475ModuleExport void UnregisterBMPImage(void)
1476{
1477 (void) UnregisterMagickInfo("BMP");
1478 (void) UnregisterMagickInfo("BMP2");
1479 (void) UnregisterMagickInfo("BMP3");
1480}
1481
1482/*
1483%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1484% %
1485% %
1486% %
1487% W r i t e B M P I m a g e %
1488% %
1489% %
1490% %
1491%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1492%
1493% WriteBMPImage() writes an image in Microsoft Windows bitmap encoded
1494% image format, version 3 for Windows or (if the image has a matte channel)
1495% version 4.
1496%
1497% The format of the WriteBMPImage method is:
1498%
cristy1e178e72011-08-28 19:44:34 +00001499% MagickBooleanType WriteBMPImage(const ImageInfo *image_info,
1500% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001501%
1502% A description of each parameter follows.
1503%
1504% o image_info: the image info.
1505%
1506% o image: The image.
1507%
cristy1e178e72011-08-28 19:44:34 +00001508% o exception: return any errors or warnings in this structure.
1509%
cristy3ed852e2009-09-05 21:47:34 +00001510*/
cristy1e178e72011-08-28 19:44:34 +00001511static MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image,
1512 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001513{
1514 BMPInfo
1515 bmp_info;
glennrpd0a3f8b2013-08-10 16:11:30 +00001516 const char
1517 *value;
1518
cristy3ed852e2009-09-05 21:47:34 +00001519
1520 const StringInfo
1521 *profile;
1522
cristy3ed852e2009-09-05 21:47:34 +00001523 MagickBooleanType
1524 have_color_info,
1525 status;
1526
1527 MagickOffsetType
1528 scene;
1529
cristya321eb72013-06-23 10:42:37 +00001530 MemoryInfo
cristy0553bd52013-06-30 15:53:50 +00001531 *pixel_info;
cristya321eb72013-06-23 10:42:37 +00001532
cristy4c08aed2011-07-01 19:47:50 +00001533 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +00001534 *p;
1535
cristybb503372010-05-27 20:51:26 +00001536 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001537 i,
1538 x;
1539
1540 register unsigned char
1541 *q;
1542
cristybb503372010-05-27 20:51:26 +00001543 size_t
cristy3ed852e2009-09-05 21:47:34 +00001544 bytes_per_line,
1545 type;
1546
cristy4e82e512011-04-24 01:33:42 +00001547 ssize_t
1548 y;
1549
1550 unsigned char
1551 *bmp_data,
1552 *pixels;
1553
cristy3ed852e2009-09-05 21:47:34 +00001554 /*
1555 Open output image file.
1556 */
1557 assert(image_info != (const ImageInfo *) NULL);
1558 assert(image_info->signature == MagickSignature);
1559 assert(image != (Image *) NULL);
1560 assert(image->signature == MagickSignature);
1561 if (image->debug != MagickFalse)
1562 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy3a37efd2011-08-28 20:31:03 +00001563 assert(exception != (ExceptionInfo *) NULL);
1564 assert(exception->signature == MagickSignature);
cristy1e178e72011-08-28 19:44:34 +00001565 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00001566 if (status == MagickFalse)
1567 return(status);
1568 type=4;
1569 if (LocaleCompare(image_info->magick,"BMP2") == 0)
1570 type=2;
1571 else
1572 if (LocaleCompare(image_info->magick,"BMP3") == 0)
1573 type=3;
glennrpd0a3f8b2013-08-10 16:11:30 +00001574
1575 value=GetImageOption(image_info,"bmp:format");
1576
1577 if (value != (char *) NULL)
1578 {
1579 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1580 " Format=%s",value);
1581
1582 if (LocaleCompare(value,"bmp2") == 0)
1583 type=2;
1584 if (LocaleCompare(value,"bmp3") == 0)
1585 type=3;
1586 if (LocaleCompare(value,"bmp4") == 0)
1587 type=4;
1588 }
1589
cristy3ed852e2009-09-05 21:47:34 +00001590 scene=0;
1591 do
1592 {
1593 /*
1594 Initialize BMP raster file header.
1595 */
cristyaf8d3912014-02-21 14:50:33 +00001596 (void) TransformImageColorspace(image,sRGBColorspace,exception);
cristy3ed852e2009-09-05 21:47:34 +00001597 (void) ResetMagickMemory(&bmp_info,0,sizeof(bmp_info));
1598 bmp_info.file_size=14+12;
1599 if (type > 2)
1600 bmp_info.file_size+=28;
1601 bmp_info.offset_bits=bmp_info.file_size;
1602 bmp_info.compression=BI_RGB;
1603 if ((image->storage_class == PseudoClass) && (image->colors > 256))
cristy1e178e72011-08-28 19:44:34 +00001604 (void) SetImageStorageClass(image,DirectClass,exception);
cristy3ed852e2009-09-05 21:47:34 +00001605 if (image->storage_class != DirectClass)
1606 {
1607 /*
1608 Colormapped BMP raster.
1609 */
1610 bmp_info.bits_per_pixel=8;
1611 if (image->colors <= 2)
1612 bmp_info.bits_per_pixel=1;
1613 else
1614 if (image->colors <= 16)
1615 bmp_info.bits_per_pixel=4;
1616 else
1617 if (image->colors <= 256)
1618 bmp_info.bits_per_pixel=8;
1619 if (image_info->compression == RLECompression)
1620 bmp_info.bits_per_pixel=8;
1621 bmp_info.number_colors=1U << bmp_info.bits_per_pixel;
cristy17f11b02014-12-20 19:37:04 +00001622 if (image->alpha_trait != UndefinedPixelTrait)
cristy1e178e72011-08-28 19:44:34 +00001623 (void) SetImageStorageClass(image,DirectClass,exception);
cristy3ed852e2009-09-05 21:47:34 +00001624 else
cristybb503372010-05-27 20:51:26 +00001625 if ((size_t) bmp_info.number_colors < image->colors)
cristy1e178e72011-08-28 19:44:34 +00001626 (void) SetImageStorageClass(image,DirectClass,exception);
cristy3ed852e2009-09-05 21:47:34 +00001627 else
1628 {
1629 bmp_info.file_size+=3*(1UL << bmp_info.bits_per_pixel);
1630 bmp_info.offset_bits+=3*(1UL << bmp_info.bits_per_pixel);
1631 if (type > 2)
1632 {
1633 bmp_info.file_size+=(1UL << bmp_info.bits_per_pixel);
1634 bmp_info.offset_bits+=(1UL << bmp_info.bits_per_pixel);
1635 }
1636 }
1637 }
1638 if (image->storage_class == DirectClass)
1639 {
1640 /*
1641 Full color BMP raster.
1642 */
1643 bmp_info.number_colors=0;
1644 bmp_info.bits_per_pixel=(unsigned short)
cristy17f11b02014-12-20 19:37:04 +00001645 ((type > 3) && (image->alpha_trait != UndefinedPixelTrait) ? 32 : 24);
cristy3ed852e2009-09-05 21:47:34 +00001646 bmp_info.compression=(unsigned int) ((type > 3) &&
cristy17f11b02014-12-20 19:37:04 +00001647 (image->alpha_trait != UndefinedPixelTrait) ? BI_BITFIELDS : BI_RGB);
cristy3ed852e2009-09-05 21:47:34 +00001648 }
1649 bytes_per_line=4*((image->columns*bmp_info.bits_per_pixel+31)/32);
1650 bmp_info.ba_offset=0;
1651 profile=GetImageProfile(image,"icc");
1652 have_color_info=(image->rendering_intent != UndefinedIntent) ||
1653 (profile != (StringInfo *) NULL) || (image->gamma != 0.0) ? MagickTrue :
1654 MagickFalse;
1655 if (type == 2)
1656 bmp_info.size=12;
1657 else
cristy17f11b02014-12-20 19:37:04 +00001658 if ((type == 3) || ((image->alpha_trait == UndefinedPixelTrait) &&
cristy3ed852e2009-09-05 21:47:34 +00001659 (have_color_info == MagickFalse)))
1660 {
1661 type=3;
1662 bmp_info.size=40;
1663 }
1664 else
1665 {
1666 int
1667 extra_size;
1668
1669 bmp_info.size=108;
1670 extra_size=68;
1671 if ((image->rendering_intent != UndefinedIntent) ||
1672 (profile != (StringInfo *) NULL))
1673 {
1674 bmp_info.size=124;
1675 extra_size+=16;
1676 }
1677 bmp_info.file_size+=extra_size;
1678 bmp_info.offset_bits+=extra_size;
1679 }
cristy7c242ea2013-06-21 17:19:53 +00001680 bmp_info.width=(ssize_t) image->columns;
1681 bmp_info.height=(ssize_t) image->rows;
cristy3ed852e2009-09-05 21:47:34 +00001682 bmp_info.planes=1;
1683 bmp_info.image_size=(unsigned int) (bytes_per_line*image->rows);
1684 bmp_info.file_size+=bmp_info.image_size;
1685 bmp_info.x_pixels=75*39;
1686 bmp_info.y_pixels=75*39;
1687 switch (image->units)
1688 {
1689 case UndefinedResolution:
1690 case PixelsPerInchResolution:
1691 {
cristy2a11bef2011-10-28 18:33:11 +00001692 bmp_info.x_pixels=(unsigned int) (100.0*image->resolution.x/2.54);
1693 bmp_info.y_pixels=(unsigned int) (100.0*image->resolution.y/2.54);
cristy3ed852e2009-09-05 21:47:34 +00001694 break;
1695 }
1696 case PixelsPerCentimeterResolution:
1697 {
cristy2a11bef2011-10-28 18:33:11 +00001698 bmp_info.x_pixels=(unsigned int) (100.0*image->resolution.x);
1699 bmp_info.y_pixels=(unsigned int) (100.0*image->resolution.y);
cristy3ed852e2009-09-05 21:47:34 +00001700 break;
1701 }
1702 }
1703 bmp_info.colors_important=bmp_info.number_colors;
1704 /*
1705 Convert MIFF to BMP raster pixels.
1706 */
cristy0553bd52013-06-30 15:53:50 +00001707 pixel_info=AcquireVirtualMemory((size_t) bmp_info.image_size,
cristy3ed852e2009-09-05 21:47:34 +00001708 sizeof(*pixels));
cristy0553bd52013-06-30 15:53:50 +00001709 if (pixel_info == (MemoryInfo *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001710 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
cristy0553bd52013-06-30 15:53:50 +00001711 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +00001712 (void) ResetMagickMemory(pixels,0,(size_t) bmp_info.image_size);
1713 switch (bmp_info.bits_per_pixel)
1714 {
1715 case 1:
1716 {
cristybb503372010-05-27 20:51:26 +00001717 size_t
cristy3ed852e2009-09-05 21:47:34 +00001718 bit,
1719 byte;
1720
1721 /*
1722 Convert PseudoClass image to a BMP monochrome image.
1723 */
cristybb503372010-05-27 20:51:26 +00001724 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001725 {
cristy4c08aed2011-07-01 19:47:50 +00001726 ssize_t
1727 offset;
1728
cristy1e178e72011-08-28 19:44:34 +00001729 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001730 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001731 break;
cristy3ed852e2009-09-05 21:47:34 +00001732 q=pixels+(image->rows-y-1)*bytes_per_line;
1733 bit=0;
1734 byte=0;
cristybb503372010-05-27 20:51:26 +00001735 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001736 {
1737 byte<<=1;
cristy4c08aed2011-07-01 19:47:50 +00001738 byte|=GetPixelIndex(image,p) != 0 ? 0x01 : 0x00;
cristy3ed852e2009-09-05 21:47:34 +00001739 bit++;
1740 if (bit == 8)
1741 {
1742 *q++=(unsigned char) byte;
1743 bit=0;
1744 byte=0;
1745 }
cristyed231572011-07-14 02:18:59 +00001746 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001747 }
1748 if (bit != 0)
1749 {
1750 *q++=(unsigned char) (byte << (8-bit));
1751 x++;
1752 }
cristy4c08aed2011-07-01 19:47:50 +00001753 offset=(ssize_t) (image->columns+7)/8;
1754 for (x=offset; x < (ssize_t) bytes_per_line; x++)
cristy3ed852e2009-09-05 21:47:34 +00001755 *q++=0x00;
1756 if (image->previous == (Image *) NULL)
1757 {
cristycee97112010-05-28 00:44:52 +00001758 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1759 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001760 if (status == MagickFalse)
1761 break;
1762 }
1763 }
1764 break;
1765 }
1766 case 4:
1767 {
cristybb503372010-05-27 20:51:26 +00001768 size_t
cristy4c08aed2011-07-01 19:47:50 +00001769 byte,
cristya321eb72013-06-23 10:42:37 +00001770 nibble;
1771
1772 ssize_t
cristy7c242ea2013-06-21 17:19:53 +00001773 offset;
cristy3ed852e2009-09-05 21:47:34 +00001774
1775 /*
1776 Convert PseudoClass image to a BMP monochrome image.
1777 */
cristybb503372010-05-27 20:51:26 +00001778 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001779 {
cristy1e178e72011-08-28 19:44:34 +00001780 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001781 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001782 break;
cristy3ed852e2009-09-05 21:47:34 +00001783 q=pixels+(image->rows-y-1)*bytes_per_line;
1784 nibble=0;
1785 byte=0;
cristybb503372010-05-27 20:51:26 +00001786 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001787 {
1788 byte<<=4;
cristy4c08aed2011-07-01 19:47:50 +00001789 byte|=((size_t) GetPixelIndex(image,p) & 0x0f);
cristy3ed852e2009-09-05 21:47:34 +00001790 nibble++;
1791 if (nibble == 2)
1792 {
1793 *q++=(unsigned char) byte;
1794 nibble=0;
1795 byte=0;
1796 }
cristyed231572011-07-14 02:18:59 +00001797 p+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00001798 }
1799 if (nibble != 0)
1800 {
1801 *q++=(unsigned char) (byte << 4);
1802 x++;
1803 }
1804 offset=(ssize_t) (image->columns+1)/2;
1805 for (x=offset; x < (ssize_t) bytes_per_line; x++)
cristy3ed852e2009-09-05 21:47:34 +00001806 *q++=0x00;
1807 if (image->previous == (Image *) NULL)
1808 {
cristycee97112010-05-28 00:44:52 +00001809 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1810 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001811 if (status == MagickFalse)
1812 break;
1813 }
1814 }
1815 break;
1816 }
1817 case 8:
1818 {
1819 /*
1820 Convert PseudoClass packet to BMP pixel.
1821 */
cristybb503372010-05-27 20:51:26 +00001822 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001823 {
cristy1e178e72011-08-28 19:44:34 +00001824 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001825 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001826 break;
cristy3ed852e2009-09-05 21:47:34 +00001827 q=pixels+(image->rows-y-1)*bytes_per_line;
cristybb503372010-05-27 20:51:26 +00001828 for (x=0; x < (ssize_t) image->columns; x++)
cristy4c08aed2011-07-01 19:47:50 +00001829 {
1830 *q++=(unsigned char) GetPixelIndex(image,p);
cristyed231572011-07-14 02:18:59 +00001831 p+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00001832 }
cristybb503372010-05-27 20:51:26 +00001833 for ( ; x < (ssize_t) bytes_per_line; x++)
cristy3ed852e2009-09-05 21:47:34 +00001834 *q++=0x00;
1835 if (image->previous == (Image *) NULL)
1836 {
cristycee97112010-05-28 00:44:52 +00001837 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1838 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001839 if (status == MagickFalse)
1840 break;
1841 }
1842 }
1843 break;
1844 }
1845 case 24:
1846 {
1847 /*
1848 Convert DirectClass packet to BMP BGR888.
1849 */
cristybb503372010-05-27 20:51:26 +00001850 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001851 {
cristy1e178e72011-08-28 19:44:34 +00001852 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001853 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001854 break;
1855 q=pixels+(image->rows-y-1)*bytes_per_line;
cristybb503372010-05-27 20:51:26 +00001856 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001857 {
cristy4c08aed2011-07-01 19:47:50 +00001858 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
1859 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
1860 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
cristyed231572011-07-14 02:18:59 +00001861 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001862 }
cristybb503372010-05-27 20:51:26 +00001863 for (x=3L*(ssize_t) image->columns; x < (ssize_t) bytes_per_line; x++)
cristy3ed852e2009-09-05 21:47:34 +00001864 *q++=0x00;
1865 if (image->previous == (Image *) NULL)
1866 {
cristycee97112010-05-28 00:44:52 +00001867 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1868 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001869 if (status == MagickFalse)
1870 break;
1871 }
1872 }
1873 break;
1874 }
1875 case 32:
1876 {
1877 /*
1878 Convert DirectClass packet to ARGB8888 pixel.
1879 */
cristybb503372010-05-27 20:51:26 +00001880 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001881 {
cristy1e178e72011-08-28 19:44:34 +00001882 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001883 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001884 break;
1885 q=pixels+(image->rows-y-1)*bytes_per_line;
cristybb503372010-05-27 20:51:26 +00001886 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001887 {
cristy4c08aed2011-07-01 19:47:50 +00001888 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
1889 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
1890 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
1891 *q++=ScaleQuantumToChar(GetPixelAlpha(image,p));
cristyed231572011-07-14 02:18:59 +00001892 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001893 }
1894 if (image->previous == (Image *) NULL)
1895 {
cristycee97112010-05-28 00:44:52 +00001896 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1897 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001898 if (status == MagickFalse)
1899 break;
1900 }
1901 }
1902 break;
1903 }
1904 }
1905 if ((type > 2) && (bmp_info.bits_per_pixel == 8))
1906 if (image_info->compression != NoCompression)
1907 {
cristya321eb72013-06-23 10:42:37 +00001908 MemoryInfo
1909 *rle_info;
cristy3ed852e2009-09-05 21:47:34 +00001910
1911 /*
1912 Convert run-length encoded raster pixels.
1913 */
cristya321eb72013-06-23 10:42:37 +00001914 rle_info=AcquireVirtualMemory((size_t) (2*(bytes_per_line+2)+2),
1915 (image->rows+2)*sizeof(*pixels));
1916 if (rle_info == (MemoryInfo *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001917 {
cristy0553bd52013-06-30 15:53:50 +00001918 pixel_info=RelinquishVirtualMemory(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +00001919 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1920 }
cristya321eb72013-06-23 10:42:37 +00001921 bmp_data=(unsigned char *) GetVirtualMemoryBlob(rle_info);
cristy3ed852e2009-09-05 21:47:34 +00001922 bmp_info.file_size-=bmp_info.image_size;
1923 bmp_info.image_size=(unsigned int) EncodeImage(image,bytes_per_line,
1924 pixels,bmp_data);
1925 bmp_info.file_size+=bmp_info.image_size;
cristy0553bd52013-06-30 15:53:50 +00001926 pixel_info=RelinquishVirtualMemory(pixel_info);
1927 pixel_info=rle_info;
cristy3ed852e2009-09-05 21:47:34 +00001928 pixels=bmp_data;
1929 bmp_info.compression=BI_RLE8;
1930 }
1931 /*
1932 Write BMP for Windows, all versions, 14-byte header.
1933 */
1934 if (image->debug != MagickFalse)
1935 {
1936 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +00001937 " Writing BMP version %.20g datastream",(double) type);
cristy3ed852e2009-09-05 21:47:34 +00001938 if (image->storage_class == DirectClass)
1939 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1940 " Storage class=DirectClass");
1941 else
1942 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1943 " Storage class=PseudoClass");
1944 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +00001945 " Image depth=%.20g",(double) image->depth);
cristy17f11b02014-12-20 19:37:04 +00001946 if (image->alpha_trait != UndefinedPixelTrait)
cristy3ed852e2009-09-05 21:47:34 +00001947 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1948 " Matte=True");
1949 else
1950 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1951 " Matte=MagickFalse");
1952 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +00001953 " BMP bits_per_pixel=%.20g",(double) bmp_info.bits_per_pixel);
cristy3ed852e2009-09-05 21:47:34 +00001954 switch ((int) bmp_info.compression)
1955 {
1956 case BI_RGB:
1957 {
1958 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1959 " Compression=BI_RGB");
1960 break;
1961 }
1962 case BI_RLE8:
1963 {
1964 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1965 " Compression=BI_RLE8");
1966 break;
1967 }
1968 case BI_BITFIELDS:
1969 {
1970 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1971 " Compression=BI_BITFIELDS");
1972 break;
1973 }
1974 default:
1975 {
1976 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1977 " Compression=UNKNOWN (%u)",bmp_info.compression);
1978 break;
1979 }
1980 }
1981 if (bmp_info.number_colors == 0)
1982 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1983 " Number_colors=unspecified");
1984 else
1985 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1986 " Number_colors=%u",bmp_info.number_colors);
1987 }
1988 (void) WriteBlob(image,2,(unsigned char *) "BM");
1989 (void) WriteBlobLSBLong(image,bmp_info.file_size);
1990 (void) WriteBlobLSBLong(image,bmp_info.ba_offset); /* always 0 */
1991 (void) WriteBlobLSBLong(image,bmp_info.offset_bits);
1992 if (type == 2)
1993 {
1994 /*
1995 Write 12-byte version 2 bitmap header.
1996 */
1997 (void) WriteBlobLSBLong(image,bmp_info.size);
1998 (void) WriteBlobLSBShort(image,(unsigned short) bmp_info.width);
1999 (void) WriteBlobLSBShort(image,(unsigned short) bmp_info.height);
2000 (void) WriteBlobLSBShort(image,bmp_info.planes);
2001 (void) WriteBlobLSBShort(image,bmp_info.bits_per_pixel);
2002 }
2003 else
2004 {
2005 /*
2006 Write 40-byte version 3+ bitmap header.
2007 */
2008 (void) WriteBlobLSBLong(image,bmp_info.size);
2009 (void) WriteBlobLSBLong(image,(unsigned int) bmp_info.width);
2010 (void) WriteBlobLSBLong(image,(unsigned int) bmp_info.height);
2011 (void) WriteBlobLSBShort(image,bmp_info.planes);
2012 (void) WriteBlobLSBShort(image,bmp_info.bits_per_pixel);
2013 (void) WriteBlobLSBLong(image,bmp_info.compression);
2014 (void) WriteBlobLSBLong(image,bmp_info.image_size);
2015 (void) WriteBlobLSBLong(image,bmp_info.x_pixels);
2016 (void) WriteBlobLSBLong(image,bmp_info.y_pixels);
2017 (void) WriteBlobLSBLong(image,bmp_info.number_colors);
2018 (void) WriteBlobLSBLong(image,bmp_info.colors_important);
2019 }
cristy17f11b02014-12-20 19:37:04 +00002020 if ((type > 3) && ((image->alpha_trait != UndefinedPixelTrait) ||
cristy3ed852e2009-09-05 21:47:34 +00002021 (have_color_info != MagickFalse)))
2022 {
2023 /*
2024 Write the rest of the 108-byte BMP Version 4 header.
2025 */
2026 (void) WriteBlobLSBLong(image,0x00ff0000U); /* Red mask */
2027 (void) WriteBlobLSBLong(image,0x0000ff00U); /* Green mask */
2028 (void) WriteBlobLSBLong(image,0x000000ffU); /* Blue mask */
2029 (void) WriteBlobLSBLong(image,0xff000000U); /* Alpha mask */
cristy55388ab2012-05-01 00:01:47 +00002030 (void) WriteBlobLSBLong(image,0x73524742U); /* sRGB */
cristy3ed852e2009-09-05 21:47:34 +00002031 (void) WriteBlobLSBLong(image,(unsigned int)
cristyc554cc82012-08-12 19:55:34 +00002032 (image->chromaticity.red_primary.x*0x40000000));
cristy3ed852e2009-09-05 21:47:34 +00002033 (void) WriteBlobLSBLong(image,(unsigned int)
cristyc554cc82012-08-12 19:55:34 +00002034 (image->chromaticity.red_primary.y*0x40000000));
cristy3ed852e2009-09-05 21:47:34 +00002035 (void) WriteBlobLSBLong(image,(unsigned int)
cristyc554cc82012-08-12 19:55:34 +00002036 ((1.000f-(image->chromaticity.red_primary.x+
2037 image->chromaticity.red_primary.y))*0x40000000));
cristy3ed852e2009-09-05 21:47:34 +00002038 (void) WriteBlobLSBLong(image,(unsigned int)
cristyc554cc82012-08-12 19:55:34 +00002039 (image->chromaticity.green_primary.x*0x40000000));
cristy3ed852e2009-09-05 21:47:34 +00002040 (void) WriteBlobLSBLong(image,(unsigned int)
cristyc554cc82012-08-12 19:55:34 +00002041 (image->chromaticity.green_primary.y*0x40000000));
cristy3ed852e2009-09-05 21:47:34 +00002042 (void) WriteBlobLSBLong(image,(unsigned int)
cristyc554cc82012-08-12 19:55:34 +00002043 ((1.000f-(image->chromaticity.green_primary.x+
2044 image->chromaticity.green_primary.y))*0x40000000));
cristy3ed852e2009-09-05 21:47:34 +00002045 (void) WriteBlobLSBLong(image,(unsigned int)
cristyc554cc82012-08-12 19:55:34 +00002046 (image->chromaticity.blue_primary.x*0x40000000));
cristy3ed852e2009-09-05 21:47:34 +00002047 (void) WriteBlobLSBLong(image,(unsigned int)
cristyc554cc82012-08-12 19:55:34 +00002048 (image->chromaticity.blue_primary.y*0x40000000));
cristy3ed852e2009-09-05 21:47:34 +00002049 (void) WriteBlobLSBLong(image,(unsigned int)
cristyc554cc82012-08-12 19:55:34 +00002050 ((1.000f-(image->chromaticity.blue_primary.x+
2051 image->chromaticity.blue_primary.y))*0x40000000));
cristy3ed852e2009-09-05 21:47:34 +00002052 (void) WriteBlobLSBLong(image,(unsigned int)
cristyc554cc82012-08-12 19:55:34 +00002053 (bmp_info.gamma_scale.x*0x10000));
cristy3ed852e2009-09-05 21:47:34 +00002054 (void) WriteBlobLSBLong(image,(unsigned int)
cristyc554cc82012-08-12 19:55:34 +00002055 (bmp_info.gamma_scale.y*0x10000));
cristy3ed852e2009-09-05 21:47:34 +00002056 (void) WriteBlobLSBLong(image,(unsigned int)
cristyc554cc82012-08-12 19:55:34 +00002057 (bmp_info.gamma_scale.z*0x10000));
cristy3ed852e2009-09-05 21:47:34 +00002058 if ((image->rendering_intent != UndefinedIntent) ||
2059 (profile != (StringInfo *) NULL))
2060 {
cristybb503372010-05-27 20:51:26 +00002061 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002062 intent;
2063
2064 switch ((int) image->rendering_intent)
2065 {
2066 case SaturationIntent:
2067 {
2068 intent=LCS_GM_BUSINESS;
2069 break;
2070 }
2071 case RelativeIntent:
2072 {
2073 intent=LCS_GM_GRAPHICS;
2074 break;
2075 }
2076 case PerceptualIntent:
2077 {
2078 intent=LCS_GM_IMAGES;
2079 break;
2080 }
2081 case AbsoluteIntent:
2082 {
2083 intent=LCS_GM_ABS_COLORIMETRIC;
2084 break;
2085 }
2086 default:
2087 {
2088 intent=0;
2089 break;
2090 }
2091 }
2092 (void) WriteBlobLSBLong(image,(unsigned int) intent);
2093 (void) WriteBlobLSBLong(image,0x00); /* dummy profile data */
2094 (void) WriteBlobLSBLong(image,0x00); /* dummy profile length */
2095 (void) WriteBlobLSBLong(image,0x00); /* reserved */
2096 }
2097 }
2098 if (image->storage_class == PseudoClass)
2099 {
2100 unsigned char
2101 *bmp_colormap;
2102
2103 /*
2104 Dump colormap to file.
2105 */
2106 if (image->debug != MagickFalse)
2107 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +00002108 " Colormap: %.20g entries",(double) image->colors);
cristy3ed852e2009-09-05 21:47:34 +00002109 bmp_colormap=(unsigned char *) AcquireQuantumMemory((size_t) (1UL <<
2110 bmp_info.bits_per_pixel),4*sizeof(*bmp_colormap));
2111 if (bmp_colormap == (unsigned char *) NULL)
2112 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2113 q=bmp_colormap;
cristybb503372010-05-27 20:51:26 +00002114 for (i=0; i < (ssize_t) MagickMin((ssize_t) image->colors,(ssize_t) bmp_info.number_colors); i++)
cristy3ed852e2009-09-05 21:47:34 +00002115 {
cristya321eb72013-06-23 10:42:37 +00002116 *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].blue));
2117 *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].green));
2118 *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].red));
cristy3ed852e2009-09-05 21:47:34 +00002119 if (type > 2)
2120 *q++=(unsigned char) 0x0;
2121 }
cristybb503372010-05-27 20:51:26 +00002122 for ( ; i < (ssize_t) (1UL << bmp_info.bits_per_pixel); i++)
cristy3ed852e2009-09-05 21:47:34 +00002123 {
2124 *q++=(unsigned char) 0x00;
2125 *q++=(unsigned char) 0x00;
2126 *q++=(unsigned char) 0x00;
2127 if (type > 2)
2128 *q++=(unsigned char) 0x00;
2129 }
2130 if (type <= 2)
2131 (void) WriteBlob(image,(size_t) (3*(1L << bmp_info.bits_per_pixel)),
2132 bmp_colormap);
2133 else
2134 (void) WriteBlob(image,(size_t) (4*(1L << bmp_info.bits_per_pixel)),
2135 bmp_colormap);
2136 bmp_colormap=(unsigned char *) RelinquishMagickMemory(bmp_colormap);
2137 }
2138 if (image->debug != MagickFalse)
2139 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2140 " Pixels: %u bytes",bmp_info.image_size);
2141 (void) WriteBlob(image,(size_t) bmp_info.image_size,pixels);
cristy0553bd52013-06-30 15:53:50 +00002142 pixel_info=RelinquishVirtualMemory(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +00002143 if (GetNextImageInList(image) == (Image *) NULL)
2144 break;
2145 image=SyncNextImageInList(image);
2146 status=SetImageProgress(image,SaveImagesTag,scene++,
2147 GetImageListLength(image));
2148 if (status == MagickFalse)
2149 break;
2150 } while (image_info->adjoin != MagickFalse);
2151 (void) CloseBlob(image);
2152 return(MagickTrue);
cristy84af0c32013-06-23 18:08:28 +00002153}