blob: 17df06a59c21209975581b663d8946b87390f795 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% DDDD IIIII BBBB %
7% D D I B B %
8% D D I BBBB %
9% D D I B B %
10% DDDD IIIII BBBB %
11% %
12% %
13% Read/Write Windows DIB Image Format %
14% %
15% Software Design %
cristyde984cd2013-12-01 14:49:27 +000016% Cristy %
cristy3ed852e2009-09-05 21:47:34 +000017% July 1992 %
18% %
19% %
cristyb56bb242014-11-25 17:12:48 +000020% Copyright 1999-2015 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37*/
38
39/*
40 Include declarations.
41*/
cristy4c08aed2011-07-01 19:47:50 +000042#include "MagickCore/studio.h"
43#include "MagickCore/attribute.h"
44#include "MagickCore/blob.h"
45#include "MagickCore/blob-private.h"
46#include "MagickCore/cache.h"
47#include "MagickCore/color.h"
48#include "MagickCore/color-private.h"
49#include "MagickCore/colormap.h"
50#include "MagickCore/colormap-private.h"
51#include "MagickCore/colorspace.h"
cristy510d06a2011-07-06 23:43:54 +000052#include "MagickCore/colorspace-private.h"
cristy4c08aed2011-07-01 19:47:50 +000053#include "MagickCore/draw.h"
54#include "MagickCore/exception.h"
55#include "MagickCore/exception-private.h"
56#include "MagickCore/geometry.h"
57#include "MagickCore/image.h"
58#include "MagickCore/image-private.h"
59#include "MagickCore/list.h"
60#include "MagickCore/log.h"
61#include "MagickCore/magick.h"
62#include "MagickCore/memory_.h"
63#include "MagickCore/monitor.h"
64#include "MagickCore/monitor-private.h"
65#include "MagickCore/pixel-accessor.h"
66#include "MagickCore/quantum-private.h"
67#include "MagickCore/static.h"
68#include "MagickCore/string_.h"
69#include "MagickCore/module.h"
70#include "MagickCore/transform.h"
cristy3ed852e2009-09-05 21:47:34 +000071
72/*
73 Typedef declarations.
74*/
75typedef struct _DIBInfo
76{
cristyf6fe0a12010-05-30 00:44:47 +000077 size_t
cristy3ed852e2009-09-05 21:47:34 +000078 size;
79
cristyf6fe0a12010-05-30 00:44:47 +000080 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000081 width,
82 height;
83
84 unsigned short
85 planes,
86 bits_per_pixel;
87
cristyf6fe0a12010-05-30 00:44:47 +000088 size_t
cristy3ed852e2009-09-05 21:47:34 +000089 compression,
90 image_size,
91 x_pixels,
92 y_pixels,
93 number_colors,
94 red_mask,
95 green_mask,
96 blue_mask,
97 alpha_mask,
98 colors_important;
99
cristyf6fe0a12010-05-30 00:44:47 +0000100 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000101 colorspace;
102
103 PointInfo
104 red_primary,
105 green_primary,
106 blue_primary,
107 gamma_scale;
108} DIBInfo;
109
110/*
111 Forward declarations.
112*/
113static MagickBooleanType
cristy1e178e72011-08-28 19:44:34 +0000114 WriteDIBImage(const ImageInfo *,Image *,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000115
116/*
117%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
118% %
119% %
120% %
121% D e c o d e I m a g e %
122% %
123% %
124% %
125%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
126%
127% DecodeImage unpacks the packed image pixels into runlength-encoded
128% pixel packets.
129%
130% The format of the DecodeImage method is:
131%
132% MagickBooleanType DecodeImage(Image *image,
133% const MagickBooleanType compression,unsigned char *pixels)
134%
135% A description of each parameter follows:
136%
137% o image: the address of a structure of type Image.
138%
139% o compression: A value of 1 means the compressed pixels are runlength
140% encoded for a 256-color bitmap. A value of 2 means a 16-color bitmap.
141%
142% o pixels: The address of a byte (8 bits) array of pixel data created by
143% the decoding process.
144%
145*/
146
147static inline size_t MagickMin(const size_t x,const size_t y)
148{
149 if (x < y)
150 return(x);
151 return(y);
152}
153
154static MagickBooleanType DecodeImage(Image *image,
155 const MagickBooleanType compression,unsigned char *pixels)
156{
cristy07a3cca2012-12-10 13:09:10 +0000157#if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__MINGW32__) || defined(__MINGW64__)
cristy3ed852e2009-09-05 21:47:34 +0000158#define BI_RGB 0
159#define BI_RLE8 1
160#define BI_RLE4 2
161#define BI_BITFIELDS 3
cristyf8dcd772014-12-19 12:11:44 +0000162#undef BI_JPEG
163#define BI_JPEG 4
164#undef BI_PNG
165#define BI_PNG 5
cristy3ed852e2009-09-05 21:47:34 +0000166#endif
167
168 int
169 count;
170
cristybb503372010-05-27 20:51:26 +0000171 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000172 y;
173
cristybb503372010-05-27 20:51:26 +0000174 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000175 i,
176 x;
177
178 register unsigned char
179 *p,
180 *q;
181
182 unsigned char
183 byte;
184
185 assert(image != (Image *) NULL);
186 assert(image->signature == MagickSignature);
187 if (image->debug != MagickFalse)
188 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
189 assert(pixels != (unsigned char *) NULL);
190 (void) ResetMagickMemory(pixels,0,(size_t) image->columns*image->rows*
191 sizeof(*pixels));
192 byte=0;
193 x=0;
194 p=pixels;
195 q=pixels+(size_t) image->columns*image->rows;
cristybb503372010-05-27 20:51:26 +0000196 for (y=0; y < (ssize_t) image->rows; )
cristy3ed852e2009-09-05 21:47:34 +0000197 {
198 if ((p < pixels) || (p >= q))
199 break;
200 count=ReadBlobByte(image);
201 if (count == EOF)
202 break;
203 if (count != 0)
204 {
205 count=(int) MagickMin((size_t) count,(size_t) (q-p));
206 /*
207 Encoded mode.
208 */
209 byte=(unsigned char) ReadBlobByte(image);
210 if (compression == BI_RLE8)
211 {
212 for (i=0; i < count; i++)
213 *p++=(unsigned char) byte;
214 }
215 else
216 {
217 for (i=0; i < count; i++)
218 *p++=(unsigned char)
219 ((i & 0x01) != 0 ? (byte & 0x0f) : ((byte >> 4) & 0x0f));
220 }
221 x+=count;
222 }
223 else
224 {
225 /*
226 Escape mode.
227 */
228 count=ReadBlobByte(image);
229 if (count == 0x01)
230 return(MagickTrue);
231 switch (count)
232 {
233 case 0x00:
234 {
235 /*
236 End of line.
237 */
238 x=0;
239 y++;
240 p=pixels+y*image->columns;
241 break;
242 }
243 case 0x02:
244 {
245 /*
246 Delta mode.
247 */
248 x+=ReadBlobByte(image);
249 y+=ReadBlobByte(image);
250 p=pixels+y*image->columns+x;
251 break;
252 }
253 default:
254 {
255 /*
256 Absolute mode.
257 */
258 count=(int) MagickMin((size_t) count,(size_t) (q-p));
259 if (compression == BI_RLE8)
260 for (i=0; i < count; i++)
261 *p++=(unsigned char) ReadBlobByte(image);
262 else
263 for (i=0; i < count; i++)
264 {
265 if ((i & 0x01) == 0)
266 byte=(unsigned char) ReadBlobByte(image);
267 *p++=(unsigned char)
268 ((i & 0x01) != 0 ? (byte & 0x0f) : ((byte >> 4) & 0x0f));
269 }
270 x+=count;
271 /*
272 Read pad byte.
273 */
274 if (compression == BI_RLE8)
275 {
276 if ((count & 0x01) != 0)
277 (void) ReadBlobByte(image);
278 }
279 else
280 if (((count & 0x03) == 1) || ((count & 0x03) == 2))
281 (void) ReadBlobByte(image);
282 break;
283 }
284 }
285 }
286 if (SetImageProgress(image,LoadImageTag,y,image->rows) == MagickFalse)
287 break;
288 }
289 (void) ReadBlobByte(image); /* end of line */
290 (void) ReadBlobByte(image);
291 return(MagickTrue);
292}
293
294/*
295%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
296% %
297% %
298% %
299% E n c o d e I m a g e %
300% %
301% %
302% %
303%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
304%
305% EncodeImage compresses pixels using a runlength encoded format.
306%
307% The format of the EncodeImage method is:
308%
309% static MagickBooleanType EncodeImage(Image *image,
cristybb503372010-05-27 20:51:26 +0000310% const size_t bytes_per_line,const unsigned char *pixels,
cristy3ed852e2009-09-05 21:47:34 +0000311% unsigned char *compressed_pixels)
312%
313% A description of each parameter follows:
314%
315% o image: The image.
316%
317% o bytes_per_line: the number of bytes in a scanline of compressed pixels
318%
319% o pixels: The address of a byte (8 bits) array of pixel data created by
320% the compression process.
321%
322% o compressed_pixels: The address of a byte (8 bits) array of compressed
323% pixel data.
324%
325*/
cristybb503372010-05-27 20:51:26 +0000326static size_t EncodeImage(Image *image,const size_t bytes_per_line,
cristy3ed852e2009-09-05 21:47:34 +0000327 const unsigned char *pixels,unsigned char *compressed_pixels)
328{
cristybb503372010-05-27 20:51:26 +0000329 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000330 y;
331
332 register const unsigned char
333 *p;
334
cristybb503372010-05-27 20:51:26 +0000335 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000336 i,
337 x;
338
339 register unsigned char
340 *q;
341
342 /*
343 Runlength encode pixels.
344 */
345 assert(image != (Image *) NULL);
346 assert(image->signature == MagickSignature);
347 if (image->debug != MagickFalse)
348 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
349 assert(pixels != (const unsigned char *) NULL);
350 assert(compressed_pixels != (unsigned char *) NULL);
351 p=pixels;
352 q=compressed_pixels;
353 i=0;
cristybb503372010-05-27 20:51:26 +0000354 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000355 {
cristybb503372010-05-27 20:51:26 +0000356 for (x=0; x < (ssize_t) bytes_per_line; x+=i)
cristy3ed852e2009-09-05 21:47:34 +0000357 {
358 /*
359 Determine runlength.
360 */
cristybb503372010-05-27 20:51:26 +0000361 for (i=1; ((x+i) < (ssize_t) bytes_per_line); i++)
cristy3ed852e2009-09-05 21:47:34 +0000362 if ((*(p+i) != *p) || (i == 255))
363 break;
364 *q++=(unsigned char) i;
365 *q++=(*p);
366 p+=i;
367 }
368 /*
369 End of line.
370 */
371 *q++=0x00;
372 *q++=0x00;
373 if (SetImageProgress(image,LoadImageTag,y,image->rows) == MagickFalse)
374 break;
375 }
376 /*
377 End of bitmap.
378 */
379 *q++=0;
380 *q++=0x01;
381 return((size_t) (q-compressed_pixels));
382}
383
384/*
385%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
386% %
387% %
388% %
389% I s D I B %
390% %
391% %
392% %
393%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
394%
395% IsDIB() returns MagickTrue if the image format type, identified by the
396% magick string, is DIB.
397%
398% The format of the IsDIB method is:
399%
400% MagickBooleanType IsDIB(const unsigned char *magick,const size_t length)
401%
402% A description of each parameter follows:
403%
404% o magick: compare image format pattern against these bytes.
405%
406% o length: Specifies the length of the magick string.
407%
408*/
409static MagickBooleanType IsDIB(const unsigned char *magick,const size_t length)
410{
411 if (length < 2)
412 return(MagickFalse);
413 if (memcmp(magick,"\050\000",2) == 0)
414 return(MagickTrue);
415 return(MagickFalse);
416}
417
418/*
419%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
420% %
421% %
422% %
423% R e a d D I B I m a g e %
424% %
425% %
426% %
427%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
428%
429% ReadDIBImage() reads a Microsoft Windows bitmap image file and
430% returns it. It allocates the memory necessary for the new Image structure
431% and returns a pointer to the new image.
432%
433% The format of the ReadDIBImage method is:
434%
435% image=ReadDIBImage(image_info)
436%
437% A description of each parameter follows:
438%
439% o image_info: the image info.
440%
441% o exception: return any errors or warnings in this structure.
442%
443*/
444
cristybb503372010-05-27 20:51:26 +0000445static inline ssize_t MagickAbsoluteValue(const ssize_t x)
cristy3ed852e2009-09-05 21:47:34 +0000446{
447 if (x < 0)
448 return(-x);
449 return(x);
450}
451
452static inline size_t MagickMax(const size_t x,const size_t y)
453{
454 if (x > y)
455 return(x);
456 return(y);
457}
458
459static Image *ReadDIBImage(const ImageInfo *image_info,ExceptionInfo *exception)
460{
461 DIBInfo
462 dib_info;
463
464 Image
465 *image;
466
cristy3ed852e2009-09-05 21:47:34 +0000467 MagickBooleanType
468 status;
469
cristy0553bd52013-06-30 15:53:50 +0000470 MemoryInfo
471 *pixel_info;
472
cristy4c08aed2011-07-01 19:47:50 +0000473 Quantum
474 index;
cristy3ed852e2009-09-05 21:47:34 +0000475
cristybb503372010-05-27 20:51:26 +0000476 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000477 x;
478
cristy4c08aed2011-07-01 19:47:50 +0000479 register Quantum
cristy3ed852e2009-09-05 21:47:34 +0000480 *q;
481
cristybb503372010-05-27 20:51:26 +0000482 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000483 i;
484
485 register unsigned char
486 *p;
487
488 size_t
cristyddbc41b2011-04-24 14:27:48 +0000489 bytes_per_line,
cristy3ed852e2009-09-05 21:47:34 +0000490 length;
491
492 ssize_t
cristy4c08aed2011-07-01 19:47:50 +0000493 bit,
494 count,
495 y;
496
cristy3ed852e2009-09-05 21:47:34 +0000497
498 unsigned char
499 *pixels;
500
cristy3ed852e2009-09-05 21:47:34 +0000501 /*
502 Open image file.
503 */
504 assert(image_info != (const ImageInfo *) NULL);
505 assert(image_info->signature == MagickSignature);
506 if (image_info->debug != MagickFalse)
507 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
508 image_info->filename);
509 assert(exception != (ExceptionInfo *) NULL);
510 assert(exception->signature == MagickSignature);
cristy9950d572011-10-01 18:22:35 +0000511 image=AcquireImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +0000512 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
513 if (status == MagickFalse)
514 {
515 image=DestroyImageList(image);
516 return((Image *) NULL);
517 }
518 /*
519 Determine if this a DIB file.
520 */
521 (void) ResetMagickMemory(&dib_info,0,sizeof(dib_info));
522 dib_info.size=ReadBlobLSBLong(image);
cristyacabb842014-12-14 23:36:33 +0000523 if (dib_info.size != 40)
cristy3ed852e2009-09-05 21:47:34 +0000524 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
525 /*
526 Microsoft Windows 3.X DIB image file.
527 */
528 dib_info.width=(short) ReadBlobLSBLong(image);
529 dib_info.height=(short) ReadBlobLSBLong(image);
530 dib_info.planes=ReadBlobLSBShort(image);
531 dib_info.bits_per_pixel=ReadBlobLSBShort(image);
cristyf8dcd772014-12-19 12:11:44 +0000532 if (dib_info.bits_per_pixel > 32)
533 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
cristy3ed852e2009-09-05 21:47:34 +0000534 dib_info.compression=ReadBlobLSBLong(image);
535 dib_info.image_size=ReadBlobLSBLong(image);
536 dib_info.x_pixels=ReadBlobLSBLong(image);
537 dib_info.y_pixels=ReadBlobLSBLong(image);
538 dib_info.number_colors=ReadBlobLSBLong(image);
539 dib_info.colors_important=ReadBlobLSBLong(image);
540 if ((dib_info.compression == BI_BITFIELDS) &&
541 ((dib_info.bits_per_pixel == 16) || (dib_info.bits_per_pixel == 32)))
542 {
543 dib_info.red_mask=ReadBlobLSBLong(image);
544 dib_info.green_mask=ReadBlobLSBLong(image);
545 dib_info.blue_mask=ReadBlobLSBLong(image);
546 }
cristyf8dcd772014-12-19 12:11:44 +0000547 if (dib_info.width <= 0)
548 ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize");
549 if (dib_info.height == 0)
550 ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize");
551 if (dib_info.planes != 1)
552 ThrowReaderException(CorruptImageError,"StaticPlanesValueNotEqualToOne");
553 if ((dib_info.bits_per_pixel != 1) && (dib_info.bits_per_pixel != 4) &&
554 (dib_info.bits_per_pixel != 8) && (dib_info.bits_per_pixel != 16) &&
555 (dib_info.bits_per_pixel != 24) && (dib_info.bits_per_pixel != 32))
556 ThrowReaderException(CorruptImageError,"UnrecognizedBitsPerPixel");
557 if (dib_info.bits_per_pixel < 16 &&
558 dib_info.number_colors > (1U << dib_info.bits_per_pixel))
559 ThrowReaderException(CorruptImageError,"UnrecognizedNumberOfColors");
560 if ((dib_info.compression == 1) && (dib_info.bits_per_pixel != 8))
561 ThrowReaderException(CorruptImageError,"UnrecognizedBitsPerPixel");
562 if ((dib_info.compression == 2) && (dib_info.bits_per_pixel != 4))
563 ThrowReaderException(CorruptImageError,"UnrecognizedBitsPerPixel");
564 if ((dib_info.compression == 3) && (dib_info.bits_per_pixel < 16))
565 ThrowReaderException(CorruptImageError,"UnrecognizedBitsPerPixel");
566 switch (dib_info.compression)
567 {
568 case BI_RGB:
569 case BI_RLE8:
570 case BI_RLE4:
571 case BI_BITFIELDS:
572 break;
573 case BI_JPEG:
574 ThrowReaderException(CoderError,"JPEGCompressNotSupported");
575 case BI_PNG:
576 ThrowReaderException(CoderError,"PNGCompressNotSupported");
577 default:
578 ThrowReaderException(CorruptImageError,"UnrecognizedImageCompression");
579 }
cristybb503372010-05-27 20:51:26 +0000580 image->columns=(size_t) MagickAbsoluteValue(dib_info.width);
581 image->rows=(size_t) MagickAbsoluteValue(dib_info.height);
cristy3ed852e2009-09-05 21:47:34 +0000582 image->depth=8;
cristyf8dcd772014-12-19 12:11:44 +0000583 image->alpha_trait=dib_info.bits_per_pixel == 32 ? BlendPixelTrait :
584 UndefinedPixelTrait;
cristy3ed852e2009-09-05 21:47:34 +0000585 if ((dib_info.number_colors != 0) || (dib_info.bits_per_pixel < 16))
586 {
cristyeaedf062010-05-29 22:36:02 +0000587 size_t
588 one;
589
cristy3ed852e2009-09-05 21:47:34 +0000590 image->storage_class=PseudoClass;
591 image->colors=dib_info.number_colors;
cristyeaedf062010-05-29 22:36:02 +0000592 one=1;
cristy3ed852e2009-09-05 21:47:34 +0000593 if (image->colors == 0)
cristyeaedf062010-05-29 22:36:02 +0000594 image->colors=one << dib_info.bits_per_pixel;
cristy3ed852e2009-09-05 21:47:34 +0000595 }
596 if (image_info->size)
597 {
598 RectangleInfo
599 geometry;
600
601 MagickStatusType
602 flags;
603
604 flags=ParseAbsoluteGeometry(image_info->size,&geometry);
605 if (flags & WidthValue)
606 if ((geometry.width != 0) && (geometry.width < image->columns))
607 image->columns=geometry.width;
608 if (flags & HeightValue)
609 if ((geometry.height != 0) && (geometry.height < image->rows))
610 image->rows=geometry.height;
611 }
cristyacabb842014-12-14 23:36:33 +0000612 status=SetImageExtent(image,image->columns,image->rows,exception);
613 if (status == MagickFalse)
614 return(DestroyImageList(image));
cristy3ed852e2009-09-05 21:47:34 +0000615 if (image->storage_class == PseudoClass)
616 {
617 size_t
618 length,
619 packet_size;
620
621 unsigned char
622 *dib_colormap;
623
624 /*
625 Read DIB raster colormap.
626 */
cristy018f07f2011-09-04 21:15:19 +0000627 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000628 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
629 length=(size_t) image->colors;
630 dib_colormap=(unsigned char *) AcquireQuantumMemory(length,
631 4*sizeof(*dib_colormap));
632 if (dib_colormap == (unsigned char *) NULL)
633 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
634 packet_size=4;
635 count=ReadBlob(image,packet_size*image->colors,dib_colormap);
636 if (count != (ssize_t) (packet_size*image->colors))
637 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
638 p=dib_colormap;
cristybb503372010-05-27 20:51:26 +0000639 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +0000640 {
641 image->colormap[i].blue=ScaleCharToQuantum(*p++);
642 image->colormap[i].green=ScaleCharToQuantum(*p++);
643 image->colormap[i].red=ScaleCharToQuantum(*p++);
644 if (packet_size == 4)
645 p++;
646 }
647 dib_colormap=(unsigned char *) RelinquishMagickMemory(dib_colormap);
648 }
649 /*
650 Read image data.
651 */
652 if (dib_info.compression == BI_RLE4)
653 dib_info.bits_per_pixel<<=1;
654 bytes_per_line=4*((image->columns*dib_info.bits_per_pixel+31)/32);
655 length=bytes_per_line*image->rows;
cristy0553bd52013-06-30 15:53:50 +0000656 pixel_info=AcquireVirtualMemory((size_t) image->rows,MagickMax(
657 bytes_per_line,image->columns+256UL)*sizeof(*pixels));
658 if (pixel_info == (MemoryInfo *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000659 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
cristy0553bd52013-06-30 15:53:50 +0000660 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +0000661 if ((dib_info.compression == BI_RGB) ||
662 (dib_info.compression == BI_BITFIELDS))
663 {
664 count=ReadBlob(image,length,pixels);
665 if (count != (ssize_t) (length))
666 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
667 }
668 else
669 {
670 /*
671 Convert run-length encoded raster pixels.
672 */
673 status=DecodeImage(image,dib_info.compression ? MagickTrue : MagickFalse,
674 pixels);
675 if (status == MagickFalse)
676 ThrowReaderException(CorruptImageError,"UnableToRunlengthDecodeImage");
677 }
678 /*
679 Initialize image structure.
680 */
681 image->units=PixelsPerCentimeterResolution;
cristy2a11bef2011-10-28 18:33:11 +0000682 image->resolution.x=(double) dib_info.x_pixels/100.0;
683 image->resolution.y=(double) dib_info.y_pixels/100.0;
cristy3ed852e2009-09-05 21:47:34 +0000684 /*
685 Convert DIB raster image to pixel packets.
686 */
687 switch (dib_info.bits_per_pixel)
688 {
689 case 1:
690 {
691 /*
692 Convert bitmap scanline.
693 */
cristybb503372010-05-27 20:51:26 +0000694 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +0000695 {
696 p=pixels+(image->rows-y-1)*bytes_per_line;
697 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000698 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000699 break;
cristybb503372010-05-27 20:51:26 +0000700 for (x=0; x < ((ssize_t) image->columns-7); x+=8)
cristy3ed852e2009-09-05 21:47:34 +0000701 {
702 for (bit=0; bit < 8; bit++)
703 {
cristy4c08aed2011-07-01 19:47:50 +0000704 index=(Quantum) ((*p) & (0x80 >> bit) ? 0x01 : 0x00);
705 SetPixelIndex(image,index,q);
cristyed231572011-07-14 02:18:59 +0000706 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000707 }
708 p++;
709 }
710 if ((image->columns % 8) != 0)
711 {
cristybb503372010-05-27 20:51:26 +0000712 for (bit=0; bit < (ssize_t) (image->columns % 8); bit++)
cristy3ed852e2009-09-05 21:47:34 +0000713 {
cristy4c08aed2011-07-01 19:47:50 +0000714 index=(Quantum) ((*p) & (0x80 >> bit) ? 0x01 : 0x00);
715 SetPixelIndex(image,index,q);
cristyed231572011-07-14 02:18:59 +0000716 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000717 }
718 p++;
719 }
720 if (SyncAuthenticPixels(image,exception) == MagickFalse)
721 break;
722 if (image->previous == (Image *) NULL)
723 {
724 status=SetImageProgress(image,LoadImageTag,image->rows-y-1,
725 image->rows);
726 if (status == MagickFalse)
727 break;
728 }
729 }
cristyea1a8aa2011-10-20 13:24:06 +0000730 (void) SyncImage(image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000731 break;
732 }
733 case 4:
734 {
735 /*
736 Convert PseudoColor scanline.
737 */
cristybb503372010-05-27 20:51:26 +0000738 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +0000739 {
740 p=pixels+(image->rows-y-1)*bytes_per_line;
741 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000742 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000743 break;
cristybb503372010-05-27 20:51:26 +0000744 for (x=0; x < ((ssize_t) image->columns-1); x+=2)
cristy3ed852e2009-09-05 21:47:34 +0000745 {
cristyc82a27b2011-10-21 01:07:16 +0000746 index=ConstrainColormapIndex(image,(*p >> 4) & 0xf,exception);
cristy4c08aed2011-07-01 19:47:50 +0000747 SetPixelIndex(image,index,q);
cristyed231572011-07-14 02:18:59 +0000748 q+=GetPixelChannels(image);
cristyc82a27b2011-10-21 01:07:16 +0000749 index=ConstrainColormapIndex(image,*p & 0xf,exception);
cristy4c08aed2011-07-01 19:47:50 +0000750 SetPixelIndex(image,index,q);
cristy3ed852e2009-09-05 21:47:34 +0000751 p++;
cristyed231572011-07-14 02:18:59 +0000752 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000753 }
754 if ((image->columns % 2) != 0)
755 {
cristyc82a27b2011-10-21 01:07:16 +0000756 index=ConstrainColormapIndex(image,(*p >> 4) & 0xf,exception);
cristy4c08aed2011-07-01 19:47:50 +0000757 SetPixelIndex(image,index,q);
cristyed231572011-07-14 02:18:59 +0000758 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000759 p++;
760 }
761 if (SyncAuthenticPixels(image,exception) == MagickFalse)
762 break;
763 if (image->previous == (Image *) NULL)
764 {
765 status=SetImageProgress(image,LoadImageTag,image->rows-y-1,
766 image->rows);
767 if (status == MagickFalse)
768 break;
769 }
770 }
cristyea1a8aa2011-10-20 13:24:06 +0000771 (void) SyncImage(image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000772 break;
773 }
774 case 8:
775 {
776 /*
777 Convert PseudoColor scanline.
778 */
779 if ((dib_info.compression == BI_RLE8) ||
780 (dib_info.compression == BI_RLE4))
781 bytes_per_line=image->columns;
cristybb503372010-05-27 20:51:26 +0000782 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +0000783 {
784 p=pixels+(image->rows-y-1)*bytes_per_line;
785 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000786 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000787 break;
cristybb503372010-05-27 20:51:26 +0000788 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000789 {
cristyc82a27b2011-10-21 01:07:16 +0000790 index=ConstrainColormapIndex(image,*p,exception);
cristy4c08aed2011-07-01 19:47:50 +0000791 SetPixelIndex(image,index,q);
cristy3ed852e2009-09-05 21:47:34 +0000792 p++;
cristyed231572011-07-14 02:18:59 +0000793 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000794 }
795 if (SyncAuthenticPixels(image,exception) == MagickFalse)
796 break;
797 if (image->previous == (Image *) NULL)
798 {
799 status=SetImageProgress(image,LoadImageTag,image->rows-y-1,
800 image->rows);
801 if (status == MagickFalse)
802 break;
803 }
804 }
cristyea1a8aa2011-10-20 13:24:06 +0000805 (void) SyncImage(image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000806 break;
807 }
808 case 16:
809 {
810 unsigned short
811 word;
812
813 /*
814 Convert PseudoColor scanline.
815 */
816 image->storage_class=DirectClass;
817 if (dib_info.compression == BI_RLE8)
818 bytes_per_line=2*image->columns;
cristybb503372010-05-27 20:51:26 +0000819 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +0000820 {
821 p=pixels+(image->rows-y-1)*bytes_per_line;
822 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000823 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000824 break;
cristybb503372010-05-27 20:51:26 +0000825 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000826 {
827 word=(*p++);
828 word|=(*p++ << 8);
829 if (dib_info.red_mask == 0)
830 {
cristy4c08aed2011-07-01 19:47:50 +0000831 SetPixelRed(image,ScaleCharToQuantum(ScaleColor5to8(
832 (unsigned char) ((word >> 10) & 0x1f))),q);
833 SetPixelGreen(image,ScaleCharToQuantum(ScaleColor5to8(
834 (unsigned char) ((word >> 5) & 0x1f))),q);
835 SetPixelBlue(image,ScaleCharToQuantum(ScaleColor5to8(
836 (unsigned char) (word & 0x1f))),q);
cristy3ed852e2009-09-05 21:47:34 +0000837 }
838 else
839 {
cristy4c08aed2011-07-01 19:47:50 +0000840 SetPixelRed(image,ScaleCharToQuantum(ScaleColor5to8(
841 (unsigned char) ((word >> 11) & 0x1f))),q);
842 SetPixelGreen(image,ScaleCharToQuantum(ScaleColor6to8(
843 (unsigned char) ((word >> 5) & 0x3f))),q);
844 SetPixelBlue(image,ScaleCharToQuantum(ScaleColor5to8(
845 (unsigned char) (word & 0x1f))),q);
cristy3ed852e2009-09-05 21:47:34 +0000846 }
cristyed231572011-07-14 02:18:59 +0000847 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000848 }
849 if (SyncAuthenticPixels(image,exception) == MagickFalse)
850 break;
851 if (image->previous == (Image *) NULL)
852 {
853 status=SetImageProgress(image,LoadImageTag,image->rows-y-1,
854 image->rows);
855 if (status == MagickFalse)
856 break;
857 }
858 }
859 break;
860 }
861 case 24:
862 case 32:
863 {
864 /*
865 Convert DirectColor scanline.
866 */
cristybb503372010-05-27 20:51:26 +0000867 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +0000868 {
869 p=pixels+(image->rows-y-1)*bytes_per_line;
870 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000871 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000872 break;
cristybb503372010-05-27 20:51:26 +0000873 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000874 {
cristy4c08aed2011-07-01 19:47:50 +0000875 SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
876 SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
877 SetPixelRed(image,ScaleCharToQuantum(*p++),q);
cristy17f11b02014-12-20 19:37:04 +0000878 if (image->alpha_trait != UndefinedPixelTrait)
cristy4c08aed2011-07-01 19:47:50 +0000879 SetPixelAlpha(image,ScaleCharToQuantum(*p++),q);
cristyed231572011-07-14 02:18:59 +0000880 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000881 }
882 if (SyncAuthenticPixels(image,exception) == MagickFalse)
883 break;
884 if (image->previous == (Image *) NULL)
885 {
886 status=SetImageProgress(image,LoadImageTag,image->rows-y-1,
887 image->rows);
888 if (status == MagickFalse)
889 break;
890 }
891 }
892 break;
893 }
894 default:
895 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
896 }
cristy0553bd52013-06-30 15:53:50 +0000897 pixel_info=RelinquishVirtualMemory(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +0000898 if (EOFBlob(image) != MagickFalse)
899 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
900 image->filename);
901 if (dib_info.height < 0)
902 {
903 Image
904 *flipped_image;
905
906 /*
907 Correct image orientation.
908 */
909 flipped_image=FlipImage(image,exception);
cristybbfd4cd2010-04-13 21:54:39 +0000910 if (flipped_image != (Image *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000911 {
cristybbfd4cd2010-04-13 21:54:39 +0000912 DuplicateBlob(flipped_image,image);
913 image=DestroyImage(image);
914 image=flipped_image;
cristy3ed852e2009-09-05 21:47:34 +0000915 }
cristy3ed852e2009-09-05 21:47:34 +0000916 }
917 (void) CloseBlob(image);
918 return(GetFirstImageInList(image));
919}
920
921/*
922%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
923% %
924% %
925% %
926% R e g i s t e r D I B I m a g e %
927% %
928% %
929% %
930%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
931%
932% RegisterDIBImage() adds attributes for the DIB image format to
933% the list of supported formats. The attributes include the image format
934% tag, a method to read and/or write the format, whether the format
935% supports the saving of more than one frame to the same file or blob,
936% whether the format supports native in-memory I/O, and a brief
937% description of the format.
938%
939% The format of the RegisterDIBImage method is:
940%
cristybb503372010-05-27 20:51:26 +0000941% size_t RegisterDIBImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000942%
943*/
cristybb503372010-05-27 20:51:26 +0000944ModuleExport size_t RegisterDIBImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000945{
946 MagickInfo
947 *entry;
948
949 entry=SetMagickInfo("DIB");
950 entry->decoder=(DecodeImageHandler *) ReadDIBImage;
951 entry->encoder=(EncodeImageHandler *) WriteDIBImage;
952 entry->magick=(IsImageFormatHandler *) IsDIB;
953 entry->adjoin=MagickFalse;
954 entry->stealth=MagickTrue;
955 entry->description=ConstantString(
956 "Microsoft Windows 3.X Packed Device-Independent Bitmap");
957 entry->module=ConstantString("DIB");
958 (void) RegisterMagickInfo(entry);
959 return(MagickImageCoderSignature);
960}
961
962/*
963%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
964% %
965% %
966% %
967% U n r e g i s t e r D I B I m a g e %
968% %
969% %
970% %
971%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
972%
973% UnregisterDIBImage() removes format registrations made by the
974% DIB module from the list of supported formats.
975%
976% The format of the UnregisterDIBImage method is:
977%
978% UnregisterDIBImage(void)
979%
980*/
981ModuleExport void UnregisterDIBImage(void)
982{
983 (void) UnregisterMagickInfo("DIB");
984}
985
986/*
987%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
988% %
989% %
990% %
991% W r i t e D I B I m a g e %
992% %
993% %
994% %
995%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
996%
997% WriteDIBImage() writes an image in Microsoft Windows bitmap encoded
998% image format.
999%
1000% The format of the WriteDIBImage method is:
1001%
cristy1e178e72011-08-28 19:44:34 +00001002% MagickBooleanType WriteDIBImage(const ImageInfo *image_info,
1003% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001004%
1005% A description of each parameter follows.
1006%
1007% o image_info: the image info.
1008%
1009% o image: The image.
1010%
cristy1e178e72011-08-28 19:44:34 +00001011% o exception: return any errors or warnings in this structure.
1012%
cristy3ed852e2009-09-05 21:47:34 +00001013*/
cristy1e178e72011-08-28 19:44:34 +00001014static MagickBooleanType WriteDIBImage(const ImageInfo *image_info,Image *image,
1015 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001016{
1017 DIBInfo
1018 dib_info;
1019
cristy3ed852e2009-09-05 21:47:34 +00001020 MagickBooleanType
1021 status;
1022
cristy4c08aed2011-07-01 19:47:50 +00001023 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +00001024 *p;
1025
cristybb503372010-05-27 20:51:26 +00001026 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001027 i,
1028 x;
1029
1030 register unsigned char
1031 *q;
1032
cristyddbc41b2011-04-24 14:27:48 +00001033 size_t
1034 bytes_per_line;
1035
1036 ssize_t
1037 y;
1038
cristy3ed852e2009-09-05 21:47:34 +00001039 unsigned char
1040 *dib_data,
1041 *pixels;
1042
cristy3ed852e2009-09-05 21:47:34 +00001043 /*
1044 Open output image file.
1045 */
1046 assert(image_info != (const ImageInfo *) NULL);
1047 assert(image_info->signature == MagickSignature);
1048 assert(image != (Image *) NULL);
1049 assert(image->signature == MagickSignature);
1050 if (image->debug != MagickFalse)
1051 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy3a37efd2011-08-28 20:31:03 +00001052 assert(exception != (ExceptionInfo *) NULL);
1053 assert(exception->signature == MagickSignature);
cristy1e178e72011-08-28 19:44:34 +00001054 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00001055 if (status == MagickFalse)
1056 return(status);
1057 /*
1058 Initialize DIB raster file header.
1059 */
cristyaf8d3912014-02-21 14:50:33 +00001060 (void) TransformImageColorspace(image,sRGBColorspace,exception);
cristy3ed852e2009-09-05 21:47:34 +00001061 if (image->storage_class == DirectClass)
1062 {
1063 /*
1064 Full color DIB raster.
1065 */
1066 dib_info.number_colors=0;
cristy8a46d822012-08-28 23:32:39 +00001067 dib_info.bits_per_pixel=(unsigned short) (image->alpha_trait ? 32 : 24);
cristy3ed852e2009-09-05 21:47:34 +00001068 }
1069 else
1070 {
1071 /*
1072 Colormapped DIB raster.
1073 */
1074 dib_info.bits_per_pixel=8;
1075 if (image_info->depth > 8)
1076 dib_info.bits_per_pixel=16;
cristy1e178e72011-08-28 19:44:34 +00001077 if (IsImageMonochrome(image,exception) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001078 dib_info.bits_per_pixel=1;
1079 dib_info.number_colors=(dib_info.bits_per_pixel == 16) ? 0 :
1080 (1UL << dib_info.bits_per_pixel);
1081 }
1082 bytes_per_line=4*((image->columns*dib_info.bits_per_pixel+31)/32);
1083 dib_info.size=40;
cristybb503372010-05-27 20:51:26 +00001084 dib_info.width=(ssize_t) image->columns;
1085 dib_info.height=(ssize_t) image->rows;
cristy3ed852e2009-09-05 21:47:34 +00001086 dib_info.planes=1;
cristybb503372010-05-27 20:51:26 +00001087 dib_info.compression=(size_t) (dib_info.bits_per_pixel == 16 ?
cristy3ed852e2009-09-05 21:47:34 +00001088 BI_BITFIELDS : BI_RGB);
1089 dib_info.image_size=bytes_per_line*image->rows;
1090 dib_info.x_pixels=75*39;
1091 dib_info.y_pixels=75*39;
1092 switch (image->units)
1093 {
1094 case UndefinedResolution:
1095 case PixelsPerInchResolution:
1096 {
cristy2a11bef2011-10-28 18:33:11 +00001097 dib_info.x_pixels=(size_t) (100.0*image->resolution.x/2.54);
1098 dib_info.y_pixels=(size_t) (100.0*image->resolution.y/2.54);
cristy3ed852e2009-09-05 21:47:34 +00001099 break;
1100 }
1101 case PixelsPerCentimeterResolution:
1102 {
cristy2a11bef2011-10-28 18:33:11 +00001103 dib_info.x_pixels=(size_t) (100.0*image->resolution.x);
1104 dib_info.y_pixels=(size_t) (100.0*image->resolution.y);
cristy3ed852e2009-09-05 21:47:34 +00001105 break;
1106 }
1107 }
1108 dib_info.colors_important=dib_info.number_colors;
1109 /*
1110 Convert MIFF to DIB raster pixels.
1111 */
1112 pixels=(unsigned char *) AcquireQuantumMemory(dib_info.image_size,
1113 sizeof(*pixels));
1114 if (pixels == (unsigned char *) NULL)
1115 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1116 (void) ResetMagickMemory(pixels,0,dib_info.image_size);
1117 switch (dib_info.bits_per_pixel)
1118 {
1119 case 1:
1120 {
1121 register unsigned char
1122 bit,
1123 byte;
1124
1125 /*
1126 Convert PseudoClass image to a DIB monochrome image.
1127 */
cristybb503372010-05-27 20:51:26 +00001128 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001129 {
cristy1e178e72011-08-28 19:44:34 +00001130 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001131 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001132 break;
cristy3ed852e2009-09-05 21:47:34 +00001133 q=pixels+(image->rows-y-1)*bytes_per_line;
1134 bit=0;
1135 byte=0;
cristybb503372010-05-27 20:51:26 +00001136 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001137 {
1138 byte<<=1;
cristy4c08aed2011-07-01 19:47:50 +00001139 byte|=GetPixelIndex(image,p) != 0 ? 0x01 : 0x00;
cristy3ed852e2009-09-05 21:47:34 +00001140 bit++;
1141 if (bit == 8)
1142 {
1143 *q++=byte;
1144 bit=0;
1145 byte=0;
1146 }
cristyed231572011-07-14 02:18:59 +00001147 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001148 }
1149 if (bit != 0)
1150 {
1151 *q++=(unsigned char) (byte << (8-bit));
1152 x++;
1153 }
cristybb503372010-05-27 20:51:26 +00001154 for (x=(ssize_t) (image->columns+7)/8; x < (ssize_t) bytes_per_line; x++)
cristy3ed852e2009-09-05 21:47:34 +00001155 *q++=0x00;
cristycee97112010-05-28 00:44:52 +00001156 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
cristyddbc41b2011-04-24 14:27:48 +00001157 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001158 if (status == MagickFalse)
1159 break;
1160 }
1161 break;
1162 }
1163 case 8:
1164 {
1165 /*
1166 Convert PseudoClass packet to DIB pixel.
1167 */
cristybb503372010-05-27 20:51:26 +00001168 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001169 {
cristy1e178e72011-08-28 19:44:34 +00001170 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001171 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001172 break;
cristy3ed852e2009-09-05 21:47:34 +00001173 q=pixels+(image->rows-y-1)*bytes_per_line;
cristybb503372010-05-27 20:51:26 +00001174 for (x=0; x < (ssize_t) image->columns; x++)
cristy4c08aed2011-07-01 19:47:50 +00001175 {
1176 *q++=(unsigned char) GetPixelIndex(image,p);
cristyed231572011-07-14 02:18:59 +00001177 p+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00001178 }
cristybb503372010-05-27 20:51:26 +00001179 for ( ; x < (ssize_t) bytes_per_line; x++)
cristy3ed852e2009-09-05 21:47:34 +00001180 *q++=0x00;
cristycee97112010-05-28 00:44:52 +00001181 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
cristyddbc41b2011-04-24 14:27:48 +00001182 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001183 if (status == MagickFalse)
1184 break;
1185 }
1186 break;
1187 }
1188 case 16:
1189 {
1190 unsigned short
1191 word;
1192 /*
1193 Convert PseudoClass packet to DIB pixel.
1194 */
cristybb503372010-05-27 20:51:26 +00001195 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001196 {
cristy1e178e72011-08-28 19:44:34 +00001197 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001198 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001199 break;
1200 q=pixels+(image->rows-y-1)*bytes_per_line;
cristybb503372010-05-27 20:51:26 +00001201 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001202 {
1203 word=(unsigned short) ((ScaleColor8to5((unsigned char)
cristy4c08aed2011-07-01 19:47:50 +00001204 ScaleQuantumToChar(GetPixelRed(image,p))) << 11) | (ScaleColor8to6(
1205 (unsigned char) ScaleQuantumToChar(GetPixelGreen(image,p))) << 5) |
1206 (ScaleColor8to5((unsigned char) ScaleQuantumToChar((unsigned char)
1207 GetPixelBlue(image,p)) << 0)));
cristy3ed852e2009-09-05 21:47:34 +00001208 *q++=(unsigned char)(word & 0xff);
1209 *q++=(unsigned char)(word >> 8);
cristyed231572011-07-14 02:18:59 +00001210 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001211 }
cristyf6fe0a12010-05-30 00:44:47 +00001212 for (x=(ssize_t) (2*image->columns); x < (ssize_t) bytes_per_line; x++)
cristy3ed852e2009-09-05 21:47:34 +00001213 *q++=0x00;
cristycee97112010-05-28 00:44:52 +00001214 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
cristyddbc41b2011-04-24 14:27:48 +00001215 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001216 if (status == MagickFalse)
1217 break;
1218 }
1219 break;
1220 }
1221 case 24:
1222 case 32:
1223 {
1224 /*
1225 Convert DirectClass packet to DIB RGB pixel.
1226 */
cristybb503372010-05-27 20:51:26 +00001227 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001228 {
cristy1e178e72011-08-28 19:44:34 +00001229 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001230 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001231 break;
1232 q=pixels+(image->rows-y-1)*bytes_per_line;
cristybb503372010-05-27 20:51:26 +00001233 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001234 {
cristy4c08aed2011-07-01 19:47:50 +00001235 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
1236 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
1237 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
cristy17f11b02014-12-20 19:37:04 +00001238 if (image->alpha_trait != UndefinedPixelTrait)
cristy4c08aed2011-07-01 19:47:50 +00001239 *q++=ScaleQuantumToChar(GetPixelAlpha(image,p));
cristyed231572011-07-14 02:18:59 +00001240 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001241 }
1242 if (dib_info.bits_per_pixel == 24)
cristyf6fe0a12010-05-30 00:44:47 +00001243 for (x=(ssize_t) (3*image->columns); x < (ssize_t) bytes_per_line; x++)
cristy3ed852e2009-09-05 21:47:34 +00001244 *q++=0x00;
cristycee97112010-05-28 00:44:52 +00001245 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
cristyddbc41b2011-04-24 14:27:48 +00001246 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001247 if (status == MagickFalse)
1248 break;
1249 }
1250 break;
1251 }
1252 }
1253 if (dib_info.bits_per_pixel == 8)
1254 if (image_info->compression != NoCompression)
1255 {
1256 size_t
1257 length;
1258
1259 /*
1260 Convert run-length encoded raster pixels.
1261 */
1262 length=2UL*(bytes_per_line+2UL)+2UL;
1263 dib_data=(unsigned char *) AcquireQuantumMemory(length,
1264 (image->rows+2UL)*sizeof(*dib_data));
cristy4d0ca342014-05-01 00:42:09 +00001265 if (dib_data == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001266 {
1267 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1268 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1269 }
cristybb503372010-05-27 20:51:26 +00001270 dib_info.image_size=(size_t) EncodeImage(image,bytes_per_line,
cristy3ed852e2009-09-05 21:47:34 +00001271 pixels,dib_data);
1272 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1273 pixels=dib_data;
1274 dib_info.compression = BI_RLE8;
1275 }
1276 /*
1277 Write DIB header.
1278 */
cristyf6fe0a12010-05-30 00:44:47 +00001279 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.size);
cristyeaedf062010-05-29 22:36:02 +00001280 (void) WriteBlobLSBLong(image,dib_info.width);
cristy3ed852e2009-09-05 21:47:34 +00001281 (void) WriteBlobLSBLong(image,(unsigned short) dib_info.height);
1282 (void) WriteBlobLSBShort(image,(unsigned short) dib_info.planes);
1283 (void) WriteBlobLSBShort(image,dib_info.bits_per_pixel);
cristyf6fe0a12010-05-30 00:44:47 +00001284 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.compression);
1285 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.image_size);
1286 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.x_pixels);
1287 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.y_pixels);
1288 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.number_colors);
1289 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.colors_important);
cristy3ed852e2009-09-05 21:47:34 +00001290 if (image->storage_class == PseudoClass)
1291 {
1292 if (dib_info.bits_per_pixel <= 8)
1293 {
1294 unsigned char
1295 *dib_colormap;
1296
1297 /*
1298 Dump colormap to file.
1299 */
1300 dib_colormap=(unsigned char *) AcquireQuantumMemory((size_t)
cristy4d0ca342014-05-01 00:42:09 +00001301 (1UL << dib_info.bits_per_pixel),4*sizeof(*dib_colormap));
cristy3ed852e2009-09-05 21:47:34 +00001302 if (dib_colormap == (unsigned char *) NULL)
1303 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1304 q=dib_colormap;
cristybb503372010-05-27 20:51:26 +00001305 for (i=0; i < (ssize_t) MagickMin(image->colors,dib_info.number_colors); i++)
cristy3ed852e2009-09-05 21:47:34 +00001306 {
1307 *q++=ScaleQuantumToChar(image->colormap[i].blue);
1308 *q++=ScaleQuantumToChar(image->colormap[i].green);
1309 *q++=ScaleQuantumToChar(image->colormap[i].red);
1310 *q++=(Quantum) 0x0;
1311 }
cristybb503372010-05-27 20:51:26 +00001312 for ( ; i < (ssize_t) (1L << dib_info.bits_per_pixel); i++)
cristy3ed852e2009-09-05 21:47:34 +00001313 {
1314 *q++=(Quantum) 0x0;
1315 *q++=(Quantum) 0x0;
1316 *q++=(Quantum) 0x0;
1317 *q++=(Quantum) 0x0;
1318 }
1319 (void) WriteBlob(image,(size_t) (4*(1 << dib_info.bits_per_pixel)),
1320 dib_colormap);
1321 dib_colormap=(unsigned char *) RelinquishMagickMemory(dib_colormap);
1322 }
1323 else
1324 if ((dib_info.bits_per_pixel == 16) &&
1325 (dib_info.compression == BI_BITFIELDS))
1326 {
1327 (void) WriteBlobLSBLong(image,0xf800);
1328 (void) WriteBlobLSBLong(image,0x07e0);
1329 (void) WriteBlobLSBLong(image,0x001f);
1330 }
1331 }
1332 (void) WriteBlob(image,dib_info.image_size,pixels);
1333 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1334 (void) CloseBlob(image);
1335 return(MagickTrue);
1336}