blob: 9dd025ea17ac6a06d76adc875f3dbd9aef9a0c64 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% IIIII CCCC OOO N N %
7% I C O O NN N %
8% I C O O N N N %
9% I C O O N NN %
10% IIIII CCCC OOO N N %
11% %
12% %
13% Read Microsoft Windows Icon Format %
14% %
15% Software Design %
16% John Cristy %
17% July 1992 %
18% %
19% %
cristy1454be72011-12-19 01:52:48 +000020% Copyright 1999-2012 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"
glennrpaa192b12012-01-17 21:35:21 +000043#include "MagickCore/artifact.h"
cristy4c08aed2011-07-01 19:47:50 +000044#include "MagickCore/blob.h"
45#include "MagickCore/blob-private.h"
46#include "MagickCore/cache.h"
47#include "MagickCore/colormap.h"
48#include "MagickCore/colorspace.h"
49#include "MagickCore/exception.h"
50#include "MagickCore/exception-private.h"
51#include "MagickCore/image.h"
52#include "MagickCore/image-private.h"
53#include "MagickCore/list.h"
54#include "MagickCore/log.h"
55#include "MagickCore/magick.h"
56#include "MagickCore/memory_.h"
57#include "MagickCore/monitor.h"
58#include "MagickCore/monitor-private.h"
cristy17c826f2011-10-08 00:54:58 +000059#include "MagickCore/nt-base-private.h"
cristy4c08aed2011-07-01 19:47:50 +000060#include "MagickCore/pixel-accessor.h"
61#include "MagickCore/quantize.h"
62#include "MagickCore/quantum-private.h"
63#include "MagickCore/static.h"
64#include "MagickCore/string_.h"
65#include "MagickCore/module.h"
cristy3ed852e2009-09-05 21:47:34 +000066
67/*
68 Define declarations.
69*/
cristy0157aea2010-04-24 21:12:18 +000070#if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__MINGW32__)
cristy3ed852e2009-09-05 21:47:34 +000071#define BI_RGB 0
72#define BI_RLE8 1
73#define BI_BITFIELDS 3
74#endif
75#define MaxIcons 1024
76
77/*
78 Typedef declarations.
79*/
80typedef struct _IconEntry
81{
82 unsigned char
83 width,
84 height,
85 colors,
86 reserved;
87
88 unsigned short int
89 planes,
90 bits_per_pixel;
91
cristybb503372010-05-27 20:51:26 +000092 size_t
cristy3ed852e2009-09-05 21:47:34 +000093 size,
94 offset;
95} IconEntry;
96
97typedef struct _IconFile
98{
99 short
100 reserved,
101 resource_type,
102 count;
103
104 IconEntry
105 directory[MaxIcons];
106} IconFile;
107
108typedef struct _IconInfo
109{
cristybb503372010-05-27 20:51:26 +0000110 size_t
cristy3ed852e2009-09-05 21:47:34 +0000111 file_size,
112 ba_offset,
113 offset_bits,
114 size;
115
cristybb503372010-05-27 20:51:26 +0000116 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000117 width,
118 height;
119
120 unsigned short
121 planes,
122 bits_per_pixel;
123
cristybb503372010-05-27 20:51:26 +0000124 size_t
cristy3ed852e2009-09-05 21:47:34 +0000125 compression,
126 image_size,
127 x_pixels,
128 y_pixels,
129 number_colors,
130 red_mask,
131 green_mask,
132 blue_mask,
133 alpha_mask,
134 colors_important;
135
cristybb503372010-05-27 20:51:26 +0000136 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000137 colorspace;
138} IconInfo;
139
140/*
141 Forward declaractions.
142*/
143static MagickBooleanType
cristy1e178e72011-08-28 19:44:34 +0000144 WriteICONImage(const ImageInfo *,Image *,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000145
146/*
147%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
148% %
149% %
150% %
151% R e a d I C O N I m a g e %
152% %
153% %
154% %
155%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
156%
157% ReadICONImage() reads a Microsoft icon image file and returns it. It
158% allocates the memory necessary for the new Image structure and returns a
159% pointer to the new image.
160%
161% The format of the ReadICONImage method is:
162%
163% Image *ReadICONImage(const ImageInfo *image_info,
164% ExceptionInfo *exception)
165%
166% A description of each parameter follows:
167%
168% o image_info: the image info.
169%
170% o exception: return any errors or warnings in this structure.
171%
172*/
173static Image *ReadICONImage(const ImageInfo *image_info,
174 ExceptionInfo *exception)
175{
176 IconFile
177 icon_file;
178
179 IconInfo
180 icon_info;
181
182 Image
183 *image;
184
cristy3ed852e2009-09-05 21:47:34 +0000185 MagickBooleanType
186 status;
187
cristybb503372010-05-27 20:51:26 +0000188 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000189 i,
190 x;
191
cristy4c08aed2011-07-01 19:47:50 +0000192 register Quantum
cristy3ed852e2009-09-05 21:47:34 +0000193 *q;
194
195 register unsigned char
196 *p;
197
cristybb503372010-05-27 20:51:26 +0000198 size_t
cristy3ed852e2009-09-05 21:47:34 +0000199 bit,
cristyeaedf062010-05-29 22:36:02 +0000200 byte,
cristy3ed852e2009-09-05 21:47:34 +0000201 bytes_per_line,
cristyeaedf062010-05-29 22:36:02 +0000202 one,
cristy3ed852e2009-09-05 21:47:34 +0000203 scanline_pad;
204
cristyebc891a2011-04-24 23:04:16 +0000205 ssize_t
206 count,
207 offset,
208 y;
209
cristy3ed852e2009-09-05 21:47:34 +0000210 /*
211 Open image file.
212 */
213 assert(image_info != (const ImageInfo *) NULL);
214 assert(image_info->signature == MagickSignature);
215 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"%s",image_info->filename);
216 assert(exception != (ExceptionInfo *) NULL);
217 assert(exception->signature == MagickSignature);
cristy1f1de182011-10-05 18:41:34 +0000218 image=AcquireImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +0000219 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
220 if (status == MagickFalse)
221 {
222 image=DestroyImageList(image);
223 return((Image *) NULL);
224 }
225 icon_file.reserved=(short) ReadBlobLSBShort(image);
226 icon_file.resource_type=(short) ReadBlobLSBShort(image);
227 icon_file.count=(short) ReadBlobLSBShort(image);
228 if ((icon_file.reserved != 0) ||
229 ((icon_file.resource_type != 1) && (icon_file.resource_type != 2)) ||
230 (icon_file.count > MaxIcons))
231 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
232 for (i=0; i < icon_file.count; i++)
233 {
234 icon_file.directory[i].width=(unsigned char) ReadBlobByte(image);
235 icon_file.directory[i].height=(unsigned char) ReadBlobByte(image);
236 icon_file.directory[i].colors=(unsigned char) ReadBlobByte(image);
237 icon_file.directory[i].reserved=(unsigned char) ReadBlobByte(image);
238 icon_file.directory[i].planes=(unsigned short) ReadBlobLSBShort(image);
239 icon_file.directory[i].bits_per_pixel=(unsigned short)
240 ReadBlobLSBShort(image);
241 icon_file.directory[i].size=ReadBlobLSBLong(image);
242 icon_file.directory[i].offset=ReadBlobLSBLong(image);
243 }
cristyeaedf062010-05-29 22:36:02 +0000244 one=1;
cristy3ed852e2009-09-05 21:47:34 +0000245 for (i=0; i < icon_file.count; i++)
246 {
247 /*
248 Verify Icon identifier.
249 */
250 offset=(ssize_t) SeekBlob(image,(MagickOffsetType)
251 icon_file.directory[i].offset,SEEK_SET);
252 if (offset < 0)
253 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
254 icon_info.size=ReadBlobLSBLong(image);
cristyd63c0502011-01-03 15:45:11 +0000255 icon_info.width=(unsigned char) ((int) ReadBlobLSBLong(image));
256 icon_info.height=(unsigned char) ((int) ReadBlobLSBLong(image)/2);
cristy4e09e032011-10-05 19:42:10 +0000257 icon_info.planes=ReadBlobLSBShort(image);
258 icon_info.bits_per_pixel=ReadBlobLSBShort(image);
259 if ((icon_info.planes == 18505) && (icon_info.bits_per_pixel == 21060))
cristy3ed852e2009-09-05 21:47:34 +0000260 {
261 Image
262 *icon_image;
263
264 ImageInfo
265 *read_info;
266
cristyf054ee72011-10-05 17:04:08 +0000267 size_t
268 length;
269
270 unsigned char
271 *png;
272
cristy3ed852e2009-09-05 21:47:34 +0000273 /*
274 Icon image encoded as a compressed PNG image.
275 */
cristyf054ee72011-10-05 17:04:08 +0000276 length=icon_file.directory[i].size;
cristy4e09e032011-10-05 19:42:10 +0000277 png=(unsigned char *) AcquireQuantumMemory(length+16,sizeof(*png));
cristyf054ee72011-10-05 17:04:08 +0000278 if (png == (unsigned char *) NULL)
279 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
280 (void) CopyMagickMemory(png,"\211PNG\r\n\032\n\000\000\000\015",12);
cristy4e09e032011-10-05 19:42:10 +0000281 png[12]=(unsigned char) icon_info.planes;
282 png[13]=(unsigned char) (icon_info.planes >> 8);
283 png[14]=(unsigned char) icon_info.bits_per_pixel;
284 png[15]=(unsigned char) (icon_info.bits_per_pixel >> 8);
285 count=ReadBlob(image,length-16,png+16);
286 if (count != (ssize_t) (length-16))
cristyf054ee72011-10-05 17:04:08 +0000287 {
288 png=(unsigned char *) RelinquishMagickMemory(png);
289 ThrowReaderException(CorruptImageError,
290 "InsufficientImageDataInFile");
291 }
cristy3ed852e2009-09-05 21:47:34 +0000292 read_info=CloneImageInfo(image_info);
293 (void) CopyMagickString(read_info->magick,"PNG",MaxTextExtent);
cristy4e09e032011-10-05 19:42:10 +0000294 icon_image=BlobToImage(read_info,png,length+16,exception);
cristy3ed852e2009-09-05 21:47:34 +0000295 read_info=DestroyImageInfo(read_info);
cristyf054ee72011-10-05 17:04:08 +0000296 png=(unsigned char *) RelinquishMagickMemory(png);
cristy47de5a92011-10-05 01:47:42 +0000297 if (icon_image == (Image *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000298 {
cristy47de5a92011-10-05 01:47:42 +0000299 image=DestroyImageList(image);
300 return((Image *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000301 }
cristy47de5a92011-10-05 01:47:42 +0000302 DestroyBlob(icon_image);
303 icon_image->blob=ReferenceBlob(image->blob);
304 ReplaceImageInList(&image,icon_image);
cristy3ed852e2009-09-05 21:47:34 +0000305 }
306 else
307 {
cristyf054ee72011-10-05 17:04:08 +0000308 if (icon_info.bits_per_pixel > 32)
309 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
310 icon_info.compression=ReadBlobLSBLong(image);
311 icon_info.image_size=ReadBlobLSBLong(image);
312 icon_info.x_pixels=ReadBlobLSBLong(image);
313 icon_info.y_pixels=ReadBlobLSBLong(image);
314 icon_info.number_colors=ReadBlobLSBLong(image);
315 icon_info.colors_important=ReadBlobLSBLong(image);
316 image->matte=MagickTrue;
317 image->columns=(size_t) icon_file.directory[i].width;
318 if ((ssize_t) image->columns > icon_info.width)
319 image->columns=(size_t) icon_info.width;
cristy4e09e032011-10-05 19:42:10 +0000320 if (image->columns == 0)
321 image->columns=256;
cristyf054ee72011-10-05 17:04:08 +0000322 image->rows=(size_t) icon_file.directory[i].height;
323 if ((ssize_t) image->rows > icon_info.height)
324 image->rows=(size_t) icon_info.height;
cristy4e09e032011-10-05 19:42:10 +0000325 if (image->rows == 0)
326 image->rows=256;
cristyf054ee72011-10-05 17:04:08 +0000327 image->depth=icon_info.bits_per_pixel;
328 if (image->debug != MagickFalse)
329 {
330 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
331 " scene = %.20g",(double) i);
332 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
333 " size = %.20g",(double) icon_info.size);
334 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
335 " width = %.20g",(double) icon_file.directory[i].width);
336 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
337 " height = %.20g",(double) icon_file.directory[i].height);
338 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
339 " colors = %.20g",(double ) icon_info.number_colors);
340 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
341 " planes = %.20g",(double) icon_info.planes);
342 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
343 " bpp = %.20g",(double) icon_info.bits_per_pixel);
344 }
345 if ((icon_info.number_colors != 0) || (icon_info.bits_per_pixel <= 16))
346 {
347 image->storage_class=PseudoClass;
348 image->colors=icon_info.number_colors;
349 if (image->colors == 0)
350 image->colors=one << icon_info.bits_per_pixel;
351 }
352 if (image->storage_class == PseudoClass)
353 {
354 register ssize_t
355 i;
cristy3ed852e2009-09-05 21:47:34 +0000356
cristyf054ee72011-10-05 17:04:08 +0000357 size_t
358 number_colors,
359 one;
360
361 unsigned char
362 *icon_colormap;
363
364 /*
365 Read Icon raster colormap.
366 */
367 one=1;
368 number_colors=one << icon_info.bits_per_pixel;
369 if (AcquireImageColormap(image,number_colors,exception) == MagickFalse)
370 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
371 icon_colormap=(unsigned char *) AcquireQuantumMemory((size_t)
372 image->colors,4UL*sizeof(*icon_colormap));
373 if (icon_colormap == (unsigned char *) NULL)
374 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
375 count=ReadBlob(image,(size_t) (4*image->colors),icon_colormap);
376 if (count != (ssize_t) (4*image->colors))
377 ThrowReaderException(CorruptImageError,
378 "InsufficientImageDataInFile");
379 p=icon_colormap;
380 for (i=0; i < (ssize_t) image->colors; i++)
381 {
382 image->colormap[i].blue=(Quantum) ScaleCharToQuantum(*p++);
383 image->colormap[i].green=(Quantum) ScaleCharToQuantum(*p++);
384 image->colormap[i].red=(Quantum) ScaleCharToQuantum(*p++);
385 p++;
386 }
387 icon_colormap=(unsigned char *) RelinquishMagickMemory(icon_colormap);
388 }
cristy3ed852e2009-09-05 21:47:34 +0000389 /*
390 Convert Icon raster image to pixel packets.
391 */
cristyf054ee72011-10-05 17:04:08 +0000392 if ((image_info->ping != MagickFalse) &&
393 (image_info->number_scenes != 0))
394 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
395 break;
cristy3ed852e2009-09-05 21:47:34 +0000396 bytes_per_line=(((image->columns*icon_info.bits_per_pixel)+31) &
397 ~31) >> 3;
cristyda16f162011-02-19 23:52:17 +0000398 (void) bytes_per_line;
cristy3ed852e2009-09-05 21:47:34 +0000399 scanline_pad=((((image->columns*icon_info.bits_per_pixel)+31) & ~31)-
400 (image->columns*icon_info.bits_per_pixel)) >> 3;
401 switch (icon_info.bits_per_pixel)
402 {
403 case 1:
404 {
405 /*
406 Convert bitmap scanline.
407 */
cristybb503372010-05-27 20:51:26 +0000408 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +0000409 {
410 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000411 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000412 break;
cristybb503372010-05-27 20:51:26 +0000413 for (x=0; x < (ssize_t) (image->columns-7); x+=8)
cristy3ed852e2009-09-05 21:47:34 +0000414 {
cristyf054ee72011-10-05 17:04:08 +0000415 byte=(size_t) ReadBlobByte(image);
cristy3ed852e2009-09-05 21:47:34 +0000416 for (bit=0; bit < 8; bit++)
cristy4c08aed2011-07-01 19:47:50 +0000417 {
418 SetPixelIndex(image,((byte & (0x80 >> bit)) != 0 ? 0x01 :
419 0x00),q);
cristyed231572011-07-14 02:18:59 +0000420 q+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +0000421 }
cristy3ed852e2009-09-05 21:47:34 +0000422 }
423 if ((image->columns % 8) != 0)
424 {
cristyf054ee72011-10-05 17:04:08 +0000425 byte=(size_t) ReadBlobByte(image);
cristy3ed852e2009-09-05 21:47:34 +0000426 for (bit=0; bit < (image->columns % 8); bit++)
cristy4c08aed2011-07-01 19:47:50 +0000427 {
428 SetPixelIndex(image,((byte & (0x80 >> bit)) != 0 ? 0x01 :
429 0x00),q);
cristyed231572011-07-14 02:18:59 +0000430 q+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +0000431 }
cristy3ed852e2009-09-05 21:47:34 +0000432 }
cristybb503372010-05-27 20:51:26 +0000433 for (x=0; x < (ssize_t) scanline_pad; x++)
cristyf054ee72011-10-05 17:04:08 +0000434 (void) ReadBlobByte(image);
cristy3ed852e2009-09-05 21:47:34 +0000435 if (SyncAuthenticPixels(image,exception) == MagickFalse)
436 break;
437 if (image->previous == (Image *) NULL)
438 {
439 status=SetImageProgress(image,LoadImageTag,image->rows-y-1,
440 image->rows);
441 if (status == MagickFalse)
442 break;
443 }
444 }
445 break;
446 }
447 case 4:
448 {
449 /*
450 Read 4-bit Icon scanline.
451 */
cristybb503372010-05-27 20:51:26 +0000452 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +0000453 {
454 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000455 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000456 break;
cristybb503372010-05-27 20:51:26 +0000457 for (x=0; x < ((ssize_t) image->columns-1); x+=2)
cristy3ed852e2009-09-05 21:47:34 +0000458 {
cristyf054ee72011-10-05 17:04:08 +0000459 byte=(size_t) ReadBlobByte(image);
cristy4c08aed2011-07-01 19:47:50 +0000460 SetPixelIndex(image,((byte >> 4) & 0xf),q);
cristyed231572011-07-14 02:18:59 +0000461 q+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +0000462 SetPixelIndex(image,((byte) & 0xf),q);
cristyed231572011-07-14 02:18:59 +0000463 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000464 }
465 if ((image->columns % 2) != 0)
466 {
cristyf054ee72011-10-05 17:04:08 +0000467 byte=(size_t) ReadBlobByte(image);
cristy4c08aed2011-07-01 19:47:50 +0000468 SetPixelIndex(image,((byte >> 4) & 0xf),q);
cristyed231572011-07-14 02:18:59 +0000469 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000470 }
cristybb503372010-05-27 20:51:26 +0000471 for (x=0; x < (ssize_t) scanline_pad; x++)
cristyf054ee72011-10-05 17:04:08 +0000472 (void) ReadBlobByte(image);
cristy3ed852e2009-09-05 21:47:34 +0000473 if (SyncAuthenticPixels(image,exception) == MagickFalse)
474 break;
475 if (image->previous == (Image *) NULL)
476 {
477 status=SetImageProgress(image,LoadImageTag,image->rows-y-1,
478 image->rows);
479 if (status == MagickFalse)
480 break;
481 }
482 }
483 break;
484 }
485 case 8:
486 {
487 /*
488 Convert PseudoColor scanline.
489 */
cristybb503372010-05-27 20:51:26 +0000490 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +0000491 {
492 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000493 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000494 break;
cristybb503372010-05-27 20:51:26 +0000495 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000496 {
cristyf054ee72011-10-05 17:04:08 +0000497 byte=(size_t) ReadBlobByte(image);
cristy4c08aed2011-07-01 19:47:50 +0000498 SetPixelIndex(image,byte,q);
cristyed231572011-07-14 02:18:59 +0000499 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000500 }
cristybb503372010-05-27 20:51:26 +0000501 for (x=0; x < (ssize_t) scanline_pad; x++)
cristyf054ee72011-10-05 17:04:08 +0000502 (void) ReadBlobByte(image);
cristy3ed852e2009-09-05 21:47:34 +0000503 if (SyncAuthenticPixels(image,exception) == MagickFalse)
504 break;
505 if (image->previous == (Image *) NULL)
506 {
507 status=SetImageProgress(image,LoadImageTag,image->rows-y-1,
508 image->rows);
509 if (status == MagickFalse)
510 break;
511 }
512 }
513 break;
514 }
515 case 16:
516 {
517 /*
518 Convert PseudoColor scanline.
519 */
cristybb503372010-05-27 20:51:26 +0000520 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +0000521 {
522 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000523 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000524 break;
cristybb503372010-05-27 20:51:26 +0000525 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000526 {
cristyf054ee72011-10-05 17:04:08 +0000527 byte=(size_t) ReadBlobByte(image);
528 byte|=(size_t) (ReadBlobByte(image) << 8);
cristy4c08aed2011-07-01 19:47:50 +0000529 SetPixelIndex(image,byte,q);
cristyed231572011-07-14 02:18:59 +0000530 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000531 }
cristybb503372010-05-27 20:51:26 +0000532 for (x=0; x < (ssize_t) scanline_pad; x++)
cristyf054ee72011-10-05 17:04:08 +0000533 (void) ReadBlobByte(image);
cristy3ed852e2009-09-05 21:47:34 +0000534 if (SyncAuthenticPixels(image,exception) == MagickFalse)
535 break;
536 if (image->previous == (Image *) NULL)
537 {
538 status=SetImageProgress(image,LoadImageTag,image->rows-y-1,
539 image->rows);
540 if (status == MagickFalse)
541 break;
542 }
543 }
544 break;
545 }
546 case 24:
547 case 32:
548 {
549 /*
550 Convert DirectColor scanline.
551 */
cristybb503372010-05-27 20:51:26 +0000552 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +0000553 {
554 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000555 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000556 break;
cristybb503372010-05-27 20:51:26 +0000557 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000558 {
cristyf054ee72011-10-05 17:04:08 +0000559 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
560 ReadBlobByte(image)),q);
561 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
562 ReadBlobByte(image)),q);
563 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
564 ReadBlobByte(image)),q);
cristy3ed852e2009-09-05 21:47:34 +0000565 if (icon_info.bits_per_pixel == 32)
cristyf054ee72011-10-05 17:04:08 +0000566 SetPixelAlpha(image,ScaleCharToQuantum((unsigned char)
567 ReadBlobByte(image)),q);
cristyed231572011-07-14 02:18:59 +0000568 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000569 }
570 if (icon_info.bits_per_pixel == 24)
cristybb503372010-05-27 20:51:26 +0000571 for (x=0; x < (ssize_t) scanline_pad; x++)
cristyf054ee72011-10-05 17:04:08 +0000572 (void) ReadBlobByte(image);
cristy3ed852e2009-09-05 21:47:34 +0000573 if (SyncAuthenticPixels(image,exception) == MagickFalse)
574 break;
575 if (image->previous == (Image *) NULL)
576 {
577 status=SetImageProgress(image,LoadImageTag,image->rows-y-1,
578 image->rows);
579 if (status == MagickFalse)
580 break;
581 }
582 }
583 break;
584 }
585 default:
586 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
587 }
cristy5dd71882010-08-01 20:53:13 +0000588 if (image_info->ping == MagickFalse)
cristyea1a8aa2011-10-20 13:24:06 +0000589 (void) SyncImage(image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000590 if (icon_info.bits_per_pixel != 32)
591 {
592 /*
593 Read the ICON alpha mask.
594 */
595 image->storage_class=DirectClass;
cristybb503372010-05-27 20:51:26 +0000596 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +0000597 {
598 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000599 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000600 break;
cristybb503372010-05-27 20:51:26 +0000601 for (x=0; x < ((ssize_t) image->columns-7); x+=8)
cristy3ed852e2009-09-05 21:47:34 +0000602 {
cristyf054ee72011-10-05 17:04:08 +0000603 byte=(size_t) ReadBlobByte(image);
cristy3ed852e2009-09-05 21:47:34 +0000604 for (bit=0; bit < 8; bit++)
cristy4c08aed2011-07-01 19:47:50 +0000605 {
606 SetPixelAlpha(image,(((byte & (0x80 >> bit)) != 0) ?
607 TransparentAlpha : OpaqueAlpha),q);
cristyed231572011-07-14 02:18:59 +0000608 q+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +0000609 }
cristy3ed852e2009-09-05 21:47:34 +0000610 }
611 if ((image->columns % 8) != 0)
612 {
cristyf054ee72011-10-05 17:04:08 +0000613 byte=(size_t) ReadBlobByte(image);
cristy3ed852e2009-09-05 21:47:34 +0000614 for (bit=0; bit < (image->columns % 8); bit++)
cristy4c08aed2011-07-01 19:47:50 +0000615 {
616 SetPixelAlpha(image,(((byte & (0x80 >> bit)) != 0) ?
617 TransparentAlpha : OpaqueAlpha),q);
cristyed231572011-07-14 02:18:59 +0000618 q+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +0000619 }
cristy3ed852e2009-09-05 21:47:34 +0000620 }
cristy0e8200f2009-09-13 21:10:06 +0000621 if ((image->columns % 32) != 0)
cristybb503372010-05-27 20:51:26 +0000622 for (x=0; x < (ssize_t) ((32-(image->columns % 32))/8); x++)
cristyf054ee72011-10-05 17:04:08 +0000623 (void) ReadBlobByte(image);
cristy3ed852e2009-09-05 21:47:34 +0000624 if (SyncAuthenticPixels(image,exception) == MagickFalse)
625 break;
626 }
627 }
628 if (EOFBlob(image) != MagickFalse)
629 {
630 ThrowFileException(exception,CorruptImageError,
631 "UnexpectedEndOfFile",image->filename);
632 break;
633 }
634 }
635 /*
636 Proceed to next image.
637 */
638 if (image_info->number_scenes != 0)
639 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
640 break;
cristybb503372010-05-27 20:51:26 +0000641 if (i < (ssize_t) (icon_file.count-1))
cristy3ed852e2009-09-05 21:47:34 +0000642 {
643 /*
644 Allocate next image structure.
645 */
cristy1f1de182011-10-05 18:41:34 +0000646 AcquireNextImage(image_info,image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000647 if (GetNextImageInList(image) == (Image *) NULL)
648 {
649 image=DestroyImageList(image);
650 return((Image *) NULL);
651 }
652 image=SyncNextImageInList(image);
653 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
654 GetBlobSize(image));
655 if (status == MagickFalse)
656 break;
657 }
658 }
659 (void) CloseBlob(image);
660 return(GetFirstImageInList(image));
661}
662
663/*
664%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
665% %
666% %
667% %
668% R e g i s t e r I C O N I m a g e %
669% %
670% %
671% %
672%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
673%
674% RegisterICONImage() adds attributes for the Icon image format to
675% the list of supported formats. The attributes include the image format
676% tag, a method to read and/or write the format, whether the format
677% supports the saving of more than one frame to the same file or blob,
678% whether the format supports native in-memory I/O, and a brief
679% description of the format.
680%
681% The format of the RegisterICONImage method is:
682%
cristybb503372010-05-27 20:51:26 +0000683% size_t RegisterICONImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000684%
685*/
cristybb503372010-05-27 20:51:26 +0000686ModuleExport size_t RegisterICONImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000687{
688 MagickInfo
689 *entry;
690
691 entry=SetMagickInfo("CUR");
692 entry->decoder=(DecodeImageHandler *) ReadICONImage;
693 entry->encoder=(EncodeImageHandler *) WriteICONImage;
694 entry->adjoin=MagickFalse;
695 entry->seekable_stream=MagickTrue;
696 entry->description=ConstantString("Microsoft icon");
697 entry->module=ConstantString("CUR");
698 (void) RegisterMagickInfo(entry);
699 entry=SetMagickInfo("ICO");
700 entry->decoder=(DecodeImageHandler *) ReadICONImage;
701 entry->encoder=(EncodeImageHandler *) WriteICONImage;
702 entry->adjoin=MagickTrue;
703 entry->seekable_stream=MagickTrue;
704 entry->description=ConstantString("Microsoft icon");
705 entry->module=ConstantString("ICON");
706 (void) RegisterMagickInfo(entry);
707 entry=SetMagickInfo("ICON");
708 entry->decoder=(DecodeImageHandler *) ReadICONImage;
709 entry->encoder=(EncodeImageHandler *) WriteICONImage;
710 entry->adjoin=MagickFalse;
711 entry->seekable_stream=MagickTrue;
712 entry->description=ConstantString("Microsoft icon");
713 entry->module=ConstantString("ICON");
714 (void) RegisterMagickInfo(entry);
715 return(MagickImageCoderSignature);
716}
717
718/*
719%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
720% %
721% %
722% %
723% U n r e g i s t e r I C O N I m a g e %
724% %
725% %
726% %
727%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
728%
729% UnregisterICONImage() removes format registrations made by the
730% ICON module from the list of supported formats.
731%
732% The format of the UnregisterICONImage method is:
733%
734% UnregisterICONImage(void)
735%
736*/
737ModuleExport void UnregisterICONImage(void)
738{
739 (void) UnregisterMagickInfo("CUR");
740 (void) UnregisterMagickInfo("ICO");
741 (void) UnregisterMagickInfo("ICON");
742}
743
744/*
745%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
746% %
747% %
748% %
749% W r i t e I C O N I m a g e %
750% %
751% %
752% %
753%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
754%
755% WriteICONImage() writes an image in Microsoft Windows bitmap encoded
756% image format, version 3 for Windows or (if the image has a matte channel)
757% version 4.
758%
759% The format of the WriteICONImage method is:
760%
761% MagickBooleanType WriteICONImage(const ImageInfo *image_info,
cristy1e178e72011-08-28 19:44:34 +0000762% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000763%
764% A description of each parameter follows.
765%
766% o image_info: the image info.
767%
768% o image: The image.
769%
cristy1e178e72011-08-28 19:44:34 +0000770% o exception: return any errors or warnings in this structure.
771%
cristy3ed852e2009-09-05 21:47:34 +0000772*/
773static MagickBooleanType WriteICONImage(const ImageInfo *image_info,
cristy1e178e72011-08-28 19:44:34 +0000774 Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000775{
776 IconFile
777 icon_file;
778
779 IconInfo
780 icon_info;
781
782 Image
783 *next;
784
cristy3ed852e2009-09-05 21:47:34 +0000785 MagickBooleanType
786 status;
787
788 MagickOffsetType
789 offset,
790 scene;
791
cristy4c08aed2011-07-01 19:47:50 +0000792 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +0000793 *p;
794
cristybb503372010-05-27 20:51:26 +0000795 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000796 i,
797 x;
798
799 register unsigned char
800 *q;
801
cristyebc891a2011-04-24 23:04:16 +0000802 size_t
803 bytes_per_line,
804 scanline_pad;
805
806 ssize_t
807 y;
808
cristy3ed852e2009-09-05 21:47:34 +0000809 unsigned char
810 bit,
811 byte,
812 *pixels;
813
cristy3ed852e2009-09-05 21:47:34 +0000814 /*
815 Open output image file.
816 */
817 assert(image_info != (const ImageInfo *) NULL);
818 assert(image_info->signature == MagickSignature);
819 assert(image != (Image *) NULL);
820 assert(image->signature == MagickSignature);
821 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"%s",image->filename);
cristy3a37efd2011-08-28 20:31:03 +0000822 assert(exception != (ExceptionInfo *) NULL);
823 assert(exception->signature == MagickSignature);
cristy1e178e72011-08-28 19:44:34 +0000824 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +0000825 if (status == MagickFalse)
826 return(status);
827 scene=0;
828 next=image;
829 do
830 {
831 if ((image->columns > 256L) || (image->rows > 256L))
832 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
833 scene++;
834 next=SyncNextImageInList(next);
835 } while ((next != (Image *) NULL) && (image_info->adjoin != MagickFalse));
836 /*
837 Dump out a ICON header template to be properly initialized later.
838 */
839 (void) WriteBlobLSBShort(image,0);
840 (void) WriteBlobLSBShort(image,1);
841 (void) WriteBlobLSBShort(image,(unsigned char) scene);
842 (void) ResetMagickMemory(&icon_file,0,sizeof(icon_file));
843 (void) ResetMagickMemory(&icon_info,0,sizeof(icon_info));
844 scene=0;
845 next=image;
846 do
847 {
848 (void) WriteBlobByte(image,icon_file.directory[scene].width);
849 (void) WriteBlobByte(image,icon_file.directory[scene].height);
850 (void) WriteBlobByte(image,icon_file.directory[scene].colors);
851 (void) WriteBlobByte(image,icon_file.directory[scene].reserved);
852 (void) WriteBlobLSBShort(image,icon_file.directory[scene].planes);
853 (void) WriteBlobLSBShort(image,icon_file.directory[scene].bits_per_pixel);
cristy0b29b252010-05-30 01:59:46 +0000854 (void) WriteBlobLSBLong(image,(unsigned int)
855 icon_file.directory[scene].size);
856 (void) WriteBlobLSBLong(image,(unsigned int)
857 icon_file.directory[scene].offset);
cristy3ed852e2009-09-05 21:47:34 +0000858 scene++;
859 next=SyncNextImageInList(next);
860 } while ((next != (Image *) NULL) && (image_info->adjoin != MagickFalse));
861 scene=0;
862 next=image;
863 do
864 {
cristy7b2ce922011-10-06 11:40:39 +0000865 if (next->compression == ZipCompression)
cristy3ed852e2009-09-05 21:47:34 +0000866 {
867 Image
868 *write_image;
869
870 ImageInfo
871 *write_info;
872
873 size_t
874 length;
875
876 unsigned char
877 *png;
878
879 /*
880 Icon image encoded as a compressed PNG image.
881 */
cristy1e178e72011-08-28 19:44:34 +0000882 write_image=CloneImage(next,0,0,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +0000883 if (write_image == (Image *) NULL)
884 return(MagickFalse);
885 write_info=CloneImageInfo(image_info);
886 (void) CopyMagickString(write_info->filename,"PNG:",MaxTextExtent);
glennrpaa192b12012-01-17 21:35:21 +0000887
888 /* Don't write any ancillary chunks except for gAMA and tRNS */
889 (void) SetImageArtifact(write_image,"png:include-chunk",
890 "none,trns,gama");
891
cristy3ed852e2009-09-05 21:47:34 +0000892 png=(unsigned char *) ImageToBlob(write_info,write_image,&length,
cristy1e178e72011-08-28 19:44:34 +0000893 exception);
cristy3ed852e2009-09-05 21:47:34 +0000894 write_image=DestroyImage(write_image);
895 write_info=DestroyImageInfo(write_info);
896 if (png == (unsigned char *) NULL)
897 return(MagickFalse);
898 icon_file.directory[scene].width=0;
899 icon_file.directory[scene].height=0;
900 icon_file.directory[scene].colors=0;
901 icon_file.directory[scene].reserved=0;
902 icon_file.directory[scene].planes=1;
903 icon_file.directory[scene].bits_per_pixel=32;
cristybb503372010-05-27 20:51:26 +0000904 icon_file.directory[scene].size=(size_t) length;
905 icon_file.directory[scene].offset=(size_t) TellBlob(image);
cristy3ed852e2009-09-05 21:47:34 +0000906 (void) WriteBlob(image,(size_t) length,png);
907 png=(unsigned char *) RelinquishMagickMemory(png);
908 }
909 else
910 {
911 /*
912 Initialize ICON raster file header.
913 */
914 if (next->colorspace != RGBColorspace)
cristye941a752011-10-15 01:52:48 +0000915 (void) TransformImageColorspace(next,RGBColorspace,exception);
cristy3ed852e2009-09-05 21:47:34 +0000916 icon_info.file_size=14+12+28;
917 icon_info.offset_bits=icon_info.file_size;
918 icon_info.compression=BI_RGB;
919 if ((next->storage_class != DirectClass) && (next->colors > 256))
cristy1e178e72011-08-28 19:44:34 +0000920 (void) SetImageStorageClass(next,DirectClass,exception);
cristy3ed852e2009-09-05 21:47:34 +0000921 if (next->storage_class == DirectClass)
922 {
923 /*
924 Full color ICON raster.
925 */
926 icon_info.number_colors=0;
927 icon_info.bits_per_pixel=32;
cristybb503372010-05-27 20:51:26 +0000928 icon_info.compression=(size_t) BI_RGB;
cristy3ed852e2009-09-05 21:47:34 +0000929 }
930 else
931 {
cristy35ef8242010-06-03 16:24:13 +0000932 size_t
933 one;
934
cristy3ed852e2009-09-05 21:47:34 +0000935 /*
936 Colormapped ICON raster.
937 */
938 icon_info.bits_per_pixel=8;
939 if (next->colors <= 256)
940 icon_info.bits_per_pixel=8;
941 if (next->colors <= 16)
942 icon_info.bits_per_pixel=4;
943 if (next->colors <= 2)
944 icon_info.bits_per_pixel=1;
cristy35ef8242010-06-03 16:24:13 +0000945 one=1;
946 icon_info.number_colors=one << icon_info.bits_per_pixel;
cristy3ed852e2009-09-05 21:47:34 +0000947 if (icon_info.number_colors < next->colors)
948 {
cristy1e178e72011-08-28 19:44:34 +0000949 (void) SetImageStorageClass(next,DirectClass,exception);
cristy3ed852e2009-09-05 21:47:34 +0000950 icon_info.number_colors=0;
951 icon_info.bits_per_pixel=(unsigned short) 24;
cristybb503372010-05-27 20:51:26 +0000952 icon_info.compression=(size_t) BI_RGB;
cristy3ed852e2009-09-05 21:47:34 +0000953 }
954 else
955 {
cristy0b29b252010-05-30 01:59:46 +0000956 size_t
957 one;
958
959 one=1;
960 icon_info.file_size+=3*(one << icon_info.bits_per_pixel);
961 icon_info.offset_bits+=3*(one << icon_info.bits_per_pixel);
962 icon_info.file_size+=(one << icon_info.bits_per_pixel);
963 icon_info.offset_bits+=(one << icon_info.bits_per_pixel);
cristy3ed852e2009-09-05 21:47:34 +0000964 }
965 }
966 bytes_per_line=(((next->columns*icon_info.bits_per_pixel)+31) &
967 ~31) >> 3;
968 icon_info.ba_offset=0;
cristybb503372010-05-27 20:51:26 +0000969 icon_info.width=(ssize_t) next->columns;
970 icon_info.height=(ssize_t) next->rows;
cristy3ed852e2009-09-05 21:47:34 +0000971 icon_info.planes=1;
972 icon_info.image_size=bytes_per_line*next->rows;
973 icon_info.size=40;
974 icon_info.size+=(4*icon_info.number_colors);
975 icon_info.size+=icon_info.image_size;
976 icon_info.size+=(((icon_info.width+31) & ~31) >> 3)*icon_info.height;
977 icon_info.file_size+=icon_info.image_size;
978 icon_info.x_pixels=0;
979 icon_info.y_pixels=0;
980 switch (next->units)
981 {
982 case UndefinedResolution:
983 case PixelsPerInchResolution:
984 {
cristy2a11bef2011-10-28 18:33:11 +0000985 icon_info.x_pixels=(size_t) (100.0*next->resolution.x/2.54);
986 icon_info.y_pixels=(size_t) (100.0*next->resolution.y/2.54);
cristy3ed852e2009-09-05 21:47:34 +0000987 break;
988 }
989 case PixelsPerCentimeterResolution:
990 {
cristy2a11bef2011-10-28 18:33:11 +0000991 icon_info.x_pixels=(size_t) (100.0*next->resolution.x);
992 icon_info.y_pixels=(size_t) (100.0*next->resolution.y);
cristy3ed852e2009-09-05 21:47:34 +0000993 break;
994 }
995 }
996 icon_info.colors_important=icon_info.number_colors;
997 /*
998 Convert MIFF to ICON raster pixels.
999 */
1000 pixels=(unsigned char *) AcquireQuantumMemory((size_t)
1001 icon_info.image_size,sizeof(*pixels));
1002 if (pixels == (unsigned char *) NULL)
1003 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1004 (void) ResetMagickMemory(pixels,0,(size_t) icon_info.image_size);
1005 switch (icon_info.bits_per_pixel)
1006 {
1007 case 1:
1008 {
cristybb503372010-05-27 20:51:26 +00001009 size_t
cristy3ed852e2009-09-05 21:47:34 +00001010 bit,
1011 byte;
1012
1013 /*
1014 Convert PseudoClass image to a ICON monochrome image.
1015 */
cristybb503372010-05-27 20:51:26 +00001016 for (y=0; y < (ssize_t) next->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001017 {
cristy1e178e72011-08-28 19:44:34 +00001018 p=GetVirtualPixels(next,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001019 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001020 break;
cristy3ed852e2009-09-05 21:47:34 +00001021 q=pixels+(next->rows-y-1)*bytes_per_line;
1022 bit=0;
1023 byte=0;
cristybb503372010-05-27 20:51:26 +00001024 for (x=0; x < (ssize_t) next->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001025 {
1026 byte<<=1;
cristy4c08aed2011-07-01 19:47:50 +00001027 byte|=GetPixelIndex(next,p) != 0 ? 0x01 : 0x00;
cristy3ed852e2009-09-05 21:47:34 +00001028 bit++;
1029 if (bit == 8)
1030 {
1031 *q++=(unsigned char) byte;
1032 bit=0;
1033 byte=0;
1034 }
cristyed231572011-07-14 02:18:59 +00001035 p+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00001036 }
cristy3ed852e2009-09-05 21:47:34 +00001037 if (bit != 0)
1038 *q++=(unsigned char) (byte << (8-bit));
1039 if (next->previous == (Image *) NULL)
1040 {
1041 status=SetImageProgress(next,SaveImageTag,y,next->rows);
1042 if (status == MagickFalse)
1043 break;
1044 }
1045 }
1046 break;
1047 }
1048 case 4:
1049 {
cristybb503372010-05-27 20:51:26 +00001050 size_t
cristy3ed852e2009-09-05 21:47:34 +00001051 nibble,
1052 byte;
1053
1054 /*
1055 Convert PseudoClass image to a ICON monochrome image.
1056 */
cristybb503372010-05-27 20:51:26 +00001057 for (y=0; y < (ssize_t) next->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001058 {
cristy1e178e72011-08-28 19:44:34 +00001059 p=GetVirtualPixels(next,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001060 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001061 break;
cristy3ed852e2009-09-05 21:47:34 +00001062 q=pixels+(next->rows-y-1)*bytes_per_line;
1063 nibble=0;
1064 byte=0;
cristybb503372010-05-27 20:51:26 +00001065 for (x=0; x < (ssize_t) next->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001066 {
1067 byte<<=4;
cristy4c08aed2011-07-01 19:47:50 +00001068 byte|=((size_t) GetPixelIndex(next,p) & 0x0f);
cristy3ed852e2009-09-05 21:47:34 +00001069 nibble++;
1070 if (nibble == 2)
1071 {
1072 *q++=(unsigned char) byte;
1073 nibble=0;
1074 byte=0;
1075 }
cristyed231572011-07-14 02:18:59 +00001076 p+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00001077 }
cristy3ed852e2009-09-05 21:47:34 +00001078 if (nibble != 0)
1079 *q++=(unsigned char) (byte << 4);
1080 if (next->previous == (Image *) NULL)
1081 {
1082 status=SetImageProgress(next,SaveImageTag,y,next->rows);
1083 if (status == MagickFalse)
1084 break;
1085 }
1086 }
1087 break;
1088 }
1089 case 8:
1090 {
1091 /*
1092 Convert PseudoClass packet to ICON pixel.
1093 */
cristybb503372010-05-27 20:51:26 +00001094 for (y=0; y < (ssize_t) next->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001095 {
cristy1e178e72011-08-28 19:44:34 +00001096 p=GetVirtualPixels(next,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001097 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001098 break;
cristy3ed852e2009-09-05 21:47:34 +00001099 q=pixels+(next->rows-y-1)*bytes_per_line;
cristybb503372010-05-27 20:51:26 +00001100 for (x=0; x < (ssize_t) next->columns; x++)
cristy4c08aed2011-07-01 19:47:50 +00001101 {
1102 *q++=(unsigned char) GetPixelIndex(next,p);
cristyed231572011-07-14 02:18:59 +00001103 p+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00001104 }
cristy3ed852e2009-09-05 21:47:34 +00001105 if (next->previous == (Image *) NULL)
1106 {
1107 status=SetImageProgress(next,SaveImageTag,y,next->rows);
1108 if (status == MagickFalse)
1109 break;
1110 }
1111 }
1112 break;
1113 }
1114 case 24:
1115 case 32:
1116 {
1117 /*
1118 Convert DirectClass packet to ICON BGR888 or BGRA8888 pixel.
1119 */
cristybb503372010-05-27 20:51:26 +00001120 for (y=0; y < (ssize_t) next->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001121 {
cristy1e178e72011-08-28 19:44:34 +00001122 p=GetVirtualPixels(next,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001123 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001124 break;
1125 q=pixels+(next->rows-y-1)*bytes_per_line;
cristybb503372010-05-27 20:51:26 +00001126 for (x=0; x < (ssize_t) next->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001127 {
cristy4c08aed2011-07-01 19:47:50 +00001128 *q++=ScaleQuantumToChar(GetPixelBlue(next,p));
1129 *q++=ScaleQuantumToChar(GetPixelGreen(next,p));
1130 *q++=ScaleQuantumToChar(GetPixelRed(next,p));
cristy3ed852e2009-09-05 21:47:34 +00001131 if (next->matte == MagickFalse)
1132 *q++=ScaleQuantumToChar(QuantumRange);
1133 else
cristy4c08aed2011-07-01 19:47:50 +00001134 *q++=ScaleQuantumToChar(GetPixelAlpha(next,p));
cristyed231572011-07-14 02:18:59 +00001135 p+=GetPixelChannels(next);
cristy3ed852e2009-09-05 21:47:34 +00001136 }
1137 if (icon_info.bits_per_pixel == 24)
cristybb503372010-05-27 20:51:26 +00001138 for (x=3L*(ssize_t) next->columns; x < (ssize_t) bytes_per_line; x++)
cristy3ed852e2009-09-05 21:47:34 +00001139 *q++=0x00;
1140 if (next->previous == (Image *) NULL)
1141 {
1142 status=SetImageProgress(next,SaveImageTag,y,next->rows);
1143 if (status == MagickFalse)
1144 break;
1145 }
1146 }
1147 break;
1148 }
1149 }
1150 /*
1151 Write 40-byte version 3+ bitmap header.
1152 */
1153 icon_file.directory[scene].width=(unsigned char) icon_info.width;
1154 icon_file.directory[scene].height=(unsigned char) icon_info.height;
1155 icon_file.directory[scene].colors=(unsigned char)
1156 icon_info.number_colors;
1157 icon_file.directory[scene].reserved=0;
1158 icon_file.directory[scene].planes=icon_info.planes;
1159 icon_file.directory[scene].bits_per_pixel=icon_info.bits_per_pixel;
1160 icon_file.directory[scene].size=icon_info.size;
cristybb503372010-05-27 20:51:26 +00001161 icon_file.directory[scene].offset=(size_t) TellBlob(image);
cristy35ef8242010-06-03 16:24:13 +00001162 (void) WriteBlobLSBLong(image,(unsigned int) 40);
1163 (void) WriteBlobLSBLong(image,(unsigned int) icon_info.width);
1164 (void) WriteBlobLSBLong(image,(unsigned int) icon_info.height*2);
cristy3ed852e2009-09-05 21:47:34 +00001165 (void) WriteBlobLSBShort(image,icon_info.planes);
1166 (void) WriteBlobLSBShort(image,icon_info.bits_per_pixel);
cristy35ef8242010-06-03 16:24:13 +00001167 (void) WriteBlobLSBLong(image,(unsigned int) icon_info.compression);
1168 (void) WriteBlobLSBLong(image,(unsigned int) icon_info.image_size);
1169 (void) WriteBlobLSBLong(image,(unsigned int) icon_info.x_pixels);
1170 (void) WriteBlobLSBLong(image,(unsigned int) icon_info.y_pixels);
1171 (void) WriteBlobLSBLong(image,(unsigned int) icon_info.number_colors);
1172 (void) WriteBlobLSBLong(image,(unsigned int) icon_info.colors_important);
cristy3ed852e2009-09-05 21:47:34 +00001173 if (next->storage_class == PseudoClass)
1174 {
1175 unsigned char
1176 *icon_colormap;
1177
1178 /*
1179 Dump colormap to file.
1180 */
1181 icon_colormap=(unsigned char *) AcquireQuantumMemory((size_t)
1182 (1UL << icon_info.bits_per_pixel),4UL*sizeof(*icon_colormap));
1183 if (icon_colormap == (unsigned char *) NULL)
1184 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1185 q=icon_colormap;
cristybb503372010-05-27 20:51:26 +00001186 for (i=0; i < (ssize_t) next->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00001187 {
1188 *q++=ScaleQuantumToChar(next->colormap[i].blue);
1189 *q++=ScaleQuantumToChar(next->colormap[i].green);
1190 *q++=ScaleQuantumToChar(next->colormap[i].red);
1191 *q++=(unsigned char) 0x0;
1192 }
cristybb503372010-05-27 20:51:26 +00001193 for ( ; i < (ssize_t) (1UL << icon_info.bits_per_pixel); i++)
cristy3ed852e2009-09-05 21:47:34 +00001194 {
1195 *q++=(unsigned char) 0x00;
1196 *q++=(unsigned char) 0x00;
1197 *q++=(unsigned char) 0x00;
1198 *q++=(unsigned char) 0x00;
1199 }
1200 (void) WriteBlob(image,(size_t) (4UL*(1UL <<
1201 icon_info.bits_per_pixel)),icon_colormap);
1202 icon_colormap=(unsigned char *) RelinquishMagickMemory(
1203 icon_colormap);
1204 }
1205 (void) WriteBlob(image,(size_t) icon_info.image_size,pixels);
1206 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1207 /*
1208 Write matte mask.
1209 */
1210 scanline_pad=(((next->columns+31) & ~31)-next->columns) >> 3;
cristybb503372010-05-27 20:51:26 +00001211 for (y=((ssize_t) next->rows - 1); y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +00001212 {
cristy1e178e72011-08-28 19:44:34 +00001213 p=GetVirtualPixels(next,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001214 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001215 break;
1216 bit=0;
1217 byte=0;
cristybb503372010-05-27 20:51:26 +00001218 for (x=0; x < (ssize_t) next->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001219 {
1220 byte<<=1;
1221 if ((next->matte == MagickTrue) &&
cristy4c08aed2011-07-01 19:47:50 +00001222 (GetPixelAlpha(next,p) == (Quantum) TransparentAlpha))
cristy3ed852e2009-09-05 21:47:34 +00001223 byte|=0x01;
1224 bit++;
1225 if (bit == 8)
1226 {
1227 (void) WriteBlobByte(image,(unsigned char) byte);
1228 bit=0;
1229 byte=0;
1230 }
cristyed231572011-07-14 02:18:59 +00001231 p+=GetPixelChannels(next);
cristy3ed852e2009-09-05 21:47:34 +00001232 }
1233 if (bit != 0)
1234 (void) WriteBlobByte(image,(unsigned char) (byte << (8-bit)));
cristybb503372010-05-27 20:51:26 +00001235 for (i=0; i < (ssize_t) scanline_pad; i++)
cristy3ed852e2009-09-05 21:47:34 +00001236 (void) WriteBlobByte(image,(unsigned char) 0);
1237 }
1238 }
1239 if (GetNextImageInList(next) == (Image *) NULL)
1240 break;
1241 next=SyncNextImageInList(next);
1242 status=SetImageProgress(next,SaveImagesTag,scene++,
1243 GetImageListLength(next));
1244 if (status == MagickFalse)
1245 break;
1246 } while ((next != (Image *) NULL) && (image_info->adjoin != MagickFalse));
1247 offset=SeekBlob(image,0,SEEK_SET);
cristyda16f162011-02-19 23:52:17 +00001248 (void) offset;
cristy3ed852e2009-09-05 21:47:34 +00001249 (void) WriteBlobLSBShort(image,0);
1250 (void) WriteBlobLSBShort(image,1);
1251 (void) WriteBlobLSBShort(image,(unsigned short) (scene+1));
1252 scene=0;
1253 next=image;
1254 do
1255 {
1256 (void) WriteBlobByte(image,icon_file.directory[scene].width);
1257 (void) WriteBlobByte(image,icon_file.directory[scene].height);
1258 (void) WriteBlobByte(image,icon_file.directory[scene].colors);
1259 (void) WriteBlobByte(image,icon_file.directory[scene].reserved);
1260 (void) WriteBlobLSBShort(image,icon_file.directory[scene].planes);
1261 (void) WriteBlobLSBShort(image,icon_file.directory[scene].bits_per_pixel);
cristy0b29b252010-05-30 01:59:46 +00001262 (void) WriteBlobLSBLong(image,(unsigned int)
1263 icon_file.directory[scene].size);
1264 (void) WriteBlobLSBLong(image,(unsigned int)
1265 icon_file.directory[scene].offset);
cristy3ed852e2009-09-05 21:47:34 +00001266 scene++;
1267 next=SyncNextImageInList(next);
1268 } while ((next != (Image *) NULL) && (image_info->adjoin != MagickFalse));
1269 (void) CloseBlob(image);
1270 return(MagickTrue);
1271}