blob: b324f20e36121d749dc4eca5f0ab320b2f8f6c54 [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);
cristyca793d72015-01-23 13:03:55 +0000517 if ((dib_info.bits_per_pixel != 1) && (dib_info.bits_per_pixel != 4) &&
518 (dib_info.bits_per_pixel != 8) && (dib_info.bits_per_pixel != 16) &&
519 (dib_info.bits_per_pixel != 24) && (dib_info.bits_per_pixel != 32))
520 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
cristy3ed852e2009-09-05 21:47:34 +0000521 if ((dib_info.compression == BI_BITFIELDS) &&
522 ((dib_info.bits_per_pixel == 16) || (dib_info.bits_per_pixel == 32)))
523 {
524 dib_info.red_mask=ReadBlobLSBLong(image);
525 dib_info.green_mask=ReadBlobLSBLong(image);
526 dib_info.blue_mask=ReadBlobLSBLong(image);
527 }
cristyca793d72015-01-23 13:03:55 +0000528 if (EOFBlob(image) != MagickFalse)
529 ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
cristyf8dcd772014-12-19 12:11:44 +0000530 if (dib_info.width <= 0)
531 ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize");
532 if (dib_info.height == 0)
533 ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize");
534 if (dib_info.planes != 1)
535 ThrowReaderException(CorruptImageError,"StaticPlanesValueNotEqualToOne");
536 if ((dib_info.bits_per_pixel != 1) && (dib_info.bits_per_pixel != 4) &&
537 (dib_info.bits_per_pixel != 8) && (dib_info.bits_per_pixel != 16) &&
538 (dib_info.bits_per_pixel != 24) && (dib_info.bits_per_pixel != 32))
539 ThrowReaderException(CorruptImageError,"UnrecognizedBitsPerPixel");
540 if (dib_info.bits_per_pixel < 16 &&
cristy58d4fe12015-02-07 11:53:05 +0000541 dib_info.number_colors > (1UL << dib_info.bits_per_pixel))
cristyf8dcd772014-12-19 12:11:44 +0000542 ThrowReaderException(CorruptImageError,"UnrecognizedNumberOfColors");
543 if ((dib_info.compression == 1) && (dib_info.bits_per_pixel != 8))
544 ThrowReaderException(CorruptImageError,"UnrecognizedBitsPerPixel");
545 if ((dib_info.compression == 2) && (dib_info.bits_per_pixel != 4))
546 ThrowReaderException(CorruptImageError,"UnrecognizedBitsPerPixel");
547 if ((dib_info.compression == 3) && (dib_info.bits_per_pixel < 16))
548 ThrowReaderException(CorruptImageError,"UnrecognizedBitsPerPixel");
549 switch (dib_info.compression)
550 {
551 case BI_RGB:
552 case BI_RLE8:
553 case BI_RLE4:
554 case BI_BITFIELDS:
555 break;
556 case BI_JPEG:
557 ThrowReaderException(CoderError,"JPEGCompressNotSupported");
558 case BI_PNG:
559 ThrowReaderException(CoderError,"PNGCompressNotSupported");
560 default:
561 ThrowReaderException(CorruptImageError,"UnrecognizedImageCompression");
562 }
cristybb503372010-05-27 20:51:26 +0000563 image->columns=(size_t) MagickAbsoluteValue(dib_info.width);
564 image->rows=(size_t) MagickAbsoluteValue(dib_info.height);
cristy3ed852e2009-09-05 21:47:34 +0000565 image->depth=8;
cristyf8dcd772014-12-19 12:11:44 +0000566 image->alpha_trait=dib_info.bits_per_pixel == 32 ? BlendPixelTrait :
567 UndefinedPixelTrait;
cristyca793d72015-01-23 13:03:55 +0000568 if ((dib_info.number_colors > 256) || (dib_info.colors_important > 256))
569 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
cristy3ed852e2009-09-05 21:47:34 +0000570 if ((dib_info.number_colors != 0) || (dib_info.bits_per_pixel < 16))
571 {
cristyeaedf062010-05-29 22:36:02 +0000572 size_t
573 one;
574
cristy3ed852e2009-09-05 21:47:34 +0000575 image->storage_class=PseudoClass;
576 image->colors=dib_info.number_colors;
cristyeaedf062010-05-29 22:36:02 +0000577 one=1;
cristy3ed852e2009-09-05 21:47:34 +0000578 if (image->colors == 0)
cristyeaedf062010-05-29 22:36:02 +0000579 image->colors=one << dib_info.bits_per_pixel;
cristy3ed852e2009-09-05 21:47:34 +0000580 }
581 if (image_info->size)
582 {
583 RectangleInfo
584 geometry;
585
586 MagickStatusType
587 flags;
588
589 flags=ParseAbsoluteGeometry(image_info->size,&geometry);
590 if (flags & WidthValue)
591 if ((geometry.width != 0) && (geometry.width < image->columns))
592 image->columns=geometry.width;
593 if (flags & HeightValue)
594 if ((geometry.height != 0) && (geometry.height < image->rows))
595 image->rows=geometry.height;
596 }
cristyacabb842014-12-14 23:36:33 +0000597 status=SetImageExtent(image,image->columns,image->rows,exception);
598 if (status == MagickFalse)
599 return(DestroyImageList(image));
cristy3ed852e2009-09-05 21:47:34 +0000600 if (image->storage_class == PseudoClass)
601 {
602 size_t
603 length,
604 packet_size;
605
606 unsigned char
607 *dib_colormap;
608
609 /*
610 Read DIB raster colormap.
611 */
cristy018f07f2011-09-04 21:15:19 +0000612 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000613 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
614 length=(size_t) image->colors;
615 dib_colormap=(unsigned char *) AcquireQuantumMemory(length,
616 4*sizeof(*dib_colormap));
617 if (dib_colormap == (unsigned char *) NULL)
618 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
619 packet_size=4;
620 count=ReadBlob(image,packet_size*image->colors,dib_colormap);
621 if (count != (ssize_t) (packet_size*image->colors))
622 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
623 p=dib_colormap;
cristybb503372010-05-27 20:51:26 +0000624 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +0000625 {
626 image->colormap[i].blue=ScaleCharToQuantum(*p++);
627 image->colormap[i].green=ScaleCharToQuantum(*p++);
628 image->colormap[i].red=ScaleCharToQuantum(*p++);
629 if (packet_size == 4)
630 p++;
631 }
632 dib_colormap=(unsigned char *) RelinquishMagickMemory(dib_colormap);
633 }
634 /*
635 Read image data.
636 */
637 if (dib_info.compression == BI_RLE4)
638 dib_info.bits_per_pixel<<=1;
639 bytes_per_line=4*((image->columns*dib_info.bits_per_pixel+31)/32);
640 length=bytes_per_line*image->rows;
cristy0553bd52013-06-30 15:53:50 +0000641 pixel_info=AcquireVirtualMemory((size_t) image->rows,MagickMax(
642 bytes_per_line,image->columns+256UL)*sizeof(*pixels));
643 if (pixel_info == (MemoryInfo *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000644 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
cristy0553bd52013-06-30 15:53:50 +0000645 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +0000646 if ((dib_info.compression == BI_RGB) ||
647 (dib_info.compression == BI_BITFIELDS))
648 {
649 count=ReadBlob(image,length,pixels);
650 if (count != (ssize_t) (length))
651 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
652 }
653 else
654 {
655 /*
656 Convert run-length encoded raster pixels.
657 */
658 status=DecodeImage(image,dib_info.compression ? MagickTrue : MagickFalse,
659 pixels);
660 if (status == MagickFalse)
661 ThrowReaderException(CorruptImageError,"UnableToRunlengthDecodeImage");
662 }
663 /*
664 Initialize image structure.
665 */
666 image->units=PixelsPerCentimeterResolution;
cristy2a11bef2011-10-28 18:33:11 +0000667 image->resolution.x=(double) dib_info.x_pixels/100.0;
668 image->resolution.y=(double) dib_info.y_pixels/100.0;
cristy3ed852e2009-09-05 21:47:34 +0000669 /*
670 Convert DIB raster image to pixel packets.
671 */
672 switch (dib_info.bits_per_pixel)
673 {
674 case 1:
675 {
676 /*
677 Convert bitmap scanline.
678 */
cristybb503372010-05-27 20:51:26 +0000679 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +0000680 {
681 p=pixels+(image->rows-y-1)*bytes_per_line;
682 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000683 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000684 break;
cristybb503372010-05-27 20:51:26 +0000685 for (x=0; x < ((ssize_t) image->columns-7); x+=8)
cristy3ed852e2009-09-05 21:47:34 +0000686 {
687 for (bit=0; bit < 8; bit++)
688 {
cristy4c08aed2011-07-01 19:47:50 +0000689 index=(Quantum) ((*p) & (0x80 >> bit) ? 0x01 : 0x00);
690 SetPixelIndex(image,index,q);
cristyed231572011-07-14 02:18:59 +0000691 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000692 }
693 p++;
694 }
695 if ((image->columns % 8) != 0)
696 {
cristybb503372010-05-27 20:51:26 +0000697 for (bit=0; bit < (ssize_t) (image->columns % 8); bit++)
cristy3ed852e2009-09-05 21:47:34 +0000698 {
cristy4c08aed2011-07-01 19:47:50 +0000699 index=(Quantum) ((*p) & (0x80 >> bit) ? 0x01 : 0x00);
700 SetPixelIndex(image,index,q);
cristyed231572011-07-14 02:18:59 +0000701 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000702 }
703 p++;
704 }
705 if (SyncAuthenticPixels(image,exception) == MagickFalse)
706 break;
707 if (image->previous == (Image *) NULL)
708 {
709 status=SetImageProgress(image,LoadImageTag,image->rows-y-1,
710 image->rows);
711 if (status == MagickFalse)
712 break;
713 }
714 }
cristyea1a8aa2011-10-20 13:24:06 +0000715 (void) SyncImage(image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000716 break;
717 }
718 case 4:
719 {
720 /*
721 Convert PseudoColor scanline.
722 */
cristybb503372010-05-27 20:51:26 +0000723 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +0000724 {
725 p=pixels+(image->rows-y-1)*bytes_per_line;
726 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000727 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000728 break;
cristybb503372010-05-27 20:51:26 +0000729 for (x=0; x < ((ssize_t) image->columns-1); x+=2)
cristy3ed852e2009-09-05 21:47:34 +0000730 {
cristyc82a27b2011-10-21 01:07:16 +0000731 index=ConstrainColormapIndex(image,(*p >> 4) & 0xf,exception);
cristy4c08aed2011-07-01 19:47:50 +0000732 SetPixelIndex(image,index,q);
cristyed231572011-07-14 02:18:59 +0000733 q+=GetPixelChannels(image);
cristyc82a27b2011-10-21 01:07:16 +0000734 index=ConstrainColormapIndex(image,*p & 0xf,exception);
cristy4c08aed2011-07-01 19:47:50 +0000735 SetPixelIndex(image,index,q);
cristy3ed852e2009-09-05 21:47:34 +0000736 p++;
cristyed231572011-07-14 02:18:59 +0000737 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000738 }
739 if ((image->columns % 2) != 0)
740 {
cristyc82a27b2011-10-21 01:07:16 +0000741 index=ConstrainColormapIndex(image,(*p >> 4) & 0xf,exception);
cristy4c08aed2011-07-01 19:47:50 +0000742 SetPixelIndex(image,index,q);
cristyed231572011-07-14 02:18:59 +0000743 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000744 p++;
745 }
746 if (SyncAuthenticPixels(image,exception) == MagickFalse)
747 break;
748 if (image->previous == (Image *) NULL)
749 {
750 status=SetImageProgress(image,LoadImageTag,image->rows-y-1,
751 image->rows);
752 if (status == MagickFalse)
753 break;
754 }
755 }
cristyea1a8aa2011-10-20 13:24:06 +0000756 (void) SyncImage(image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000757 break;
758 }
759 case 8:
760 {
761 /*
762 Convert PseudoColor scanline.
763 */
764 if ((dib_info.compression == BI_RLE8) ||
765 (dib_info.compression == BI_RLE4))
766 bytes_per_line=image->columns;
cristybb503372010-05-27 20:51:26 +0000767 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +0000768 {
769 p=pixels+(image->rows-y-1)*bytes_per_line;
770 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000771 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000772 break;
cristybb503372010-05-27 20:51:26 +0000773 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000774 {
cristyc82a27b2011-10-21 01:07:16 +0000775 index=ConstrainColormapIndex(image,*p,exception);
cristy4c08aed2011-07-01 19:47:50 +0000776 SetPixelIndex(image,index,q);
cristy3ed852e2009-09-05 21:47:34 +0000777 p++;
cristyed231572011-07-14 02:18:59 +0000778 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000779 }
780 if (SyncAuthenticPixels(image,exception) == MagickFalse)
781 break;
782 if (image->previous == (Image *) NULL)
783 {
784 status=SetImageProgress(image,LoadImageTag,image->rows-y-1,
785 image->rows);
786 if (status == MagickFalse)
787 break;
788 }
789 }
cristyea1a8aa2011-10-20 13:24:06 +0000790 (void) SyncImage(image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000791 break;
792 }
793 case 16:
794 {
795 unsigned short
796 word;
797
798 /*
799 Convert PseudoColor scanline.
800 */
801 image->storage_class=DirectClass;
802 if (dib_info.compression == BI_RLE8)
803 bytes_per_line=2*image->columns;
cristybb503372010-05-27 20:51:26 +0000804 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +0000805 {
806 p=pixels+(image->rows-y-1)*bytes_per_line;
807 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000808 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000809 break;
cristybb503372010-05-27 20:51:26 +0000810 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000811 {
812 word=(*p++);
813 word|=(*p++ << 8);
814 if (dib_info.red_mask == 0)
815 {
cristy4c08aed2011-07-01 19:47:50 +0000816 SetPixelRed(image,ScaleCharToQuantum(ScaleColor5to8(
817 (unsigned char) ((word >> 10) & 0x1f))),q);
818 SetPixelGreen(image,ScaleCharToQuantum(ScaleColor5to8(
819 (unsigned char) ((word >> 5) & 0x1f))),q);
820 SetPixelBlue(image,ScaleCharToQuantum(ScaleColor5to8(
821 (unsigned char) (word & 0x1f))),q);
cristy3ed852e2009-09-05 21:47:34 +0000822 }
823 else
824 {
cristy4c08aed2011-07-01 19:47:50 +0000825 SetPixelRed(image,ScaleCharToQuantum(ScaleColor5to8(
826 (unsigned char) ((word >> 11) & 0x1f))),q);
827 SetPixelGreen(image,ScaleCharToQuantum(ScaleColor6to8(
828 (unsigned char) ((word >> 5) & 0x3f))),q);
829 SetPixelBlue(image,ScaleCharToQuantum(ScaleColor5to8(
830 (unsigned char) (word & 0x1f))),q);
cristy3ed852e2009-09-05 21:47:34 +0000831 }
cristyed231572011-07-14 02:18:59 +0000832 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000833 }
834 if (SyncAuthenticPixels(image,exception) == MagickFalse)
835 break;
836 if (image->previous == (Image *) NULL)
837 {
838 status=SetImageProgress(image,LoadImageTag,image->rows-y-1,
839 image->rows);
840 if (status == MagickFalse)
841 break;
842 }
843 }
844 break;
845 }
846 case 24:
847 case 32:
848 {
849 /*
850 Convert DirectColor scanline.
851 */
cristybb503372010-05-27 20:51:26 +0000852 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +0000853 {
854 p=pixels+(image->rows-y-1)*bytes_per_line;
855 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000856 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000857 break;
cristybb503372010-05-27 20:51:26 +0000858 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000859 {
cristy4c08aed2011-07-01 19:47:50 +0000860 SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
861 SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
862 SetPixelRed(image,ScaleCharToQuantum(*p++),q);
cristy17f11b02014-12-20 19:37:04 +0000863 if (image->alpha_trait != UndefinedPixelTrait)
cristy4c08aed2011-07-01 19:47:50 +0000864 SetPixelAlpha(image,ScaleCharToQuantum(*p++),q);
cristyed231572011-07-14 02:18:59 +0000865 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000866 }
867 if (SyncAuthenticPixels(image,exception) == MagickFalse)
868 break;
869 if (image->previous == (Image *) NULL)
870 {
871 status=SetImageProgress(image,LoadImageTag,image->rows-y-1,
872 image->rows);
873 if (status == MagickFalse)
874 break;
875 }
876 }
877 break;
878 }
879 default:
880 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
881 }
cristy0553bd52013-06-30 15:53:50 +0000882 pixel_info=RelinquishVirtualMemory(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +0000883 if (EOFBlob(image) != MagickFalse)
884 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
885 image->filename);
886 if (dib_info.height < 0)
887 {
888 Image
889 *flipped_image;
890
891 /*
892 Correct image orientation.
893 */
894 flipped_image=FlipImage(image,exception);
cristybbfd4cd2010-04-13 21:54:39 +0000895 if (flipped_image != (Image *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000896 {
cristybbfd4cd2010-04-13 21:54:39 +0000897 DuplicateBlob(flipped_image,image);
898 image=DestroyImage(image);
899 image=flipped_image;
cristy3ed852e2009-09-05 21:47:34 +0000900 }
cristy3ed852e2009-09-05 21:47:34 +0000901 }
902 (void) CloseBlob(image);
903 return(GetFirstImageInList(image));
904}
905
906/*
907%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
908% %
909% %
910% %
911% R e g i s t e r D I B I m a g e %
912% %
913% %
914% %
915%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
916%
917% RegisterDIBImage() adds attributes for the DIB image format to
918% the list of supported formats. The attributes include the image format
919% tag, a method to read and/or write the format, whether the format
920% supports the saving of more than one frame to the same file or blob,
921% whether the format supports native in-memory I/O, and a brief
922% description of the format.
923%
924% The format of the RegisterDIBImage method is:
925%
cristybb503372010-05-27 20:51:26 +0000926% size_t RegisterDIBImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000927%
928*/
cristybb503372010-05-27 20:51:26 +0000929ModuleExport size_t RegisterDIBImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000930{
931 MagickInfo
932 *entry;
933
934 entry=SetMagickInfo("DIB");
935 entry->decoder=(DecodeImageHandler *) ReadDIBImage;
936 entry->encoder=(EncodeImageHandler *) WriteDIBImage;
937 entry->magick=(IsImageFormatHandler *) IsDIB;
dirk08e9a112015-02-22 01:51:41 +0000938 entry->flags^=CoderAdjoinFlag;
939 entry->flags|=CoderStealthFlag;
cristy3ed852e2009-09-05 21:47:34 +0000940 entry->description=ConstantString(
941 "Microsoft Windows 3.X Packed Device-Independent Bitmap");
942 entry->module=ConstantString("DIB");
943 (void) RegisterMagickInfo(entry);
944 return(MagickImageCoderSignature);
945}
946
947/*
948%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
949% %
950% %
951% %
952% U n r e g i s t e r D I B I m a g e %
953% %
954% %
955% %
956%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
957%
958% UnregisterDIBImage() removes format registrations made by the
959% DIB module from the list of supported formats.
960%
961% The format of the UnregisterDIBImage method is:
962%
963% UnregisterDIBImage(void)
964%
965*/
966ModuleExport void UnregisterDIBImage(void)
967{
968 (void) UnregisterMagickInfo("DIB");
969}
970
971/*
972%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
973% %
974% %
975% %
976% W r i t e D I B I m a g e %
977% %
978% %
979% %
980%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
981%
982% WriteDIBImage() writes an image in Microsoft Windows bitmap encoded
983% image format.
984%
985% The format of the WriteDIBImage method is:
986%
cristy1e178e72011-08-28 19:44:34 +0000987% MagickBooleanType WriteDIBImage(const ImageInfo *image_info,
988% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000989%
990% A description of each parameter follows.
991%
992% o image_info: the image info.
993%
994% o image: The image.
995%
cristy1e178e72011-08-28 19:44:34 +0000996% o exception: return any errors or warnings in this structure.
997%
cristy3ed852e2009-09-05 21:47:34 +0000998*/
cristy1e178e72011-08-28 19:44:34 +0000999static MagickBooleanType WriteDIBImage(const ImageInfo *image_info,Image *image,
1000 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001001{
1002 DIBInfo
1003 dib_info;
1004
cristy3ed852e2009-09-05 21:47:34 +00001005 MagickBooleanType
1006 status;
1007
cristy4c08aed2011-07-01 19:47:50 +00001008 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +00001009 *p;
1010
cristybb503372010-05-27 20:51:26 +00001011 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001012 i,
1013 x;
1014
1015 register unsigned char
1016 *q;
1017
cristyddbc41b2011-04-24 14:27:48 +00001018 size_t
1019 bytes_per_line;
1020
1021 ssize_t
1022 y;
1023
cristy3ed852e2009-09-05 21:47:34 +00001024 unsigned char
1025 *dib_data,
1026 *pixels;
1027
cristy3ed852e2009-09-05 21:47:34 +00001028 /*
1029 Open output image file.
1030 */
1031 assert(image_info != (const ImageInfo *) NULL);
1032 assert(image_info->signature == MagickSignature);
1033 assert(image != (Image *) NULL);
1034 assert(image->signature == MagickSignature);
1035 if (image->debug != MagickFalse)
1036 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy3a37efd2011-08-28 20:31:03 +00001037 assert(exception != (ExceptionInfo *) NULL);
1038 assert(exception->signature == MagickSignature);
cristy1e178e72011-08-28 19:44:34 +00001039 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00001040 if (status == MagickFalse)
1041 return(status);
1042 /*
1043 Initialize DIB raster file header.
1044 */
cristyaf8d3912014-02-21 14:50:33 +00001045 (void) TransformImageColorspace(image,sRGBColorspace,exception);
cristy3ed852e2009-09-05 21:47:34 +00001046 if (image->storage_class == DirectClass)
1047 {
1048 /*
1049 Full color DIB raster.
1050 */
1051 dib_info.number_colors=0;
cristy8a46d822012-08-28 23:32:39 +00001052 dib_info.bits_per_pixel=(unsigned short) (image->alpha_trait ? 32 : 24);
cristy3ed852e2009-09-05 21:47:34 +00001053 }
1054 else
1055 {
1056 /*
1057 Colormapped DIB raster.
1058 */
1059 dib_info.bits_per_pixel=8;
1060 if (image_info->depth > 8)
1061 dib_info.bits_per_pixel=16;
dirkf1d85482015-04-06 00:36:00 +00001062 if (SetImageMonochrome(image,exception) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001063 dib_info.bits_per_pixel=1;
1064 dib_info.number_colors=(dib_info.bits_per_pixel == 16) ? 0 :
1065 (1UL << dib_info.bits_per_pixel);
1066 }
1067 bytes_per_line=4*((image->columns*dib_info.bits_per_pixel+31)/32);
1068 dib_info.size=40;
cristybb503372010-05-27 20:51:26 +00001069 dib_info.width=(ssize_t) image->columns;
1070 dib_info.height=(ssize_t) image->rows;
cristy3ed852e2009-09-05 21:47:34 +00001071 dib_info.planes=1;
cristybb503372010-05-27 20:51:26 +00001072 dib_info.compression=(size_t) (dib_info.bits_per_pixel == 16 ?
cristy3ed852e2009-09-05 21:47:34 +00001073 BI_BITFIELDS : BI_RGB);
1074 dib_info.image_size=bytes_per_line*image->rows;
1075 dib_info.x_pixels=75*39;
1076 dib_info.y_pixels=75*39;
1077 switch (image->units)
1078 {
1079 case UndefinedResolution:
1080 case PixelsPerInchResolution:
1081 {
cristy2a11bef2011-10-28 18:33:11 +00001082 dib_info.x_pixels=(size_t) (100.0*image->resolution.x/2.54);
1083 dib_info.y_pixels=(size_t) (100.0*image->resolution.y/2.54);
cristy3ed852e2009-09-05 21:47:34 +00001084 break;
1085 }
1086 case PixelsPerCentimeterResolution:
1087 {
cristy2a11bef2011-10-28 18:33:11 +00001088 dib_info.x_pixels=(size_t) (100.0*image->resolution.x);
1089 dib_info.y_pixels=(size_t) (100.0*image->resolution.y);
cristy3ed852e2009-09-05 21:47:34 +00001090 break;
1091 }
1092 }
1093 dib_info.colors_important=dib_info.number_colors;
1094 /*
1095 Convert MIFF to DIB raster pixels.
1096 */
1097 pixels=(unsigned char *) AcquireQuantumMemory(dib_info.image_size,
1098 sizeof(*pixels));
1099 if (pixels == (unsigned char *) NULL)
1100 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1101 (void) ResetMagickMemory(pixels,0,dib_info.image_size);
1102 switch (dib_info.bits_per_pixel)
1103 {
1104 case 1:
1105 {
1106 register unsigned char
1107 bit,
1108 byte;
1109
1110 /*
1111 Convert PseudoClass image to a DIB monochrome image.
1112 */
cristybb503372010-05-27 20:51:26 +00001113 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001114 {
cristy1e178e72011-08-28 19:44:34 +00001115 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001116 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001117 break;
cristy3ed852e2009-09-05 21:47:34 +00001118 q=pixels+(image->rows-y-1)*bytes_per_line;
1119 bit=0;
1120 byte=0;
cristybb503372010-05-27 20:51:26 +00001121 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001122 {
1123 byte<<=1;
cristy4c08aed2011-07-01 19:47:50 +00001124 byte|=GetPixelIndex(image,p) != 0 ? 0x01 : 0x00;
cristy3ed852e2009-09-05 21:47:34 +00001125 bit++;
1126 if (bit == 8)
1127 {
1128 *q++=byte;
1129 bit=0;
1130 byte=0;
1131 }
cristyed231572011-07-14 02:18:59 +00001132 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001133 }
1134 if (bit != 0)
1135 {
1136 *q++=(unsigned char) (byte << (8-bit));
1137 x++;
1138 }
cristybb503372010-05-27 20:51:26 +00001139 for (x=(ssize_t) (image->columns+7)/8; x < (ssize_t) bytes_per_line; x++)
cristy3ed852e2009-09-05 21:47:34 +00001140 *q++=0x00;
cristycee97112010-05-28 00:44:52 +00001141 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
cristyddbc41b2011-04-24 14:27:48 +00001142 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001143 if (status == MagickFalse)
1144 break;
1145 }
1146 break;
1147 }
1148 case 8:
1149 {
1150 /*
1151 Convert PseudoClass packet to DIB pixel.
1152 */
cristybb503372010-05-27 20:51:26 +00001153 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001154 {
cristy1e178e72011-08-28 19:44:34 +00001155 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001156 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001157 break;
cristy3ed852e2009-09-05 21:47:34 +00001158 q=pixels+(image->rows-y-1)*bytes_per_line;
cristybb503372010-05-27 20:51:26 +00001159 for (x=0; x < (ssize_t) image->columns; x++)
cristy4c08aed2011-07-01 19:47:50 +00001160 {
1161 *q++=(unsigned char) GetPixelIndex(image,p);
cristyed231572011-07-14 02:18:59 +00001162 p+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00001163 }
cristybb503372010-05-27 20:51:26 +00001164 for ( ; x < (ssize_t) bytes_per_line; x++)
cristy3ed852e2009-09-05 21:47:34 +00001165 *q++=0x00;
cristycee97112010-05-28 00:44:52 +00001166 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
cristyddbc41b2011-04-24 14:27:48 +00001167 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001168 if (status == MagickFalse)
1169 break;
1170 }
1171 break;
1172 }
1173 case 16:
1174 {
1175 unsigned short
1176 word;
1177 /*
cristyca793d72015-01-23 13:03:55 +00001178 Convert PseudoClass packet to DIB pixel.
cristy3ed852e2009-09-05 21:47:34 +00001179 */
cristybb503372010-05-27 20:51:26 +00001180 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001181 {
cristy1e178e72011-08-28 19:44:34 +00001182 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001183 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001184 break;
1185 q=pixels+(image->rows-y-1)*bytes_per_line;
cristybb503372010-05-27 20:51:26 +00001186 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001187 {
1188 word=(unsigned short) ((ScaleColor8to5((unsigned char)
cristy4c08aed2011-07-01 19:47:50 +00001189 ScaleQuantumToChar(GetPixelRed(image,p))) << 11) | (ScaleColor8to6(
1190 (unsigned char) ScaleQuantumToChar(GetPixelGreen(image,p))) << 5) |
1191 (ScaleColor8to5((unsigned char) ScaleQuantumToChar((unsigned char)
1192 GetPixelBlue(image,p)) << 0)));
cristy3ed852e2009-09-05 21:47:34 +00001193 *q++=(unsigned char)(word & 0xff);
1194 *q++=(unsigned char)(word >> 8);
cristyed231572011-07-14 02:18:59 +00001195 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001196 }
cristyf6fe0a12010-05-30 00:44:47 +00001197 for (x=(ssize_t) (2*image->columns); x < (ssize_t) bytes_per_line; x++)
cristy3ed852e2009-09-05 21:47:34 +00001198 *q++=0x00;
cristycee97112010-05-28 00:44:52 +00001199 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
cristyddbc41b2011-04-24 14:27:48 +00001200 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001201 if (status == MagickFalse)
1202 break;
1203 }
1204 break;
1205 }
1206 case 24:
1207 case 32:
1208 {
1209 /*
1210 Convert DirectClass packet to DIB RGB pixel.
1211 */
cristybb503372010-05-27 20:51:26 +00001212 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001213 {
cristy1e178e72011-08-28 19:44:34 +00001214 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001215 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001216 break;
1217 q=pixels+(image->rows-y-1)*bytes_per_line;
cristybb503372010-05-27 20:51:26 +00001218 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001219 {
cristy4c08aed2011-07-01 19:47:50 +00001220 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
1221 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
1222 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
cristy17f11b02014-12-20 19:37:04 +00001223 if (image->alpha_trait != UndefinedPixelTrait)
cristy4c08aed2011-07-01 19:47:50 +00001224 *q++=ScaleQuantumToChar(GetPixelAlpha(image,p));
cristyed231572011-07-14 02:18:59 +00001225 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001226 }
1227 if (dib_info.bits_per_pixel == 24)
cristyf6fe0a12010-05-30 00:44:47 +00001228 for (x=(ssize_t) (3*image->columns); x < (ssize_t) bytes_per_line; x++)
cristy3ed852e2009-09-05 21:47:34 +00001229 *q++=0x00;
cristycee97112010-05-28 00:44:52 +00001230 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
cristyddbc41b2011-04-24 14:27:48 +00001231 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001232 if (status == MagickFalse)
1233 break;
1234 }
1235 break;
1236 }
1237 }
1238 if (dib_info.bits_per_pixel == 8)
1239 if (image_info->compression != NoCompression)
1240 {
1241 size_t
1242 length;
1243
1244 /*
1245 Convert run-length encoded raster pixels.
1246 */
1247 length=2UL*(bytes_per_line+2UL)+2UL;
1248 dib_data=(unsigned char *) AcquireQuantumMemory(length,
1249 (image->rows+2UL)*sizeof(*dib_data));
cristy4d0ca342014-05-01 00:42:09 +00001250 if (dib_data == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001251 {
1252 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1253 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1254 }
cristybb503372010-05-27 20:51:26 +00001255 dib_info.image_size=(size_t) EncodeImage(image,bytes_per_line,
cristy3ed852e2009-09-05 21:47:34 +00001256 pixels,dib_data);
1257 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1258 pixels=dib_data;
1259 dib_info.compression = BI_RLE8;
1260 }
1261 /*
1262 Write DIB header.
1263 */
cristyf6fe0a12010-05-30 00:44:47 +00001264 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.size);
cristyeaedf062010-05-29 22:36:02 +00001265 (void) WriteBlobLSBLong(image,dib_info.width);
cristy3ed852e2009-09-05 21:47:34 +00001266 (void) WriteBlobLSBLong(image,(unsigned short) dib_info.height);
1267 (void) WriteBlobLSBShort(image,(unsigned short) dib_info.planes);
1268 (void) WriteBlobLSBShort(image,dib_info.bits_per_pixel);
cristyf6fe0a12010-05-30 00:44:47 +00001269 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.compression);
1270 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.image_size);
1271 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.x_pixels);
1272 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.y_pixels);
1273 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.number_colors);
1274 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.colors_important);
cristy3ed852e2009-09-05 21:47:34 +00001275 if (image->storage_class == PseudoClass)
1276 {
1277 if (dib_info.bits_per_pixel <= 8)
1278 {
1279 unsigned char
1280 *dib_colormap;
1281
1282 /*
1283 Dump colormap to file.
1284 */
1285 dib_colormap=(unsigned char *) AcquireQuantumMemory((size_t)
cristy4d0ca342014-05-01 00:42:09 +00001286 (1UL << dib_info.bits_per_pixel),4*sizeof(*dib_colormap));
cristy3ed852e2009-09-05 21:47:34 +00001287 if (dib_colormap == (unsigned char *) NULL)
1288 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1289 q=dib_colormap;
cristybb503372010-05-27 20:51:26 +00001290 for (i=0; i < (ssize_t) MagickMin(image->colors,dib_info.number_colors); i++)
cristy3ed852e2009-09-05 21:47:34 +00001291 {
1292 *q++=ScaleQuantumToChar(image->colormap[i].blue);
1293 *q++=ScaleQuantumToChar(image->colormap[i].green);
1294 *q++=ScaleQuantumToChar(image->colormap[i].red);
1295 *q++=(Quantum) 0x0;
1296 }
cristybb503372010-05-27 20:51:26 +00001297 for ( ; i < (ssize_t) (1L << dib_info.bits_per_pixel); i++)
cristy3ed852e2009-09-05 21:47:34 +00001298 {
1299 *q++=(Quantum) 0x0;
1300 *q++=(Quantum) 0x0;
1301 *q++=(Quantum) 0x0;
1302 *q++=(Quantum) 0x0;
1303 }
1304 (void) WriteBlob(image,(size_t) (4*(1 << dib_info.bits_per_pixel)),
1305 dib_colormap);
1306 dib_colormap=(unsigned char *) RelinquishMagickMemory(dib_colormap);
1307 }
1308 else
1309 if ((dib_info.bits_per_pixel == 16) &&
1310 (dib_info.compression == BI_BITFIELDS))
1311 {
1312 (void) WriteBlobLSBLong(image,0xf800);
1313 (void) WriteBlobLSBLong(image,0x07e0);
1314 (void) WriteBlobLSBLong(image,0x001f);
1315 }
1316 }
1317 (void) WriteBlob(image,dib_info.image_size,pixels);
1318 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1319 (void) CloseBlob(image);
1320 return(MagickTrue);
1321}