blob: 9d735a47626aa39ed0e6985bbb8ff94e4815ef12 [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*/
cristy3ed852e2009-09-05 21:47:34 +0000146static MagickBooleanType DecodeImage(Image *image,
147 const MagickBooleanType compression,unsigned char *pixels)
148{
cristy07a3cca2012-12-10 13:09:10 +0000149#if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__MINGW32__) || defined(__MINGW64__)
cristy3ed852e2009-09-05 21:47:34 +0000150#define BI_RGB 0
151#define BI_RLE8 1
152#define BI_RLE4 2
153#define BI_BITFIELDS 3
cristyf8dcd772014-12-19 12:11:44 +0000154#undef BI_JPEG
155#define BI_JPEG 4
156#undef BI_PNG
157#define BI_PNG 5
cristy3ed852e2009-09-05 21:47:34 +0000158#endif
159
160 int
161 count;
162
cristybb503372010-05-27 20:51:26 +0000163 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000164 y;
165
cristybb503372010-05-27 20:51:26 +0000166 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000167 i,
168 x;
169
170 register unsigned char
171 *p,
172 *q;
173
174 unsigned char
175 byte;
176
177 assert(image != (Image *) NULL);
178 assert(image->signature == MagickSignature);
179 if (image->debug != MagickFalse)
180 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
181 assert(pixels != (unsigned char *) NULL);
182 (void) ResetMagickMemory(pixels,0,(size_t) image->columns*image->rows*
183 sizeof(*pixels));
184 byte=0;
185 x=0;
186 p=pixels;
187 q=pixels+(size_t) image->columns*image->rows;
cristybb503372010-05-27 20:51:26 +0000188 for (y=0; y < (ssize_t) image->rows; )
cristy3ed852e2009-09-05 21:47:34 +0000189 {
190 if ((p < pixels) || (p >= q))
191 break;
192 count=ReadBlobByte(image);
193 if (count == EOF)
194 break;
195 if (count != 0)
196 {
197 count=(int) MagickMin((size_t) count,(size_t) (q-p));
198 /*
199 Encoded mode.
200 */
201 byte=(unsigned char) ReadBlobByte(image);
202 if (compression == BI_RLE8)
203 {
204 for (i=0; i < count; i++)
205 *p++=(unsigned char) byte;
206 }
207 else
208 {
209 for (i=0; i < count; i++)
210 *p++=(unsigned char)
211 ((i & 0x01) != 0 ? (byte & 0x0f) : ((byte >> 4) & 0x0f));
212 }
213 x+=count;
214 }
215 else
216 {
217 /*
218 Escape mode.
219 */
220 count=ReadBlobByte(image);
221 if (count == 0x01)
222 return(MagickTrue);
223 switch (count)
224 {
225 case 0x00:
226 {
227 /*
228 End of line.
229 */
230 x=0;
231 y++;
232 p=pixels+y*image->columns;
233 break;
234 }
235 case 0x02:
236 {
237 /*
238 Delta mode.
239 */
240 x+=ReadBlobByte(image);
241 y+=ReadBlobByte(image);
242 p=pixels+y*image->columns+x;
243 break;
244 }
245 default:
246 {
247 /*
248 Absolute mode.
249 */
250 count=(int) MagickMin((size_t) count,(size_t) (q-p));
251 if (compression == BI_RLE8)
252 for (i=0; i < count; i++)
253 *p++=(unsigned char) ReadBlobByte(image);
254 else
255 for (i=0; i < count; i++)
256 {
257 if ((i & 0x01) == 0)
258 byte=(unsigned char) ReadBlobByte(image);
259 *p++=(unsigned char)
260 ((i & 0x01) != 0 ? (byte & 0x0f) : ((byte >> 4) & 0x0f));
261 }
262 x+=count;
263 /*
264 Read pad byte.
265 */
266 if (compression == BI_RLE8)
267 {
268 if ((count & 0x01) != 0)
269 (void) ReadBlobByte(image);
270 }
271 else
272 if (((count & 0x03) == 1) || ((count & 0x03) == 2))
273 (void) ReadBlobByte(image);
274 break;
275 }
276 }
277 }
278 if (SetImageProgress(image,LoadImageTag,y,image->rows) == MagickFalse)
279 break;
280 }
281 (void) ReadBlobByte(image); /* end of line */
282 (void) ReadBlobByte(image);
283 return(MagickTrue);
284}
285
286/*
287%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
288% %
289% %
290% %
291% E n c o d e I m a g e %
292% %
293% %
294% %
295%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
296%
297% EncodeImage compresses pixels using a runlength encoded format.
298%
299% The format of the EncodeImage method is:
300%
301% static MagickBooleanType EncodeImage(Image *image,
cristybb503372010-05-27 20:51:26 +0000302% const size_t bytes_per_line,const unsigned char *pixels,
cristy3ed852e2009-09-05 21:47:34 +0000303% unsigned char *compressed_pixels)
304%
305% A description of each parameter follows:
306%
307% o image: The image.
308%
309% o bytes_per_line: the number of bytes in a scanline of compressed pixels
310%
311% o pixels: The address of a byte (8 bits) array of pixel data created by
312% the compression process.
313%
314% o compressed_pixels: The address of a byte (8 bits) array of compressed
315% pixel data.
316%
317*/
cristybb503372010-05-27 20:51:26 +0000318static size_t EncodeImage(Image *image,const size_t bytes_per_line,
cristy3ed852e2009-09-05 21:47:34 +0000319 const unsigned char *pixels,unsigned char *compressed_pixels)
320{
cristybb503372010-05-27 20:51:26 +0000321 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000322 y;
323
324 register const unsigned char
325 *p;
326
cristybb503372010-05-27 20:51:26 +0000327 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000328 i,
329 x;
330
331 register unsigned char
332 *q;
333
334 /*
335 Runlength encode pixels.
336 */
337 assert(image != (Image *) NULL);
338 assert(image->signature == MagickSignature);
339 if (image->debug != MagickFalse)
340 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
341 assert(pixels != (const unsigned char *) NULL);
342 assert(compressed_pixels != (unsigned char *) NULL);
343 p=pixels;
344 q=compressed_pixels;
345 i=0;
cristybb503372010-05-27 20:51:26 +0000346 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000347 {
cristybb503372010-05-27 20:51:26 +0000348 for (x=0; x < (ssize_t) bytes_per_line; x+=i)
cristy3ed852e2009-09-05 21:47:34 +0000349 {
350 /*
351 Determine runlength.
352 */
cristybb503372010-05-27 20:51:26 +0000353 for (i=1; ((x+i) < (ssize_t) bytes_per_line); i++)
cristy3ed852e2009-09-05 21:47:34 +0000354 if ((*(p+i) != *p) || (i == 255))
355 break;
356 *q++=(unsigned char) i;
357 *q++=(*p);
358 p+=i;
359 }
360 /*
361 End of line.
362 */
363 *q++=0x00;
364 *q++=0x00;
365 if (SetImageProgress(image,LoadImageTag,y,image->rows) == MagickFalse)
366 break;
367 }
368 /*
369 End of bitmap.
370 */
371 *q++=0;
372 *q++=0x01;
373 return((size_t) (q-compressed_pixels));
374}
375
376/*
377%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
378% %
379% %
380% %
381% I s D I B %
382% %
383% %
384% %
385%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
386%
387% IsDIB() returns MagickTrue if the image format type, identified by the
388% magick string, is DIB.
389%
390% The format of the IsDIB method is:
391%
392% MagickBooleanType IsDIB(const unsigned char *magick,const size_t length)
393%
394% A description of each parameter follows:
395%
396% o magick: compare image format pattern against these bytes.
397%
398% o length: Specifies the length of the magick string.
399%
400*/
401static MagickBooleanType IsDIB(const unsigned char *magick,const size_t length)
402{
403 if (length < 2)
404 return(MagickFalse);
405 if (memcmp(magick,"\050\000",2) == 0)
406 return(MagickTrue);
407 return(MagickFalse);
408}
409
410/*
411%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
412% %
413% %
414% %
415% R e a d D I B I m a g e %
416% %
417% %
418% %
419%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
420%
421% ReadDIBImage() reads a Microsoft Windows bitmap image file and
422% returns it. It allocates the memory necessary for the new Image structure
423% and returns a pointer to the new image.
424%
425% The format of the ReadDIBImage method is:
426%
427% image=ReadDIBImage(image_info)
428%
429% A description of each parameter follows:
430%
431% o image_info: the image info.
432%
433% o exception: return any errors or warnings in this structure.
434%
435*/
cristy3ed852e2009-09-05 21:47:34 +0000436static Image *ReadDIBImage(const ImageInfo *image_info,ExceptionInfo *exception)
437{
438 DIBInfo
439 dib_info;
440
441 Image
442 *image;
443
cristy3ed852e2009-09-05 21:47:34 +0000444 MagickBooleanType
445 status;
446
cristy0553bd52013-06-30 15:53:50 +0000447 MemoryInfo
448 *pixel_info;
449
cristy4c08aed2011-07-01 19:47:50 +0000450 Quantum
451 index;
cristy3ed852e2009-09-05 21:47:34 +0000452
cristybb503372010-05-27 20:51:26 +0000453 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000454 x;
455
cristy4c08aed2011-07-01 19:47:50 +0000456 register Quantum
cristy3ed852e2009-09-05 21:47:34 +0000457 *q;
458
cristybb503372010-05-27 20:51:26 +0000459 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000460 i;
461
462 register unsigned char
463 *p;
464
465 size_t
cristyddbc41b2011-04-24 14:27:48 +0000466 bytes_per_line,
cristy3ed852e2009-09-05 21:47:34 +0000467 length;
468
469 ssize_t
cristy4c08aed2011-07-01 19:47:50 +0000470 bit,
471 count,
472 y;
473
cristy3ed852e2009-09-05 21:47:34 +0000474
475 unsigned char
476 *pixels;
477
cristy3ed852e2009-09-05 21:47:34 +0000478 /*
479 Open image file.
480 */
481 assert(image_info != (const ImageInfo *) NULL);
482 assert(image_info->signature == MagickSignature);
483 if (image_info->debug != MagickFalse)
484 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
485 image_info->filename);
486 assert(exception != (ExceptionInfo *) NULL);
487 assert(exception->signature == MagickSignature);
cristy9950d572011-10-01 18:22:35 +0000488 image=AcquireImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +0000489 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
490 if (status == MagickFalse)
491 {
492 image=DestroyImageList(image);
493 return((Image *) NULL);
494 }
495 /*
496 Determine if this a DIB file.
497 */
498 (void) ResetMagickMemory(&dib_info,0,sizeof(dib_info));
499 dib_info.size=ReadBlobLSBLong(image);
cristyacabb842014-12-14 23:36:33 +0000500 if (dib_info.size != 40)
cristy3ed852e2009-09-05 21:47:34 +0000501 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
502 /*
503 Microsoft Windows 3.X DIB image file.
504 */
505 dib_info.width=(short) ReadBlobLSBLong(image);
506 dib_info.height=(short) ReadBlobLSBLong(image);
507 dib_info.planes=ReadBlobLSBShort(image);
508 dib_info.bits_per_pixel=ReadBlobLSBShort(image);
cristyf8dcd772014-12-19 12:11:44 +0000509 if (dib_info.bits_per_pixel > 32)
510 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
cristy3ed852e2009-09-05 21:47:34 +0000511 dib_info.compression=ReadBlobLSBLong(image);
512 dib_info.image_size=ReadBlobLSBLong(image);
513 dib_info.x_pixels=ReadBlobLSBLong(image);
514 dib_info.y_pixels=ReadBlobLSBLong(image);
515 dib_info.number_colors=ReadBlobLSBLong(image);
516 dib_info.colors_important=ReadBlobLSBLong(image);
517 if ((dib_info.compression == BI_BITFIELDS) &&
518 ((dib_info.bits_per_pixel == 16) || (dib_info.bits_per_pixel == 32)))
519 {
520 dib_info.red_mask=ReadBlobLSBLong(image);
521 dib_info.green_mask=ReadBlobLSBLong(image);
522 dib_info.blue_mask=ReadBlobLSBLong(image);
523 }
cristyf8dcd772014-12-19 12:11:44 +0000524 if (dib_info.width <= 0)
525 ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize");
526 if (dib_info.height == 0)
527 ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize");
528 if (dib_info.planes != 1)
529 ThrowReaderException(CorruptImageError,"StaticPlanesValueNotEqualToOne");
530 if ((dib_info.bits_per_pixel != 1) && (dib_info.bits_per_pixel != 4) &&
531 (dib_info.bits_per_pixel != 8) && (dib_info.bits_per_pixel != 16) &&
532 (dib_info.bits_per_pixel != 24) && (dib_info.bits_per_pixel != 32))
533 ThrowReaderException(CorruptImageError,"UnrecognizedBitsPerPixel");
534 if (dib_info.bits_per_pixel < 16 &&
535 dib_info.number_colors > (1U << dib_info.bits_per_pixel))
536 ThrowReaderException(CorruptImageError,"UnrecognizedNumberOfColors");
537 if ((dib_info.compression == 1) && (dib_info.bits_per_pixel != 8))
538 ThrowReaderException(CorruptImageError,"UnrecognizedBitsPerPixel");
539 if ((dib_info.compression == 2) && (dib_info.bits_per_pixel != 4))
540 ThrowReaderException(CorruptImageError,"UnrecognizedBitsPerPixel");
541 if ((dib_info.compression == 3) && (dib_info.bits_per_pixel < 16))
542 ThrowReaderException(CorruptImageError,"UnrecognizedBitsPerPixel");
543 switch (dib_info.compression)
544 {
545 case BI_RGB:
546 case BI_RLE8:
547 case BI_RLE4:
548 case BI_BITFIELDS:
549 break;
550 case BI_JPEG:
551 ThrowReaderException(CoderError,"JPEGCompressNotSupported");
552 case BI_PNG:
553 ThrowReaderException(CoderError,"PNGCompressNotSupported");
554 default:
555 ThrowReaderException(CorruptImageError,"UnrecognizedImageCompression");
556 }
cristybb503372010-05-27 20:51:26 +0000557 image->columns=(size_t) MagickAbsoluteValue(dib_info.width);
558 image->rows=(size_t) MagickAbsoluteValue(dib_info.height);
cristy3ed852e2009-09-05 21:47:34 +0000559 image->depth=8;
cristyf8dcd772014-12-19 12:11:44 +0000560 image->alpha_trait=dib_info.bits_per_pixel == 32 ? BlendPixelTrait :
561 UndefinedPixelTrait;
cristy3ed852e2009-09-05 21:47:34 +0000562 if ((dib_info.number_colors != 0) || (dib_info.bits_per_pixel < 16))
563 {
cristyeaedf062010-05-29 22:36:02 +0000564 size_t
565 one;
566
cristy3ed852e2009-09-05 21:47:34 +0000567 image->storage_class=PseudoClass;
568 image->colors=dib_info.number_colors;
cristyeaedf062010-05-29 22:36:02 +0000569 one=1;
cristy3ed852e2009-09-05 21:47:34 +0000570 if (image->colors == 0)
cristyeaedf062010-05-29 22:36:02 +0000571 image->colors=one << dib_info.bits_per_pixel;
cristy3ed852e2009-09-05 21:47:34 +0000572 }
573 if (image_info->size)
574 {
575 RectangleInfo
576 geometry;
577
578 MagickStatusType
579 flags;
580
581 flags=ParseAbsoluteGeometry(image_info->size,&geometry);
582 if (flags & WidthValue)
583 if ((geometry.width != 0) && (geometry.width < image->columns))
584 image->columns=geometry.width;
585 if (flags & HeightValue)
586 if ((geometry.height != 0) && (geometry.height < image->rows))
587 image->rows=geometry.height;
588 }
cristyacabb842014-12-14 23:36:33 +0000589 status=SetImageExtent(image,image->columns,image->rows,exception);
590 if (status == MagickFalse)
591 return(DestroyImageList(image));
cristy3ed852e2009-09-05 21:47:34 +0000592 if (image->storage_class == PseudoClass)
593 {
594 size_t
595 length,
596 packet_size;
597
598 unsigned char
599 *dib_colormap;
600
601 /*
602 Read DIB raster colormap.
603 */
cristy018f07f2011-09-04 21:15:19 +0000604 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000605 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
606 length=(size_t) image->colors;
607 dib_colormap=(unsigned char *) AcquireQuantumMemory(length,
608 4*sizeof(*dib_colormap));
609 if (dib_colormap == (unsigned char *) NULL)
610 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
611 packet_size=4;
612 count=ReadBlob(image,packet_size*image->colors,dib_colormap);
613 if (count != (ssize_t) (packet_size*image->colors))
614 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
615 p=dib_colormap;
cristybb503372010-05-27 20:51:26 +0000616 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +0000617 {
618 image->colormap[i].blue=ScaleCharToQuantum(*p++);
619 image->colormap[i].green=ScaleCharToQuantum(*p++);
620 image->colormap[i].red=ScaleCharToQuantum(*p++);
621 if (packet_size == 4)
622 p++;
623 }
624 dib_colormap=(unsigned char *) RelinquishMagickMemory(dib_colormap);
625 }
626 /*
627 Read image data.
628 */
629 if (dib_info.compression == BI_RLE4)
630 dib_info.bits_per_pixel<<=1;
631 bytes_per_line=4*((image->columns*dib_info.bits_per_pixel+31)/32);
632 length=bytes_per_line*image->rows;
cristy0553bd52013-06-30 15:53:50 +0000633 pixel_info=AcquireVirtualMemory((size_t) image->rows,MagickMax(
634 bytes_per_line,image->columns+256UL)*sizeof(*pixels));
635 if (pixel_info == (MemoryInfo *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000636 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
cristy0553bd52013-06-30 15:53:50 +0000637 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +0000638 if ((dib_info.compression == BI_RGB) ||
639 (dib_info.compression == BI_BITFIELDS))
640 {
641 count=ReadBlob(image,length,pixels);
642 if (count != (ssize_t) (length))
643 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
644 }
645 else
646 {
647 /*
648 Convert run-length encoded raster pixels.
649 */
650 status=DecodeImage(image,dib_info.compression ? MagickTrue : MagickFalse,
651 pixels);
652 if (status == MagickFalse)
653 ThrowReaderException(CorruptImageError,"UnableToRunlengthDecodeImage");
654 }
655 /*
656 Initialize image structure.
657 */
658 image->units=PixelsPerCentimeterResolution;
cristy2a11bef2011-10-28 18:33:11 +0000659 image->resolution.x=(double) dib_info.x_pixels/100.0;
660 image->resolution.y=(double) dib_info.y_pixels/100.0;
cristy3ed852e2009-09-05 21:47:34 +0000661 /*
662 Convert DIB raster image to pixel packets.
663 */
664 switch (dib_info.bits_per_pixel)
665 {
666 case 1:
667 {
668 /*
669 Convert bitmap scanline.
670 */
cristybb503372010-05-27 20:51:26 +0000671 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +0000672 {
673 p=pixels+(image->rows-y-1)*bytes_per_line;
674 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000675 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000676 break;
cristybb503372010-05-27 20:51:26 +0000677 for (x=0; x < ((ssize_t) image->columns-7); x+=8)
cristy3ed852e2009-09-05 21:47:34 +0000678 {
679 for (bit=0; bit < 8; bit++)
680 {
cristy4c08aed2011-07-01 19:47:50 +0000681 index=(Quantum) ((*p) & (0x80 >> bit) ? 0x01 : 0x00);
682 SetPixelIndex(image,index,q);
cristyed231572011-07-14 02:18:59 +0000683 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000684 }
685 p++;
686 }
687 if ((image->columns % 8) != 0)
688 {
cristybb503372010-05-27 20:51:26 +0000689 for (bit=0; bit < (ssize_t) (image->columns % 8); bit++)
cristy3ed852e2009-09-05 21:47:34 +0000690 {
cristy4c08aed2011-07-01 19:47:50 +0000691 index=(Quantum) ((*p) & (0x80 >> bit) ? 0x01 : 0x00);
692 SetPixelIndex(image,index,q);
cristyed231572011-07-14 02:18:59 +0000693 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000694 }
695 p++;
696 }
697 if (SyncAuthenticPixels(image,exception) == MagickFalse)
698 break;
699 if (image->previous == (Image *) NULL)
700 {
701 status=SetImageProgress(image,LoadImageTag,image->rows-y-1,
702 image->rows);
703 if (status == MagickFalse)
704 break;
705 }
706 }
cristyea1a8aa2011-10-20 13:24:06 +0000707 (void) SyncImage(image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000708 break;
709 }
710 case 4:
711 {
712 /*
713 Convert PseudoColor scanline.
714 */
cristybb503372010-05-27 20:51:26 +0000715 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +0000716 {
717 p=pixels+(image->rows-y-1)*bytes_per_line;
718 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000719 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000720 break;
cristybb503372010-05-27 20:51:26 +0000721 for (x=0; x < ((ssize_t) image->columns-1); x+=2)
cristy3ed852e2009-09-05 21:47:34 +0000722 {
cristyc82a27b2011-10-21 01:07:16 +0000723 index=ConstrainColormapIndex(image,(*p >> 4) & 0xf,exception);
cristy4c08aed2011-07-01 19:47:50 +0000724 SetPixelIndex(image,index,q);
cristyed231572011-07-14 02:18:59 +0000725 q+=GetPixelChannels(image);
cristyc82a27b2011-10-21 01:07:16 +0000726 index=ConstrainColormapIndex(image,*p & 0xf,exception);
cristy4c08aed2011-07-01 19:47:50 +0000727 SetPixelIndex(image,index,q);
cristy3ed852e2009-09-05 21:47:34 +0000728 p++;
cristyed231572011-07-14 02:18:59 +0000729 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000730 }
731 if ((image->columns % 2) != 0)
732 {
cristyc82a27b2011-10-21 01:07:16 +0000733 index=ConstrainColormapIndex(image,(*p >> 4) & 0xf,exception);
cristy4c08aed2011-07-01 19:47:50 +0000734 SetPixelIndex(image,index,q);
cristyed231572011-07-14 02:18:59 +0000735 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000736 p++;
737 }
738 if (SyncAuthenticPixels(image,exception) == MagickFalse)
739 break;
740 if (image->previous == (Image *) NULL)
741 {
742 status=SetImageProgress(image,LoadImageTag,image->rows-y-1,
743 image->rows);
744 if (status == MagickFalse)
745 break;
746 }
747 }
cristyea1a8aa2011-10-20 13:24:06 +0000748 (void) SyncImage(image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000749 break;
750 }
751 case 8:
752 {
753 /*
754 Convert PseudoColor scanline.
755 */
756 if ((dib_info.compression == BI_RLE8) ||
757 (dib_info.compression == BI_RLE4))
758 bytes_per_line=image->columns;
cristybb503372010-05-27 20:51:26 +0000759 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +0000760 {
761 p=pixels+(image->rows-y-1)*bytes_per_line;
762 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000763 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000764 break;
cristybb503372010-05-27 20:51:26 +0000765 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000766 {
cristyc82a27b2011-10-21 01:07:16 +0000767 index=ConstrainColormapIndex(image,*p,exception);
cristy4c08aed2011-07-01 19:47:50 +0000768 SetPixelIndex(image,index,q);
cristy3ed852e2009-09-05 21:47:34 +0000769 p++;
cristyed231572011-07-14 02:18:59 +0000770 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000771 }
772 if (SyncAuthenticPixels(image,exception) == MagickFalse)
773 break;
774 if (image->previous == (Image *) NULL)
775 {
776 status=SetImageProgress(image,LoadImageTag,image->rows-y-1,
777 image->rows);
778 if (status == MagickFalse)
779 break;
780 }
781 }
cristyea1a8aa2011-10-20 13:24:06 +0000782 (void) SyncImage(image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000783 break;
784 }
785 case 16:
786 {
787 unsigned short
788 word;
789
790 /*
791 Convert PseudoColor scanline.
792 */
793 image->storage_class=DirectClass;
794 if (dib_info.compression == BI_RLE8)
795 bytes_per_line=2*image->columns;
cristybb503372010-05-27 20:51:26 +0000796 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +0000797 {
798 p=pixels+(image->rows-y-1)*bytes_per_line;
799 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000800 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000801 break;
cristybb503372010-05-27 20:51:26 +0000802 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000803 {
804 word=(*p++);
805 word|=(*p++ << 8);
806 if (dib_info.red_mask == 0)
807 {
cristy4c08aed2011-07-01 19:47:50 +0000808 SetPixelRed(image,ScaleCharToQuantum(ScaleColor5to8(
809 (unsigned char) ((word >> 10) & 0x1f))),q);
810 SetPixelGreen(image,ScaleCharToQuantum(ScaleColor5to8(
811 (unsigned char) ((word >> 5) & 0x1f))),q);
812 SetPixelBlue(image,ScaleCharToQuantum(ScaleColor5to8(
813 (unsigned char) (word & 0x1f))),q);
cristy3ed852e2009-09-05 21:47:34 +0000814 }
815 else
816 {
cristy4c08aed2011-07-01 19:47:50 +0000817 SetPixelRed(image,ScaleCharToQuantum(ScaleColor5to8(
818 (unsigned char) ((word >> 11) & 0x1f))),q);
819 SetPixelGreen(image,ScaleCharToQuantum(ScaleColor6to8(
820 (unsigned char) ((word >> 5) & 0x3f))),q);
821 SetPixelBlue(image,ScaleCharToQuantum(ScaleColor5to8(
822 (unsigned char) (word & 0x1f))),q);
cristy3ed852e2009-09-05 21:47:34 +0000823 }
cristyed231572011-07-14 02:18:59 +0000824 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000825 }
826 if (SyncAuthenticPixels(image,exception) == MagickFalse)
827 break;
828 if (image->previous == (Image *) NULL)
829 {
830 status=SetImageProgress(image,LoadImageTag,image->rows-y-1,
831 image->rows);
832 if (status == MagickFalse)
833 break;
834 }
835 }
836 break;
837 }
838 case 24:
839 case 32:
840 {
841 /*
842 Convert DirectColor scanline.
843 */
cristybb503372010-05-27 20:51:26 +0000844 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +0000845 {
846 p=pixels+(image->rows-y-1)*bytes_per_line;
847 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000848 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000849 break;
cristybb503372010-05-27 20:51:26 +0000850 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000851 {
cristy4c08aed2011-07-01 19:47:50 +0000852 SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
853 SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
854 SetPixelRed(image,ScaleCharToQuantum(*p++),q);
cristy17f11b02014-12-20 19:37:04 +0000855 if (image->alpha_trait != UndefinedPixelTrait)
cristy4c08aed2011-07-01 19:47:50 +0000856 SetPixelAlpha(image,ScaleCharToQuantum(*p++),q);
cristyed231572011-07-14 02:18:59 +0000857 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000858 }
859 if (SyncAuthenticPixels(image,exception) == MagickFalse)
860 break;
861 if (image->previous == (Image *) NULL)
862 {
863 status=SetImageProgress(image,LoadImageTag,image->rows-y-1,
864 image->rows);
865 if (status == MagickFalse)
866 break;
867 }
868 }
869 break;
870 }
871 default:
872 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
873 }
cristy0553bd52013-06-30 15:53:50 +0000874 pixel_info=RelinquishVirtualMemory(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +0000875 if (EOFBlob(image) != MagickFalse)
876 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
877 image->filename);
878 if (dib_info.height < 0)
879 {
880 Image
881 *flipped_image;
882
883 /*
884 Correct image orientation.
885 */
886 flipped_image=FlipImage(image,exception);
cristybbfd4cd2010-04-13 21:54:39 +0000887 if (flipped_image != (Image *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000888 {
cristybbfd4cd2010-04-13 21:54:39 +0000889 DuplicateBlob(flipped_image,image);
890 image=DestroyImage(image);
891 image=flipped_image;
cristy3ed852e2009-09-05 21:47:34 +0000892 }
cristy3ed852e2009-09-05 21:47:34 +0000893 }
894 (void) CloseBlob(image);
895 return(GetFirstImageInList(image));
896}
897
898/*
899%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
900% %
901% %
902% %
903% R e g i s t e r D I B I m a g e %
904% %
905% %
906% %
907%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
908%
909% RegisterDIBImage() adds attributes for the DIB image format to
910% the list of supported formats. The attributes include the image format
911% tag, a method to read and/or write the format, whether the format
912% supports the saving of more than one frame to the same file or blob,
913% whether the format supports native in-memory I/O, and a brief
914% description of the format.
915%
916% The format of the RegisterDIBImage method is:
917%
cristybb503372010-05-27 20:51:26 +0000918% size_t RegisterDIBImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000919%
920*/
cristybb503372010-05-27 20:51:26 +0000921ModuleExport size_t RegisterDIBImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000922{
923 MagickInfo
924 *entry;
925
926 entry=SetMagickInfo("DIB");
927 entry->decoder=(DecodeImageHandler *) ReadDIBImage;
928 entry->encoder=(EncodeImageHandler *) WriteDIBImage;
929 entry->magick=(IsImageFormatHandler *) IsDIB;
930 entry->adjoin=MagickFalse;
931 entry->stealth=MagickTrue;
932 entry->description=ConstantString(
933 "Microsoft Windows 3.X Packed Device-Independent Bitmap");
934 entry->module=ConstantString("DIB");
935 (void) RegisterMagickInfo(entry);
936 return(MagickImageCoderSignature);
937}
938
939/*
940%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
941% %
942% %
943% %
944% U n r e g i s t e r D I B I m a g e %
945% %
946% %
947% %
948%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
949%
950% UnregisterDIBImage() removes format registrations made by the
951% DIB module from the list of supported formats.
952%
953% The format of the UnregisterDIBImage method is:
954%
955% UnregisterDIBImage(void)
956%
957*/
958ModuleExport void UnregisterDIBImage(void)
959{
960 (void) UnregisterMagickInfo("DIB");
961}
962
963/*
964%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
965% %
966% %
967% %
968% W r i t e D I B I m a g e %
969% %
970% %
971% %
972%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
973%
974% WriteDIBImage() writes an image in Microsoft Windows bitmap encoded
975% image format.
976%
977% The format of the WriteDIBImage method is:
978%
cristy1e178e72011-08-28 19:44:34 +0000979% MagickBooleanType WriteDIBImage(const ImageInfo *image_info,
980% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000981%
982% A description of each parameter follows.
983%
984% o image_info: the image info.
985%
986% o image: The image.
987%
cristy1e178e72011-08-28 19:44:34 +0000988% o exception: return any errors or warnings in this structure.
989%
cristy3ed852e2009-09-05 21:47:34 +0000990*/
cristy1e178e72011-08-28 19:44:34 +0000991static MagickBooleanType WriteDIBImage(const ImageInfo *image_info,Image *image,
992 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000993{
994 DIBInfo
995 dib_info;
996
cristy3ed852e2009-09-05 21:47:34 +0000997 MagickBooleanType
998 status;
999
cristy4c08aed2011-07-01 19:47:50 +00001000 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +00001001 *p;
1002
cristybb503372010-05-27 20:51:26 +00001003 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001004 i,
1005 x;
1006
1007 register unsigned char
1008 *q;
1009
cristyddbc41b2011-04-24 14:27:48 +00001010 size_t
1011 bytes_per_line;
1012
1013 ssize_t
1014 y;
1015
cristy3ed852e2009-09-05 21:47:34 +00001016 unsigned char
1017 *dib_data,
1018 *pixels;
1019
cristy3ed852e2009-09-05 21:47:34 +00001020 /*
1021 Open output image file.
1022 */
1023 assert(image_info != (const ImageInfo *) NULL);
1024 assert(image_info->signature == MagickSignature);
1025 assert(image != (Image *) NULL);
1026 assert(image->signature == MagickSignature);
1027 if (image->debug != MagickFalse)
1028 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy3a37efd2011-08-28 20:31:03 +00001029 assert(exception != (ExceptionInfo *) NULL);
1030 assert(exception->signature == MagickSignature);
cristy1e178e72011-08-28 19:44:34 +00001031 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00001032 if (status == MagickFalse)
1033 return(status);
1034 /*
1035 Initialize DIB raster file header.
1036 */
cristyaf8d3912014-02-21 14:50:33 +00001037 (void) TransformImageColorspace(image,sRGBColorspace,exception);
cristy3ed852e2009-09-05 21:47:34 +00001038 if (image->storage_class == DirectClass)
1039 {
1040 /*
1041 Full color DIB raster.
1042 */
1043 dib_info.number_colors=0;
cristy8a46d822012-08-28 23:32:39 +00001044 dib_info.bits_per_pixel=(unsigned short) (image->alpha_trait ? 32 : 24);
cristy3ed852e2009-09-05 21:47:34 +00001045 }
1046 else
1047 {
1048 /*
1049 Colormapped DIB raster.
1050 */
1051 dib_info.bits_per_pixel=8;
1052 if (image_info->depth > 8)
1053 dib_info.bits_per_pixel=16;
cristy1e178e72011-08-28 19:44:34 +00001054 if (IsImageMonochrome(image,exception) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001055 dib_info.bits_per_pixel=1;
1056 dib_info.number_colors=(dib_info.bits_per_pixel == 16) ? 0 :
1057 (1UL << dib_info.bits_per_pixel);
1058 }
1059 bytes_per_line=4*((image->columns*dib_info.bits_per_pixel+31)/32);
1060 dib_info.size=40;
cristybb503372010-05-27 20:51:26 +00001061 dib_info.width=(ssize_t) image->columns;
1062 dib_info.height=(ssize_t) image->rows;
cristy3ed852e2009-09-05 21:47:34 +00001063 dib_info.planes=1;
cristybb503372010-05-27 20:51:26 +00001064 dib_info.compression=(size_t) (dib_info.bits_per_pixel == 16 ?
cristy3ed852e2009-09-05 21:47:34 +00001065 BI_BITFIELDS : BI_RGB);
1066 dib_info.image_size=bytes_per_line*image->rows;
1067 dib_info.x_pixels=75*39;
1068 dib_info.y_pixels=75*39;
1069 switch (image->units)
1070 {
1071 case UndefinedResolution:
1072 case PixelsPerInchResolution:
1073 {
cristy2a11bef2011-10-28 18:33:11 +00001074 dib_info.x_pixels=(size_t) (100.0*image->resolution.x/2.54);
1075 dib_info.y_pixels=(size_t) (100.0*image->resolution.y/2.54);
cristy3ed852e2009-09-05 21:47:34 +00001076 break;
1077 }
1078 case PixelsPerCentimeterResolution:
1079 {
cristy2a11bef2011-10-28 18:33:11 +00001080 dib_info.x_pixels=(size_t) (100.0*image->resolution.x);
1081 dib_info.y_pixels=(size_t) (100.0*image->resolution.y);
cristy3ed852e2009-09-05 21:47:34 +00001082 break;
1083 }
1084 }
1085 dib_info.colors_important=dib_info.number_colors;
1086 /*
1087 Convert MIFF to DIB raster pixels.
1088 */
1089 pixels=(unsigned char *) AcquireQuantumMemory(dib_info.image_size,
1090 sizeof(*pixels));
1091 if (pixels == (unsigned char *) NULL)
1092 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1093 (void) ResetMagickMemory(pixels,0,dib_info.image_size);
1094 switch (dib_info.bits_per_pixel)
1095 {
1096 case 1:
1097 {
1098 register unsigned char
1099 bit,
1100 byte;
1101
1102 /*
1103 Convert PseudoClass image to a DIB monochrome image.
1104 */
cristybb503372010-05-27 20:51:26 +00001105 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001106 {
cristy1e178e72011-08-28 19:44:34 +00001107 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001108 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001109 break;
cristy3ed852e2009-09-05 21:47:34 +00001110 q=pixels+(image->rows-y-1)*bytes_per_line;
1111 bit=0;
1112 byte=0;
cristybb503372010-05-27 20:51:26 +00001113 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001114 {
1115 byte<<=1;
cristy4c08aed2011-07-01 19:47:50 +00001116 byte|=GetPixelIndex(image,p) != 0 ? 0x01 : 0x00;
cristy3ed852e2009-09-05 21:47:34 +00001117 bit++;
1118 if (bit == 8)
1119 {
1120 *q++=byte;
1121 bit=0;
1122 byte=0;
1123 }
cristyed231572011-07-14 02:18:59 +00001124 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001125 }
1126 if (bit != 0)
1127 {
1128 *q++=(unsigned char) (byte << (8-bit));
1129 x++;
1130 }
cristybb503372010-05-27 20:51:26 +00001131 for (x=(ssize_t) (image->columns+7)/8; x < (ssize_t) bytes_per_line; x++)
cristy3ed852e2009-09-05 21:47:34 +00001132 *q++=0x00;
cristycee97112010-05-28 00:44:52 +00001133 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
cristyddbc41b2011-04-24 14:27:48 +00001134 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001135 if (status == MagickFalse)
1136 break;
1137 }
1138 break;
1139 }
1140 case 8:
1141 {
1142 /*
1143 Convert PseudoClass packet to DIB pixel.
1144 */
cristybb503372010-05-27 20:51:26 +00001145 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001146 {
cristy1e178e72011-08-28 19:44:34 +00001147 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001148 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001149 break;
cristy3ed852e2009-09-05 21:47:34 +00001150 q=pixels+(image->rows-y-1)*bytes_per_line;
cristybb503372010-05-27 20:51:26 +00001151 for (x=0; x < (ssize_t) image->columns; x++)
cristy4c08aed2011-07-01 19:47:50 +00001152 {
1153 *q++=(unsigned char) GetPixelIndex(image,p);
cristyed231572011-07-14 02:18:59 +00001154 p+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00001155 }
cristybb503372010-05-27 20:51:26 +00001156 for ( ; x < (ssize_t) bytes_per_line; x++)
cristy3ed852e2009-09-05 21:47:34 +00001157 *q++=0x00;
cristycee97112010-05-28 00:44:52 +00001158 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
cristyddbc41b2011-04-24 14:27:48 +00001159 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001160 if (status == MagickFalse)
1161 break;
1162 }
1163 break;
1164 }
1165 case 16:
1166 {
1167 unsigned short
1168 word;
1169 /*
1170 Convert PseudoClass packet to DIB pixel.
1171 */
cristybb503372010-05-27 20:51:26 +00001172 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001173 {
cristy1e178e72011-08-28 19:44:34 +00001174 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001175 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001176 break;
1177 q=pixels+(image->rows-y-1)*bytes_per_line;
cristybb503372010-05-27 20:51:26 +00001178 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001179 {
1180 word=(unsigned short) ((ScaleColor8to5((unsigned char)
cristy4c08aed2011-07-01 19:47:50 +00001181 ScaleQuantumToChar(GetPixelRed(image,p))) << 11) | (ScaleColor8to6(
1182 (unsigned char) ScaleQuantumToChar(GetPixelGreen(image,p))) << 5) |
1183 (ScaleColor8to5((unsigned char) ScaleQuantumToChar((unsigned char)
1184 GetPixelBlue(image,p)) << 0)));
cristy3ed852e2009-09-05 21:47:34 +00001185 *q++=(unsigned char)(word & 0xff);
1186 *q++=(unsigned char)(word >> 8);
cristyed231572011-07-14 02:18:59 +00001187 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001188 }
cristyf6fe0a12010-05-30 00:44:47 +00001189 for (x=(ssize_t) (2*image->columns); x < (ssize_t) bytes_per_line; x++)
cristy3ed852e2009-09-05 21:47:34 +00001190 *q++=0x00;
cristycee97112010-05-28 00:44:52 +00001191 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
cristyddbc41b2011-04-24 14:27:48 +00001192 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001193 if (status == MagickFalse)
1194 break;
1195 }
1196 break;
1197 }
1198 case 24:
1199 case 32:
1200 {
1201 /*
1202 Convert DirectClass packet to DIB RGB pixel.
1203 */
cristybb503372010-05-27 20:51:26 +00001204 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001205 {
cristy1e178e72011-08-28 19:44:34 +00001206 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001207 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001208 break;
1209 q=pixels+(image->rows-y-1)*bytes_per_line;
cristybb503372010-05-27 20:51:26 +00001210 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001211 {
cristy4c08aed2011-07-01 19:47:50 +00001212 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
1213 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
1214 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
cristy17f11b02014-12-20 19:37:04 +00001215 if (image->alpha_trait != UndefinedPixelTrait)
cristy4c08aed2011-07-01 19:47:50 +00001216 *q++=ScaleQuantumToChar(GetPixelAlpha(image,p));
cristyed231572011-07-14 02:18:59 +00001217 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001218 }
1219 if (dib_info.bits_per_pixel == 24)
cristyf6fe0a12010-05-30 00:44:47 +00001220 for (x=(ssize_t) (3*image->columns); x < (ssize_t) bytes_per_line; x++)
cristy3ed852e2009-09-05 21:47:34 +00001221 *q++=0x00;
cristycee97112010-05-28 00:44:52 +00001222 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
cristyddbc41b2011-04-24 14:27:48 +00001223 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001224 if (status == MagickFalse)
1225 break;
1226 }
1227 break;
1228 }
1229 }
1230 if (dib_info.bits_per_pixel == 8)
1231 if (image_info->compression != NoCompression)
1232 {
1233 size_t
1234 length;
1235
1236 /*
1237 Convert run-length encoded raster pixels.
1238 */
1239 length=2UL*(bytes_per_line+2UL)+2UL;
1240 dib_data=(unsigned char *) AcquireQuantumMemory(length,
1241 (image->rows+2UL)*sizeof(*dib_data));
cristy4d0ca342014-05-01 00:42:09 +00001242 if (dib_data == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001243 {
1244 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1245 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1246 }
cristybb503372010-05-27 20:51:26 +00001247 dib_info.image_size=(size_t) EncodeImage(image,bytes_per_line,
cristy3ed852e2009-09-05 21:47:34 +00001248 pixels,dib_data);
1249 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1250 pixels=dib_data;
1251 dib_info.compression = BI_RLE8;
1252 }
1253 /*
1254 Write DIB header.
1255 */
cristyf6fe0a12010-05-30 00:44:47 +00001256 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.size);
cristyeaedf062010-05-29 22:36:02 +00001257 (void) WriteBlobLSBLong(image,dib_info.width);
cristy3ed852e2009-09-05 21:47:34 +00001258 (void) WriteBlobLSBLong(image,(unsigned short) dib_info.height);
1259 (void) WriteBlobLSBShort(image,(unsigned short) dib_info.planes);
1260 (void) WriteBlobLSBShort(image,dib_info.bits_per_pixel);
cristyf6fe0a12010-05-30 00:44:47 +00001261 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.compression);
1262 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.image_size);
1263 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.x_pixels);
1264 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.y_pixels);
1265 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.number_colors);
1266 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.colors_important);
cristy3ed852e2009-09-05 21:47:34 +00001267 if (image->storage_class == PseudoClass)
1268 {
1269 if (dib_info.bits_per_pixel <= 8)
1270 {
1271 unsigned char
1272 *dib_colormap;
1273
1274 /*
1275 Dump colormap to file.
1276 */
1277 dib_colormap=(unsigned char *) AcquireQuantumMemory((size_t)
cristy4d0ca342014-05-01 00:42:09 +00001278 (1UL << dib_info.bits_per_pixel),4*sizeof(*dib_colormap));
cristy3ed852e2009-09-05 21:47:34 +00001279 if (dib_colormap == (unsigned char *) NULL)
1280 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1281 q=dib_colormap;
cristybb503372010-05-27 20:51:26 +00001282 for (i=0; i < (ssize_t) MagickMin(image->colors,dib_info.number_colors); i++)
cristy3ed852e2009-09-05 21:47:34 +00001283 {
1284 *q++=ScaleQuantumToChar(image->colormap[i].blue);
1285 *q++=ScaleQuantumToChar(image->colormap[i].green);
1286 *q++=ScaleQuantumToChar(image->colormap[i].red);
1287 *q++=(Quantum) 0x0;
1288 }
cristybb503372010-05-27 20:51:26 +00001289 for ( ; i < (ssize_t) (1L << dib_info.bits_per_pixel); i++)
cristy3ed852e2009-09-05 21:47:34 +00001290 {
1291 *q++=(Quantum) 0x0;
1292 *q++=(Quantum) 0x0;
1293 *q++=(Quantum) 0x0;
1294 *q++=(Quantum) 0x0;
1295 }
1296 (void) WriteBlob(image,(size_t) (4*(1 << dib_info.bits_per_pixel)),
1297 dib_colormap);
1298 dib_colormap=(unsigned char *) RelinquishMagickMemory(dib_colormap);
1299 }
1300 else
1301 if ((dib_info.bits_per_pixel == 16) &&
1302 (dib_info.compression == BI_BITFIELDS))
1303 {
1304 (void) WriteBlobLSBLong(image,0xf800);
1305 (void) WriteBlobLSBLong(image,0x07e0);
1306 (void) WriteBlobLSBLong(image,0x001f);
1307 }
1308 }
1309 (void) WriteBlob(image,dib_info.image_size,pixels);
1310 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1311 (void) CloseBlob(image);
1312 return(MagickTrue);
1313}