blob: 507d586344cfd17da6bf6994c7fdc9c759f94fd5 [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 %
16% John Cristy %
17% July 1992 %
18% %
19% %
cristy7e41fe82010-12-04 23:12:08 +000020% Copyright 1999-2011 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"
52#include "MagickCore/draw.h"
53#include "MagickCore/exception.h"
54#include "MagickCore/exception-private.h"
55#include "MagickCore/geometry.h"
56#include "MagickCore/image.h"
57#include "MagickCore/image-private.h"
58#include "MagickCore/list.h"
59#include "MagickCore/log.h"
60#include "MagickCore/magick.h"
61#include "MagickCore/memory_.h"
62#include "MagickCore/monitor.h"
63#include "MagickCore/monitor-private.h"
64#include "MagickCore/pixel-accessor.h"
65#include "MagickCore/quantum-private.h"
66#include "MagickCore/static.h"
67#include "MagickCore/string_.h"
68#include "MagickCore/module.h"
69#include "MagickCore/transform.h"
cristy3ed852e2009-09-05 21:47:34 +000070
71/*
72 Typedef declarations.
73*/
74typedef struct _DIBInfo
75{
cristyf6fe0a12010-05-30 00:44:47 +000076 size_t
cristy3ed852e2009-09-05 21:47:34 +000077 size;
78
cristyf6fe0a12010-05-30 00:44:47 +000079 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000080 width,
81 height;
82
83 unsigned short
84 planes,
85 bits_per_pixel;
86
cristyf6fe0a12010-05-30 00:44:47 +000087 size_t
cristy3ed852e2009-09-05 21:47:34 +000088 compression,
89 image_size,
90 x_pixels,
91 y_pixels,
92 number_colors,
93 red_mask,
94 green_mask,
95 blue_mask,
96 alpha_mask,
97 colors_important;
98
cristyf6fe0a12010-05-30 00:44:47 +000099 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000100 colorspace;
101
102 PointInfo
103 red_primary,
104 green_primary,
105 blue_primary,
106 gamma_scale;
107} DIBInfo;
108
109/*
110 Forward declarations.
111*/
112static MagickBooleanType
113 WriteDIBImage(const ImageInfo *,Image *);
114
115/*
116%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
117% %
118% %
119% %
120% D e c o d e I m a g e %
121% %
122% %
123% %
124%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
125%
126% DecodeImage unpacks the packed image pixels into runlength-encoded
127% pixel packets.
128%
129% The format of the DecodeImage method is:
130%
131% MagickBooleanType DecodeImage(Image *image,
132% const MagickBooleanType compression,unsigned char *pixels)
133%
134% A description of each parameter follows:
135%
136% o image: the address of a structure of type Image.
137%
138% o compression: A value of 1 means the compressed pixels are runlength
139% encoded for a 256-color bitmap. A value of 2 means a 16-color bitmap.
140%
141% o pixels: The address of a byte (8 bits) array of pixel data created by
142% the decoding process.
143%
144*/
145
146static inline size_t MagickMin(const size_t x,const size_t y)
147{
148 if (x < y)
149 return(x);
150 return(y);
151}
152
153static MagickBooleanType DecodeImage(Image *image,
154 const MagickBooleanType compression,unsigned char *pixels)
155{
cristy0157aea2010-04-24 21:12:18 +0000156#if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__MINGW32__)
cristy3ed852e2009-09-05 21:47:34 +0000157#define BI_RGB 0
158#define BI_RLE8 1
159#define BI_RLE4 2
160#define BI_BITFIELDS 3
161#endif
162
163 int
164 count;
165
cristybb503372010-05-27 20:51:26 +0000166 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000167 y;
168
cristybb503372010-05-27 20:51:26 +0000169 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000170 i,
171 x;
172
173 register unsigned char
174 *p,
175 *q;
176
177 unsigned char
178 byte;
179
180 assert(image != (Image *) NULL);
181 assert(image->signature == MagickSignature);
182 if (image->debug != MagickFalse)
183 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
184 assert(pixels != (unsigned char *) NULL);
185 (void) ResetMagickMemory(pixels,0,(size_t) image->columns*image->rows*
186 sizeof(*pixels));
187 byte=0;
188 x=0;
189 p=pixels;
190 q=pixels+(size_t) image->columns*image->rows;
cristybb503372010-05-27 20:51:26 +0000191 for (y=0; y < (ssize_t) image->rows; )
cristy3ed852e2009-09-05 21:47:34 +0000192 {
193 if ((p < pixels) || (p >= q))
194 break;
195 count=ReadBlobByte(image);
196 if (count == EOF)
197 break;
198 if (count != 0)
199 {
200 count=(int) MagickMin((size_t) count,(size_t) (q-p));
201 /*
202 Encoded mode.
203 */
204 byte=(unsigned char) ReadBlobByte(image);
205 if (compression == BI_RLE8)
206 {
207 for (i=0; i < count; i++)
208 *p++=(unsigned char) byte;
209 }
210 else
211 {
212 for (i=0; i < count; i++)
213 *p++=(unsigned char)
214 ((i & 0x01) != 0 ? (byte & 0x0f) : ((byte >> 4) & 0x0f));
215 }
216 x+=count;
217 }
218 else
219 {
220 /*
221 Escape mode.
222 */
223 count=ReadBlobByte(image);
224 if (count == 0x01)
225 return(MagickTrue);
226 switch (count)
227 {
228 case 0x00:
229 {
230 /*
231 End of line.
232 */
233 x=0;
234 y++;
235 p=pixels+y*image->columns;
236 break;
237 }
238 case 0x02:
239 {
240 /*
241 Delta mode.
242 */
243 x+=ReadBlobByte(image);
244 y+=ReadBlobByte(image);
245 p=pixels+y*image->columns+x;
246 break;
247 }
248 default:
249 {
250 /*
251 Absolute mode.
252 */
253 count=(int) MagickMin((size_t) count,(size_t) (q-p));
254 if (compression == BI_RLE8)
255 for (i=0; i < count; i++)
256 *p++=(unsigned char) ReadBlobByte(image);
257 else
258 for (i=0; i < count; i++)
259 {
260 if ((i & 0x01) == 0)
261 byte=(unsigned char) ReadBlobByte(image);
262 *p++=(unsigned char)
263 ((i & 0x01) != 0 ? (byte & 0x0f) : ((byte >> 4) & 0x0f));
264 }
265 x+=count;
266 /*
267 Read pad byte.
268 */
269 if (compression == BI_RLE8)
270 {
271 if ((count & 0x01) != 0)
272 (void) ReadBlobByte(image);
273 }
274 else
275 if (((count & 0x03) == 1) || ((count & 0x03) == 2))
276 (void) ReadBlobByte(image);
277 break;
278 }
279 }
280 }
281 if (SetImageProgress(image,LoadImageTag,y,image->rows) == MagickFalse)
282 break;
283 }
284 (void) ReadBlobByte(image); /* end of line */
285 (void) ReadBlobByte(image);
286 return(MagickTrue);
287}
288
289/*
290%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
291% %
292% %
293% %
294% E n c o d e I m a g e %
295% %
296% %
297% %
298%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
299%
300% EncodeImage compresses pixels using a runlength encoded format.
301%
302% The format of the EncodeImage method is:
303%
304% static MagickBooleanType EncodeImage(Image *image,
cristybb503372010-05-27 20:51:26 +0000305% const size_t bytes_per_line,const unsigned char *pixels,
cristy3ed852e2009-09-05 21:47:34 +0000306% unsigned char *compressed_pixels)
307%
308% A description of each parameter follows:
309%
310% o image: The image.
311%
312% o bytes_per_line: the number of bytes in a scanline of compressed pixels
313%
314% o pixels: The address of a byte (8 bits) array of pixel data created by
315% the compression process.
316%
317% o compressed_pixels: The address of a byte (8 bits) array of compressed
318% pixel data.
319%
320*/
cristybb503372010-05-27 20:51:26 +0000321static size_t EncodeImage(Image *image,const size_t bytes_per_line,
cristy3ed852e2009-09-05 21:47:34 +0000322 const unsigned char *pixels,unsigned char *compressed_pixels)
323{
cristybb503372010-05-27 20:51:26 +0000324 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000325 y;
326
327 register const unsigned char
328 *p;
329
cristybb503372010-05-27 20:51:26 +0000330 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000331 i,
332 x;
333
334 register unsigned char
335 *q;
336
337 /*
338 Runlength encode pixels.
339 */
340 assert(image != (Image *) NULL);
341 assert(image->signature == MagickSignature);
342 if (image->debug != MagickFalse)
343 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
344 assert(pixels != (const unsigned char *) NULL);
345 assert(compressed_pixels != (unsigned char *) NULL);
346 p=pixels;
347 q=compressed_pixels;
348 i=0;
cristybb503372010-05-27 20:51:26 +0000349 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000350 {
cristybb503372010-05-27 20:51:26 +0000351 for (x=0; x < (ssize_t) bytes_per_line; x+=i)
cristy3ed852e2009-09-05 21:47:34 +0000352 {
353 /*
354 Determine runlength.
355 */
cristybb503372010-05-27 20:51:26 +0000356 for (i=1; ((x+i) < (ssize_t) bytes_per_line); i++)
cristy3ed852e2009-09-05 21:47:34 +0000357 if ((*(p+i) != *p) || (i == 255))
358 break;
359 *q++=(unsigned char) i;
360 *q++=(*p);
361 p+=i;
362 }
363 /*
364 End of line.
365 */
366 *q++=0x00;
367 *q++=0x00;
368 if (SetImageProgress(image,LoadImageTag,y,image->rows) == MagickFalse)
369 break;
370 }
371 /*
372 End of bitmap.
373 */
374 *q++=0;
375 *q++=0x01;
376 return((size_t) (q-compressed_pixels));
377}
378
379/*
380%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
381% %
382% %
383% %
384% I s D I B %
385% %
386% %
387% %
388%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
389%
390% IsDIB() returns MagickTrue if the image format type, identified by the
391% magick string, is DIB.
392%
393% The format of the IsDIB method is:
394%
395% MagickBooleanType IsDIB(const unsigned char *magick,const size_t length)
396%
397% A description of each parameter follows:
398%
399% o magick: compare image format pattern against these bytes.
400%
401% o length: Specifies the length of the magick string.
402%
403*/
404static MagickBooleanType IsDIB(const unsigned char *magick,const size_t length)
405{
406 if (length < 2)
407 return(MagickFalse);
408 if (memcmp(magick,"\050\000",2) == 0)
409 return(MagickTrue);
410 return(MagickFalse);
411}
412
413/*
414%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
415% %
416% %
417% %
418% R e a d D I B I m a g e %
419% %
420% %
421% %
422%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
423%
424% ReadDIBImage() reads a Microsoft Windows bitmap image file and
425% returns it. It allocates the memory necessary for the new Image structure
426% and returns a pointer to the new image.
427%
428% The format of the ReadDIBImage method is:
429%
430% image=ReadDIBImage(image_info)
431%
432% A description of each parameter follows:
433%
434% o image_info: the image info.
435%
436% o exception: return any errors or warnings in this structure.
437%
438*/
439
cristybb503372010-05-27 20:51:26 +0000440static inline ssize_t MagickAbsoluteValue(const ssize_t x)
cristy3ed852e2009-09-05 21:47:34 +0000441{
442 if (x < 0)
443 return(-x);
444 return(x);
445}
446
447static inline size_t MagickMax(const size_t x,const size_t y)
448{
449 if (x > y)
450 return(x);
451 return(y);
452}
453
454static Image *ReadDIBImage(const ImageInfo *image_info,ExceptionInfo *exception)
455{
456 DIBInfo
457 dib_info;
458
459 Image
460 *image;
461
cristy3ed852e2009-09-05 21:47:34 +0000462 MagickBooleanType
463 status;
464
cristy4c08aed2011-07-01 19:47:50 +0000465 Quantum
466 index;
cristy3ed852e2009-09-05 21:47:34 +0000467
cristybb503372010-05-27 20:51:26 +0000468 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000469 x;
470
cristy4c08aed2011-07-01 19:47:50 +0000471 register Quantum
cristy3ed852e2009-09-05 21:47:34 +0000472 *q;
473
cristybb503372010-05-27 20:51:26 +0000474 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000475 i;
476
477 register unsigned char
478 *p;
479
480 size_t
cristyddbc41b2011-04-24 14:27:48 +0000481 bytes_per_line,
cristy3ed852e2009-09-05 21:47:34 +0000482 length;
483
484 ssize_t
cristy4c08aed2011-07-01 19:47:50 +0000485 bit,
486 count,
487 y;
488
cristy3ed852e2009-09-05 21:47:34 +0000489
490 unsigned char
491 *pixels;
492
cristy3ed852e2009-09-05 21:47:34 +0000493 /*
494 Open image file.
495 */
496 assert(image_info != (const ImageInfo *) NULL);
497 assert(image_info->signature == MagickSignature);
498 if (image_info->debug != MagickFalse)
499 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
500 image_info->filename);
501 assert(exception != (ExceptionInfo *) NULL);
502 assert(exception->signature == MagickSignature);
503 image=AcquireImage(image_info);
504 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
505 if (status == MagickFalse)
506 {
507 image=DestroyImageList(image);
508 return((Image *) NULL);
509 }
510 /*
511 Determine if this a DIB file.
512 */
513 (void) ResetMagickMemory(&dib_info,0,sizeof(dib_info));
514 dib_info.size=ReadBlobLSBLong(image);
515 if (dib_info.size!=40)
516 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
517 /*
518 Microsoft Windows 3.X DIB image file.
519 */
520 dib_info.width=(short) ReadBlobLSBLong(image);
521 dib_info.height=(short) ReadBlobLSBLong(image);
522 dib_info.planes=ReadBlobLSBShort(image);
523 dib_info.bits_per_pixel=ReadBlobLSBShort(image);
524 dib_info.compression=ReadBlobLSBLong(image);
525 dib_info.image_size=ReadBlobLSBLong(image);
526 dib_info.x_pixels=ReadBlobLSBLong(image);
527 dib_info.y_pixels=ReadBlobLSBLong(image);
528 dib_info.number_colors=ReadBlobLSBLong(image);
529 dib_info.colors_important=ReadBlobLSBLong(image);
530 if ((dib_info.compression == BI_BITFIELDS) &&
531 ((dib_info.bits_per_pixel == 16) || (dib_info.bits_per_pixel == 32)))
532 {
533 dib_info.red_mask=ReadBlobLSBLong(image);
534 dib_info.green_mask=ReadBlobLSBLong(image);
535 dib_info.blue_mask=ReadBlobLSBLong(image);
536 }
537 image->matte=dib_info.bits_per_pixel == 32 ? MagickTrue : MagickFalse;
cristybb503372010-05-27 20:51:26 +0000538 image->columns=(size_t) MagickAbsoluteValue(dib_info.width);
539 image->rows=(size_t) MagickAbsoluteValue(dib_info.height);
cristy3ed852e2009-09-05 21:47:34 +0000540 image->depth=8;
541 if ((dib_info.number_colors != 0) || (dib_info.bits_per_pixel < 16))
542 {
cristyeaedf062010-05-29 22:36:02 +0000543 size_t
544 one;
545
cristy3ed852e2009-09-05 21:47:34 +0000546 image->storage_class=PseudoClass;
547 image->colors=dib_info.number_colors;
cristyeaedf062010-05-29 22:36:02 +0000548 one=1;
cristy3ed852e2009-09-05 21:47:34 +0000549 if (image->colors == 0)
cristyeaedf062010-05-29 22:36:02 +0000550 image->colors=one << dib_info.bits_per_pixel;
cristy3ed852e2009-09-05 21:47:34 +0000551 }
552 if (image_info->size)
553 {
554 RectangleInfo
555 geometry;
556
557 MagickStatusType
558 flags;
559
560 flags=ParseAbsoluteGeometry(image_info->size,&geometry);
561 if (flags & WidthValue)
562 if ((geometry.width != 0) && (geometry.width < image->columns))
563 image->columns=geometry.width;
564 if (flags & HeightValue)
565 if ((geometry.height != 0) && (geometry.height < image->rows))
566 image->rows=geometry.height;
567 }
568 if (image->storage_class == PseudoClass)
569 {
570 size_t
571 length,
572 packet_size;
573
574 unsigned char
575 *dib_colormap;
576
577 /*
578 Read DIB raster colormap.
579 */
580 if (AcquireImageColormap(image,image->colors) == MagickFalse)
581 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
582 length=(size_t) image->colors;
583 dib_colormap=(unsigned char *) AcquireQuantumMemory(length,
584 4*sizeof(*dib_colormap));
585 if (dib_colormap == (unsigned char *) NULL)
586 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
587 packet_size=4;
588 count=ReadBlob(image,packet_size*image->colors,dib_colormap);
589 if (count != (ssize_t) (packet_size*image->colors))
590 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
591 p=dib_colormap;
cristybb503372010-05-27 20:51:26 +0000592 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +0000593 {
594 image->colormap[i].blue=ScaleCharToQuantum(*p++);
595 image->colormap[i].green=ScaleCharToQuantum(*p++);
596 image->colormap[i].red=ScaleCharToQuantum(*p++);
597 if (packet_size == 4)
598 p++;
599 }
600 dib_colormap=(unsigned char *) RelinquishMagickMemory(dib_colormap);
601 }
602 /*
603 Read image data.
604 */
605 if (dib_info.compression == BI_RLE4)
606 dib_info.bits_per_pixel<<=1;
607 bytes_per_line=4*((image->columns*dib_info.bits_per_pixel+31)/32);
608 length=bytes_per_line*image->rows;
609 pixels=(unsigned char *) AcquireQuantumMemory((size_t) image->rows,
610 MagickMax(bytes_per_line,image->columns+256UL)*sizeof(*pixels));
611 if (pixels == (unsigned char *) NULL)
612 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
613 if ((dib_info.compression == BI_RGB) ||
614 (dib_info.compression == BI_BITFIELDS))
615 {
616 count=ReadBlob(image,length,pixels);
617 if (count != (ssize_t) (length))
618 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
619 }
620 else
621 {
622 /*
623 Convert run-length encoded raster pixels.
624 */
625 status=DecodeImage(image,dib_info.compression ? MagickTrue : MagickFalse,
626 pixels);
627 if (status == MagickFalse)
628 ThrowReaderException(CorruptImageError,"UnableToRunlengthDecodeImage");
629 }
630 /*
631 Initialize image structure.
632 */
633 image->units=PixelsPerCentimeterResolution;
634 image->x_resolution=(double) dib_info.x_pixels/100.0;
635 image->y_resolution=(double) dib_info.y_pixels/100.0;
636 /*
637 Convert DIB raster image to pixel packets.
638 */
639 switch (dib_info.bits_per_pixel)
640 {
641 case 1:
642 {
643 /*
644 Convert bitmap scanline.
645 */
cristybb503372010-05-27 20:51:26 +0000646 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +0000647 {
648 p=pixels+(image->rows-y-1)*bytes_per_line;
649 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000650 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000651 break;
cristybb503372010-05-27 20:51:26 +0000652 for (x=0; x < ((ssize_t) image->columns-7); x+=8)
cristy3ed852e2009-09-05 21:47:34 +0000653 {
654 for (bit=0; bit < 8; bit++)
655 {
cristy4c08aed2011-07-01 19:47:50 +0000656 index=(Quantum) ((*p) & (0x80 >> bit) ? 0x01 : 0x00);
657 SetPixelIndex(image,index,q);
658 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000659 }
660 p++;
661 }
662 if ((image->columns % 8) != 0)
663 {
cristybb503372010-05-27 20:51:26 +0000664 for (bit=0; bit < (ssize_t) (image->columns % 8); bit++)
cristy3ed852e2009-09-05 21:47:34 +0000665 {
cristy4c08aed2011-07-01 19:47:50 +0000666 index=(Quantum) ((*p) & (0x80 >> bit) ? 0x01 : 0x00);
667 SetPixelIndex(image,index,q);
668 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000669 }
670 p++;
671 }
672 if (SyncAuthenticPixels(image,exception) == MagickFalse)
673 break;
674 if (image->previous == (Image *) NULL)
675 {
676 status=SetImageProgress(image,LoadImageTag,image->rows-y-1,
677 image->rows);
678 if (status == MagickFalse)
679 break;
680 }
681 }
cristyddbc41b2011-04-24 14:27:48 +0000682 (void) SyncImage(image);
cristy3ed852e2009-09-05 21:47:34 +0000683 break;
684 }
685 case 4:
686 {
687 /*
688 Convert PseudoColor scanline.
689 */
cristybb503372010-05-27 20:51:26 +0000690 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +0000691 {
692 p=pixels+(image->rows-y-1)*bytes_per_line;
693 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000694 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000695 break;
cristybb503372010-05-27 20:51:26 +0000696 for (x=0; x < ((ssize_t) image->columns-1); x+=2)
cristy3ed852e2009-09-05 21:47:34 +0000697 {
698 index=ConstrainColormapIndex(image,(*p >> 4) & 0xf);
cristy4c08aed2011-07-01 19:47:50 +0000699 SetPixelIndex(image,index,q);
700 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000701 index=ConstrainColormapIndex(image,*p & 0xf);
cristy4c08aed2011-07-01 19:47:50 +0000702 SetPixelIndex(image,index,q);
cristy3ed852e2009-09-05 21:47:34 +0000703 p++;
cristy4c08aed2011-07-01 19:47:50 +0000704 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000705 }
706 if ((image->columns % 2) != 0)
707 {
708 index=ConstrainColormapIndex(image,(*p >> 4) & 0xf);
cristy4c08aed2011-07-01 19:47:50 +0000709 SetPixelIndex(image,index,q);
710 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000711 p++;
712 }
713 if (SyncAuthenticPixels(image,exception) == MagickFalse)
714 break;
715 if (image->previous == (Image *) NULL)
716 {
717 status=SetImageProgress(image,LoadImageTag,image->rows-y-1,
718 image->rows);
719 if (status == MagickFalse)
720 break;
721 }
722 }
cristyddbc41b2011-04-24 14:27:48 +0000723 (void) SyncImage(image);
cristy3ed852e2009-09-05 21:47:34 +0000724 break;
725 }
726 case 8:
727 {
728 /*
729 Convert PseudoColor scanline.
730 */
731 if ((dib_info.compression == BI_RLE8) ||
732 (dib_info.compression == BI_RLE4))
733 bytes_per_line=image->columns;
cristybb503372010-05-27 20:51:26 +0000734 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +0000735 {
736 p=pixels+(image->rows-y-1)*bytes_per_line;
737 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000738 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000739 break;
cristybb503372010-05-27 20:51:26 +0000740 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000741 {
742 index=ConstrainColormapIndex(image,*p);
cristy4c08aed2011-07-01 19:47:50 +0000743 SetPixelIndex(image,index,q);
cristy3ed852e2009-09-05 21:47:34 +0000744 p++;
cristy4c08aed2011-07-01 19:47:50 +0000745 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000746 }
747 if (SyncAuthenticPixels(image,exception) == MagickFalse)
748 break;
749 if (image->previous == (Image *) NULL)
750 {
751 status=SetImageProgress(image,LoadImageTag,image->rows-y-1,
752 image->rows);
753 if (status == MagickFalse)
754 break;
755 }
756 }
cristyddbc41b2011-04-24 14:27:48 +0000757 (void) SyncImage(image);
cristy3ed852e2009-09-05 21:47:34 +0000758 break;
759 }
760 case 16:
761 {
762 unsigned short
763 word;
764
765 /*
766 Convert PseudoColor scanline.
767 */
768 image->storage_class=DirectClass;
769 if (dib_info.compression == BI_RLE8)
770 bytes_per_line=2*image->columns;
cristybb503372010-05-27 20:51:26 +0000771 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +0000772 {
773 p=pixels+(image->rows-y-1)*bytes_per_line;
774 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000775 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000776 break;
cristybb503372010-05-27 20:51:26 +0000777 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000778 {
779 word=(*p++);
780 word|=(*p++ << 8);
781 if (dib_info.red_mask == 0)
782 {
cristy4c08aed2011-07-01 19:47:50 +0000783 SetPixelRed(image,ScaleCharToQuantum(ScaleColor5to8(
784 (unsigned char) ((word >> 10) & 0x1f))),q);
785 SetPixelGreen(image,ScaleCharToQuantum(ScaleColor5to8(
786 (unsigned char) ((word >> 5) & 0x1f))),q);
787 SetPixelBlue(image,ScaleCharToQuantum(ScaleColor5to8(
788 (unsigned char) (word & 0x1f))),q);
cristy3ed852e2009-09-05 21:47:34 +0000789 }
790 else
791 {
cristy4c08aed2011-07-01 19:47:50 +0000792 SetPixelRed(image,ScaleCharToQuantum(ScaleColor5to8(
793 (unsigned char) ((word >> 11) & 0x1f))),q);
794 SetPixelGreen(image,ScaleCharToQuantum(ScaleColor6to8(
795 (unsigned char) ((word >> 5) & 0x3f))),q);
796 SetPixelBlue(image,ScaleCharToQuantum(ScaleColor5to8(
797 (unsigned char) (word & 0x1f))),q);
cristy3ed852e2009-09-05 21:47:34 +0000798 }
cristy4c08aed2011-07-01 19:47:50 +0000799 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000800 }
801 if (SyncAuthenticPixels(image,exception) == MagickFalse)
802 break;
803 if (image->previous == (Image *) NULL)
804 {
805 status=SetImageProgress(image,LoadImageTag,image->rows-y-1,
806 image->rows);
807 if (status == MagickFalse)
808 break;
809 }
810 }
811 break;
812 }
813 case 24:
814 case 32:
815 {
816 /*
817 Convert DirectColor scanline.
818 */
cristybb503372010-05-27 20:51:26 +0000819 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +0000820 {
821 p=pixels+(image->rows-y-1)*bytes_per_line;
822 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000823 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000824 break;
cristybb503372010-05-27 20:51:26 +0000825 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000826 {
cristy4c08aed2011-07-01 19:47:50 +0000827 SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
828 SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
829 SetPixelRed(image,ScaleCharToQuantum(*p++),q);
cristy3ed852e2009-09-05 21:47:34 +0000830 if (image->matte != MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000831 SetPixelAlpha(image,ScaleCharToQuantum(*p++),q);
832 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 default:
847 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
848 }
849 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
850 if (EOFBlob(image) != MagickFalse)
851 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
852 image->filename);
853 if (dib_info.height < 0)
854 {
855 Image
856 *flipped_image;
857
858 /*
859 Correct image orientation.
860 */
861 flipped_image=FlipImage(image,exception);
cristybbfd4cd2010-04-13 21:54:39 +0000862 if (flipped_image != (Image *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000863 {
cristybbfd4cd2010-04-13 21:54:39 +0000864 DuplicateBlob(flipped_image,image);
865 image=DestroyImage(image);
866 image=flipped_image;
cristy3ed852e2009-09-05 21:47:34 +0000867 }
cristy3ed852e2009-09-05 21:47:34 +0000868 }
869 (void) CloseBlob(image);
870 return(GetFirstImageInList(image));
871}
872
873/*
874%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
875% %
876% %
877% %
878% R e g i s t e r D I B I m a g e %
879% %
880% %
881% %
882%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
883%
884% RegisterDIBImage() adds attributes for the DIB image format to
885% the list of supported formats. The attributes include the image format
886% tag, a method to read and/or write the format, whether the format
887% supports the saving of more than one frame to the same file or blob,
888% whether the format supports native in-memory I/O, and a brief
889% description of the format.
890%
891% The format of the RegisterDIBImage method is:
892%
cristybb503372010-05-27 20:51:26 +0000893% size_t RegisterDIBImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000894%
895*/
cristybb503372010-05-27 20:51:26 +0000896ModuleExport size_t RegisterDIBImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000897{
898 MagickInfo
899 *entry;
900
901 entry=SetMagickInfo("DIB");
902 entry->decoder=(DecodeImageHandler *) ReadDIBImage;
903 entry->encoder=(EncodeImageHandler *) WriteDIBImage;
904 entry->magick=(IsImageFormatHandler *) IsDIB;
905 entry->adjoin=MagickFalse;
906 entry->stealth=MagickTrue;
907 entry->description=ConstantString(
908 "Microsoft Windows 3.X Packed Device-Independent Bitmap");
909 entry->module=ConstantString("DIB");
910 (void) RegisterMagickInfo(entry);
911 return(MagickImageCoderSignature);
912}
913
914/*
915%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
916% %
917% %
918% %
919% U n r e g i s t e r D I B I m a g e %
920% %
921% %
922% %
923%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
924%
925% UnregisterDIBImage() removes format registrations made by the
926% DIB module from the list of supported formats.
927%
928% The format of the UnregisterDIBImage method is:
929%
930% UnregisterDIBImage(void)
931%
932*/
933ModuleExport void UnregisterDIBImage(void)
934{
935 (void) UnregisterMagickInfo("DIB");
936}
937
938/*
939%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
940% %
941% %
942% %
943% W r i t e D I B I m a g e %
944% %
945% %
946% %
947%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
948%
949% WriteDIBImage() writes an image in Microsoft Windows bitmap encoded
950% image format.
951%
952% The format of the WriteDIBImage method is:
953%
954% MagickBooleanType WriteDIBImage(const ImageInfo *image_info,Image *image)
955%
956% A description of each parameter follows.
957%
958% o image_info: the image info.
959%
960% o image: The image.
961%
962*/
963static MagickBooleanType WriteDIBImage(const ImageInfo *image_info,Image *image)
964{
965 DIBInfo
966 dib_info;
967
cristy3ed852e2009-09-05 21:47:34 +0000968 MagickBooleanType
969 status;
970
cristy4c08aed2011-07-01 19:47:50 +0000971 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +0000972 *p;
973
cristybb503372010-05-27 20:51:26 +0000974 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000975 i,
976 x;
977
978 register unsigned char
979 *q;
980
cristyddbc41b2011-04-24 14:27:48 +0000981 size_t
982 bytes_per_line;
983
984 ssize_t
985 y;
986
cristy3ed852e2009-09-05 21:47:34 +0000987 unsigned char
988 *dib_data,
989 *pixels;
990
cristy3ed852e2009-09-05 21:47:34 +0000991 /*
992 Open output image file.
993 */
994 assert(image_info != (const ImageInfo *) NULL);
995 assert(image_info->signature == MagickSignature);
996 assert(image != (Image *) NULL);
997 assert(image->signature == MagickSignature);
998 if (image->debug != MagickFalse)
999 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1000 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1001 if (status == MagickFalse)
1002 return(status);
1003 /*
1004 Initialize DIB raster file header.
1005 */
1006 if (image->colorspace != RGBColorspace)
1007 (void) TransformImageColorspace(image,RGBColorspace);
1008 if (image->storage_class == DirectClass)
1009 {
1010 /*
1011 Full color DIB raster.
1012 */
1013 dib_info.number_colors=0;
1014 dib_info.bits_per_pixel=(unsigned short) (image->matte ? 32 : 24);
1015 }
1016 else
1017 {
1018 /*
1019 Colormapped DIB raster.
1020 */
1021 dib_info.bits_per_pixel=8;
1022 if (image_info->depth > 8)
1023 dib_info.bits_per_pixel=16;
cristy4c08aed2011-07-01 19:47:50 +00001024 if (IsImageMonochrome(image,&image->exception) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001025 dib_info.bits_per_pixel=1;
1026 dib_info.number_colors=(dib_info.bits_per_pixel == 16) ? 0 :
1027 (1UL << dib_info.bits_per_pixel);
1028 }
1029 bytes_per_line=4*((image->columns*dib_info.bits_per_pixel+31)/32);
1030 dib_info.size=40;
cristybb503372010-05-27 20:51:26 +00001031 dib_info.width=(ssize_t) image->columns;
1032 dib_info.height=(ssize_t) image->rows;
cristy3ed852e2009-09-05 21:47:34 +00001033 dib_info.planes=1;
cristybb503372010-05-27 20:51:26 +00001034 dib_info.compression=(size_t) (dib_info.bits_per_pixel == 16 ?
cristy3ed852e2009-09-05 21:47:34 +00001035 BI_BITFIELDS : BI_RGB);
1036 dib_info.image_size=bytes_per_line*image->rows;
1037 dib_info.x_pixels=75*39;
1038 dib_info.y_pixels=75*39;
1039 switch (image->units)
1040 {
1041 case UndefinedResolution:
1042 case PixelsPerInchResolution:
1043 {
cristybb503372010-05-27 20:51:26 +00001044 dib_info.x_pixels=(size_t) (100.0*image->x_resolution/2.54);
1045 dib_info.y_pixels=(size_t) (100.0*image->y_resolution/2.54);
cristy3ed852e2009-09-05 21:47:34 +00001046 break;
1047 }
1048 case PixelsPerCentimeterResolution:
1049 {
cristybb503372010-05-27 20:51:26 +00001050 dib_info.x_pixels=(size_t) (100.0*image->x_resolution);
1051 dib_info.y_pixels=(size_t) (100.0*image->y_resolution);
cristy3ed852e2009-09-05 21:47:34 +00001052 break;
1053 }
1054 }
1055 dib_info.colors_important=dib_info.number_colors;
1056 /*
1057 Convert MIFF to DIB raster pixels.
1058 */
1059 pixels=(unsigned char *) AcquireQuantumMemory(dib_info.image_size,
1060 sizeof(*pixels));
1061 if (pixels == (unsigned char *) NULL)
1062 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1063 (void) ResetMagickMemory(pixels,0,dib_info.image_size);
1064 switch (dib_info.bits_per_pixel)
1065 {
1066 case 1:
1067 {
1068 register unsigned char
1069 bit,
1070 byte;
1071
1072 /*
1073 Convert PseudoClass image to a DIB monochrome image.
1074 */
cristybb503372010-05-27 20:51:26 +00001075 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001076 {
1077 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
cristy4c08aed2011-07-01 19:47:50 +00001078 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001079 break;
cristy3ed852e2009-09-05 21:47:34 +00001080 q=pixels+(image->rows-y-1)*bytes_per_line;
1081 bit=0;
1082 byte=0;
cristybb503372010-05-27 20:51:26 +00001083 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001084 {
1085 byte<<=1;
cristy4c08aed2011-07-01 19:47:50 +00001086 byte|=GetPixelIndex(image,p) != 0 ? 0x01 : 0x00;
cristy3ed852e2009-09-05 21:47:34 +00001087 bit++;
1088 if (bit == 8)
1089 {
1090 *q++=byte;
1091 bit=0;
1092 byte=0;
1093 }
cristy4c08aed2011-07-01 19:47:50 +00001094 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001095 }
1096 if (bit != 0)
1097 {
1098 *q++=(unsigned char) (byte << (8-bit));
1099 x++;
1100 }
cristybb503372010-05-27 20:51:26 +00001101 for (x=(ssize_t) (image->columns+7)/8; x < (ssize_t) bytes_per_line; x++)
cristy3ed852e2009-09-05 21:47:34 +00001102 *q++=0x00;
cristycee97112010-05-28 00:44:52 +00001103 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
cristyddbc41b2011-04-24 14:27:48 +00001104 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001105 if (status == MagickFalse)
1106 break;
1107 }
1108 break;
1109 }
1110 case 8:
1111 {
1112 /*
1113 Convert PseudoClass packet to DIB pixel.
1114 */
cristybb503372010-05-27 20:51:26 +00001115 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001116 {
1117 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
cristy4c08aed2011-07-01 19:47:50 +00001118 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001119 break;
cristy3ed852e2009-09-05 21:47:34 +00001120 q=pixels+(image->rows-y-1)*bytes_per_line;
cristybb503372010-05-27 20:51:26 +00001121 for (x=0; x < (ssize_t) image->columns; x++)
cristy4c08aed2011-07-01 19:47:50 +00001122 {
1123 *q++=(unsigned char) GetPixelIndex(image,p);
1124 p+=GetPixelChannels(image);
1125 }
cristybb503372010-05-27 20:51:26 +00001126 for ( ; x < (ssize_t) bytes_per_line; x++)
cristy3ed852e2009-09-05 21:47:34 +00001127 *q++=0x00;
cristycee97112010-05-28 00:44:52 +00001128 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
cristyddbc41b2011-04-24 14:27:48 +00001129 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001130 if (status == MagickFalse)
1131 break;
1132 }
1133 break;
1134 }
1135 case 16:
1136 {
1137 unsigned short
1138 word;
1139 /*
1140 Convert PseudoClass packet to DIB pixel.
1141 */
cristybb503372010-05-27 20:51:26 +00001142 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001143 {
1144 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
cristy4c08aed2011-07-01 19:47:50 +00001145 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001146 break;
1147 q=pixels+(image->rows-y-1)*bytes_per_line;
cristybb503372010-05-27 20:51:26 +00001148 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001149 {
1150 word=(unsigned short) ((ScaleColor8to5((unsigned char)
cristy4c08aed2011-07-01 19:47:50 +00001151 ScaleQuantumToChar(GetPixelRed(image,p))) << 11) | (ScaleColor8to6(
1152 (unsigned char) ScaleQuantumToChar(GetPixelGreen(image,p))) << 5) |
1153 (ScaleColor8to5((unsigned char) ScaleQuantumToChar((unsigned char)
1154 GetPixelBlue(image,p)) << 0)));
cristy3ed852e2009-09-05 21:47:34 +00001155 *q++=(unsigned char)(word & 0xff);
1156 *q++=(unsigned char)(word >> 8);
cristy4c08aed2011-07-01 19:47:50 +00001157 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001158 }
cristyf6fe0a12010-05-30 00:44:47 +00001159 for (x=(ssize_t) (2*image->columns); x < (ssize_t) bytes_per_line; x++)
cristy3ed852e2009-09-05 21:47:34 +00001160 *q++=0x00;
cristycee97112010-05-28 00:44:52 +00001161 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
cristyddbc41b2011-04-24 14:27:48 +00001162 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001163 if (status == MagickFalse)
1164 break;
1165 }
1166 break;
1167 }
1168 case 24:
1169 case 32:
1170 {
1171 /*
1172 Convert DirectClass packet to DIB RGB pixel.
1173 */
cristybb503372010-05-27 20:51:26 +00001174 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001175 {
1176 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
cristy4c08aed2011-07-01 19:47:50 +00001177 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001178 break;
1179 q=pixels+(image->rows-y-1)*bytes_per_line;
cristybb503372010-05-27 20:51:26 +00001180 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001181 {
cristy4c08aed2011-07-01 19:47:50 +00001182 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
1183 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
1184 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
cristy3ed852e2009-09-05 21:47:34 +00001185 if (image->matte != MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +00001186 *q++=ScaleQuantumToChar(GetPixelAlpha(image,p));
1187 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001188 }
1189 if (dib_info.bits_per_pixel == 24)
cristyf6fe0a12010-05-30 00:44:47 +00001190 for (x=(ssize_t) (3*image->columns); x < (ssize_t) bytes_per_line; x++)
cristy3ed852e2009-09-05 21:47:34 +00001191 *q++=0x00;
cristycee97112010-05-28 00:44:52 +00001192 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
cristyddbc41b2011-04-24 14:27:48 +00001193 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001194 if (status == MagickFalse)
1195 break;
1196 }
1197 break;
1198 }
1199 }
1200 if (dib_info.bits_per_pixel == 8)
1201 if (image_info->compression != NoCompression)
1202 {
1203 size_t
1204 length;
1205
1206 /*
1207 Convert run-length encoded raster pixels.
1208 */
1209 length=2UL*(bytes_per_line+2UL)+2UL;
1210 dib_data=(unsigned char *) AcquireQuantumMemory(length,
1211 (image->rows+2UL)*sizeof(*dib_data));
1212 if (pixels == (unsigned char *) NULL)
1213 {
1214 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1215 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1216 }
cristybb503372010-05-27 20:51:26 +00001217 dib_info.image_size=(size_t) EncodeImage(image,bytes_per_line,
cristy3ed852e2009-09-05 21:47:34 +00001218 pixels,dib_data);
1219 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1220 pixels=dib_data;
1221 dib_info.compression = BI_RLE8;
1222 }
1223 /*
1224 Write DIB header.
1225 */
cristyf6fe0a12010-05-30 00:44:47 +00001226 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.size);
cristyeaedf062010-05-29 22:36:02 +00001227 (void) WriteBlobLSBLong(image,dib_info.width);
cristy3ed852e2009-09-05 21:47:34 +00001228 (void) WriteBlobLSBLong(image,(unsigned short) dib_info.height);
1229 (void) WriteBlobLSBShort(image,(unsigned short) dib_info.planes);
1230 (void) WriteBlobLSBShort(image,dib_info.bits_per_pixel);
cristyf6fe0a12010-05-30 00:44:47 +00001231 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.compression);
1232 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.image_size);
1233 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.x_pixels);
1234 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.y_pixels);
1235 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.number_colors);
1236 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.colors_important);
cristy3ed852e2009-09-05 21:47:34 +00001237 if (image->storage_class == PseudoClass)
1238 {
1239 if (dib_info.bits_per_pixel <= 8)
1240 {
1241 unsigned char
1242 *dib_colormap;
1243
1244 /*
1245 Dump colormap to file.
1246 */
1247 dib_colormap=(unsigned char *) AcquireQuantumMemory((size_t)
1248 (1UL << dib_info.bits_per_pixel),4*sizeof(dib_colormap));
1249 if (dib_colormap == (unsigned char *) NULL)
1250 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1251 q=dib_colormap;
cristybb503372010-05-27 20:51:26 +00001252 for (i=0; i < (ssize_t) MagickMin(image->colors,dib_info.number_colors); i++)
cristy3ed852e2009-09-05 21:47:34 +00001253 {
1254 *q++=ScaleQuantumToChar(image->colormap[i].blue);
1255 *q++=ScaleQuantumToChar(image->colormap[i].green);
1256 *q++=ScaleQuantumToChar(image->colormap[i].red);
1257 *q++=(Quantum) 0x0;
1258 }
cristybb503372010-05-27 20:51:26 +00001259 for ( ; i < (ssize_t) (1L << dib_info.bits_per_pixel); i++)
cristy3ed852e2009-09-05 21:47:34 +00001260 {
1261 *q++=(Quantum) 0x0;
1262 *q++=(Quantum) 0x0;
1263 *q++=(Quantum) 0x0;
1264 *q++=(Quantum) 0x0;
1265 }
1266 (void) WriteBlob(image,(size_t) (4*(1 << dib_info.bits_per_pixel)),
1267 dib_colormap);
1268 dib_colormap=(unsigned char *) RelinquishMagickMemory(dib_colormap);
1269 }
1270 else
1271 if ((dib_info.bits_per_pixel == 16) &&
1272 (dib_info.compression == BI_BITFIELDS))
1273 {
1274 (void) WriteBlobLSBLong(image,0xf800);
1275 (void) WriteBlobLSBLong(image,0x07e0);
1276 (void) WriteBlobLSBLong(image,0x001f);
1277 }
1278 }
1279 (void) WriteBlob(image,dib_info.image_size,pixels);
1280 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1281 (void) CloseBlob(image);
1282 return(MagickTrue);
1283}