blob: 744cc74e5529ffc8272b8102b278a701d500b65a [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"
cristy3d9f5ba2012-06-26 13:37:31 +000049#include "MagickCore/colorspace-private.h"
cristy4c08aed2011-07-01 19:47:50 +000050#include "MagickCore/exception.h"
51#include "MagickCore/exception-private.h"
52#include "MagickCore/image.h"
53#include "MagickCore/image-private.h"
54#include "MagickCore/list.h"
55#include "MagickCore/log.h"
56#include "MagickCore/magick.h"
57#include "MagickCore/memory_.h"
58#include "MagickCore/monitor.h"
59#include "MagickCore/monitor-private.h"
cristy2c5fc272012-02-22 01:27:46 +000060#include "MagickCore/nt-base-private.h"
cristy4c08aed2011-07-01 19:47:50 +000061#include "MagickCore/pixel-accessor.h"
62#include "MagickCore/quantize.h"
63#include "MagickCore/quantum-private.h"
64#include "MagickCore/static.h"
65#include "MagickCore/string_.h"
66#include "MagickCore/module.h"
cristy3ed852e2009-09-05 21:47:34 +000067
68/*
69 Define declarations.
70*/
cristy0157aea2010-04-24 21:12:18 +000071#if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__MINGW32__)
cristy3ed852e2009-09-05 21:47:34 +000072#define BI_RGB 0
73#define BI_RLE8 1
74#define BI_BITFIELDS 3
75#endif
76#define MaxIcons 1024
77
78/*
79 Typedef declarations.
80*/
81typedef struct _IconEntry
82{
83 unsigned char
84 width,
85 height,
86 colors,
87 reserved;
88
89 unsigned short int
90 planes,
91 bits_per_pixel;
92
cristybb503372010-05-27 20:51:26 +000093 size_t
cristy3ed852e2009-09-05 21:47:34 +000094 size,
95 offset;
96} IconEntry;
97
98typedef struct _IconFile
99{
100 short
101 reserved,
102 resource_type,
103 count;
104
105 IconEntry
106 directory[MaxIcons];
107} IconFile;
108
109typedef struct _IconInfo
110{
cristybb503372010-05-27 20:51:26 +0000111 size_t
cristy3ed852e2009-09-05 21:47:34 +0000112 file_size,
113 ba_offset,
114 offset_bits,
115 size;
116
cristybb503372010-05-27 20:51:26 +0000117 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000118 width,
119 height;
120
121 unsigned short
122 planes,
123 bits_per_pixel;
124
cristybb503372010-05-27 20:51:26 +0000125 size_t
cristy3ed852e2009-09-05 21:47:34 +0000126 compression,
127 image_size,
128 x_pixels,
129 y_pixels,
130 number_colors,
131 red_mask,
132 green_mask,
133 blue_mask,
134 alpha_mask,
135 colors_important;
136
cristybb503372010-05-27 20:51:26 +0000137 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000138 colorspace;
139} IconInfo;
140
141/*
142 Forward declaractions.
143*/
144static MagickBooleanType
cristy1e178e72011-08-28 19:44:34 +0000145 WriteICONImage(const ImageInfo *,Image *,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000146
147/*
148%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
149% %
150% %
151% %
152% R e a d I C O N I m a g e %
153% %
154% %
155% %
156%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
157%
158% ReadICONImage() reads a Microsoft icon image file and returns it. It
159% allocates the memory necessary for the new Image structure and returns a
160% pointer to the new image.
161%
162% The format of the ReadICONImage method is:
163%
164% Image *ReadICONImage(const ImageInfo *image_info,
165% ExceptionInfo *exception)
166%
167% A description of each parameter follows:
168%
169% o image_info: the image info.
170%
171% o exception: return any errors or warnings in this structure.
172%
173*/
174static Image *ReadICONImage(const ImageInfo *image_info,
175 ExceptionInfo *exception)
176{
177 IconFile
178 icon_file;
179
180 IconInfo
181 icon_info;
182
183 Image
184 *image;
185
cristy3ed852e2009-09-05 21:47:34 +0000186 MagickBooleanType
187 status;
188
cristybb503372010-05-27 20:51:26 +0000189 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000190 i,
191 x;
192
cristy4c08aed2011-07-01 19:47:50 +0000193 register Quantum
cristy3ed852e2009-09-05 21:47:34 +0000194 *q;
195
196 register unsigned char
197 *p;
198
cristybb503372010-05-27 20:51:26 +0000199 size_t
cristy3ed852e2009-09-05 21:47:34 +0000200 bit,
cristyeaedf062010-05-29 22:36:02 +0000201 byte,
cristy3ed852e2009-09-05 21:47:34 +0000202 bytes_per_line,
cristyeaedf062010-05-29 22:36:02 +0000203 one,
cristy3ed852e2009-09-05 21:47:34 +0000204 scanline_pad;
205
cristyebc891a2011-04-24 23:04:16 +0000206 ssize_t
207 count,
208 offset,
209 y;
210
cristy3ed852e2009-09-05 21:47:34 +0000211 /*
212 Open image file.
213 */
214 assert(image_info != (const ImageInfo *) NULL);
215 assert(image_info->signature == MagickSignature);
216 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"%s",image_info->filename);
217 assert(exception != (ExceptionInfo *) NULL);
218 assert(exception->signature == MagickSignature);
cristy1f1de182011-10-05 18:41:34 +0000219 image=AcquireImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +0000220 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
221 if (status == MagickFalse)
222 {
223 image=DestroyImageList(image);
224 return((Image *) NULL);
225 }
226 icon_file.reserved=(short) ReadBlobLSBShort(image);
227 icon_file.resource_type=(short) ReadBlobLSBShort(image);
228 icon_file.count=(short) ReadBlobLSBShort(image);
229 if ((icon_file.reserved != 0) ||
230 ((icon_file.resource_type != 1) && (icon_file.resource_type != 2)) ||
231 (icon_file.count > MaxIcons))
232 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
233 for (i=0; i < icon_file.count; i++)
234 {
235 icon_file.directory[i].width=(unsigned char) ReadBlobByte(image);
236 icon_file.directory[i].height=(unsigned char) ReadBlobByte(image);
237 icon_file.directory[i].colors=(unsigned char) ReadBlobByte(image);
238 icon_file.directory[i].reserved=(unsigned char) ReadBlobByte(image);
239 icon_file.directory[i].planes=(unsigned short) ReadBlobLSBShort(image);
240 icon_file.directory[i].bits_per_pixel=(unsigned short)
241 ReadBlobLSBShort(image);
242 icon_file.directory[i].size=ReadBlobLSBLong(image);
243 icon_file.directory[i].offset=ReadBlobLSBLong(image);
244 }
cristyeaedf062010-05-29 22:36:02 +0000245 one=1;
cristy3ed852e2009-09-05 21:47:34 +0000246 for (i=0; i < icon_file.count; i++)
247 {
248 /*
249 Verify Icon identifier.
250 */
251 offset=(ssize_t) SeekBlob(image,(MagickOffsetType)
252 icon_file.directory[i].offset,SEEK_SET);
253 if (offset < 0)
254 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
255 icon_info.size=ReadBlobLSBLong(image);
cristyd63c0502011-01-03 15:45:11 +0000256 icon_info.width=(unsigned char) ((int) ReadBlobLSBLong(image));
257 icon_info.height=(unsigned char) ((int) ReadBlobLSBLong(image)/2);
cristy4e09e032011-10-05 19:42:10 +0000258 icon_info.planes=ReadBlobLSBShort(image);
259 icon_info.bits_per_pixel=ReadBlobLSBShort(image);
260 if ((icon_info.planes == 18505) && (icon_info.bits_per_pixel == 21060))
cristy3ed852e2009-09-05 21:47:34 +0000261 {
262 Image
263 *icon_image;
264
265 ImageInfo
266 *read_info;
267
cristyf054ee72011-10-05 17:04:08 +0000268 size_t
269 length;
270
271 unsigned char
272 *png;
273
cristy3ed852e2009-09-05 21:47:34 +0000274 /*
275 Icon image encoded as a compressed PNG image.
276 */
cristyf054ee72011-10-05 17:04:08 +0000277 length=icon_file.directory[i].size;
cristy4e09e032011-10-05 19:42:10 +0000278 png=(unsigned char *) AcquireQuantumMemory(length+16,sizeof(*png));
cristyf054ee72011-10-05 17:04:08 +0000279 if (png == (unsigned char *) NULL)
280 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
281 (void) CopyMagickMemory(png,"\211PNG\r\n\032\n\000\000\000\015",12);
cristy4e09e032011-10-05 19:42:10 +0000282 png[12]=(unsigned char) icon_info.planes;
283 png[13]=(unsigned char) (icon_info.planes >> 8);
284 png[14]=(unsigned char) icon_info.bits_per_pixel;
285 png[15]=(unsigned char) (icon_info.bits_per_pixel >> 8);
286 count=ReadBlob(image,length-16,png+16);
287 if (count != (ssize_t) (length-16))
cristyf054ee72011-10-05 17:04:08 +0000288 {
289 png=(unsigned char *) RelinquishMagickMemory(png);
290 ThrowReaderException(CorruptImageError,
291 "InsufficientImageDataInFile");
292 }
cristy3ed852e2009-09-05 21:47:34 +0000293 read_info=CloneImageInfo(image_info);
294 (void) CopyMagickString(read_info->magick,"PNG",MaxTextExtent);
cristy4e09e032011-10-05 19:42:10 +0000295 icon_image=BlobToImage(read_info,png,length+16,exception);
cristy3ed852e2009-09-05 21:47:34 +0000296 read_info=DestroyImageInfo(read_info);
cristyf054ee72011-10-05 17:04:08 +0000297 png=(unsigned char *) RelinquishMagickMemory(png);
cristy47de5a92011-10-05 01:47:42 +0000298 if (icon_image == (Image *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000299 {
cristy47de5a92011-10-05 01:47:42 +0000300 image=DestroyImageList(image);
301 return((Image *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000302 }
cristy47de5a92011-10-05 01:47:42 +0000303 DestroyBlob(icon_image);
304 icon_image->blob=ReferenceBlob(image->blob);
305 ReplaceImageInList(&image,icon_image);
cristy3ed852e2009-09-05 21:47:34 +0000306 }
307 else
308 {
cristyf054ee72011-10-05 17:04:08 +0000309 if (icon_info.bits_per_pixel > 32)
310 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
311 icon_info.compression=ReadBlobLSBLong(image);
312 icon_info.image_size=ReadBlobLSBLong(image);
313 icon_info.x_pixels=ReadBlobLSBLong(image);
314 icon_info.y_pixels=ReadBlobLSBLong(image);
315 icon_info.number_colors=ReadBlobLSBLong(image);
316 icon_info.colors_important=ReadBlobLSBLong(image);
317 image->matte=MagickTrue;
318 image->columns=(size_t) icon_file.directory[i].width;
319 if ((ssize_t) image->columns > icon_info.width)
320 image->columns=(size_t) icon_info.width;
cristy4e09e032011-10-05 19:42:10 +0000321 if (image->columns == 0)
322 image->columns=256;
cristyf054ee72011-10-05 17:04:08 +0000323 image->rows=(size_t) icon_file.directory[i].height;
324 if ((ssize_t) image->rows > icon_info.height)
325 image->rows=(size_t) icon_info.height;
cristy4e09e032011-10-05 19:42:10 +0000326 if (image->rows == 0)
327 image->rows=256;
cristyf054ee72011-10-05 17:04:08 +0000328 image->depth=icon_info.bits_per_pixel;
329 if (image->debug != MagickFalse)
330 {
331 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
332 " scene = %.20g",(double) i);
333 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
334 " size = %.20g",(double) icon_info.size);
335 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
336 " width = %.20g",(double) icon_file.directory[i].width);
337 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
338 " height = %.20g",(double) icon_file.directory[i].height);
339 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
340 " colors = %.20g",(double ) icon_info.number_colors);
341 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
342 " planes = %.20g",(double) icon_info.planes);
343 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
344 " bpp = %.20g",(double) icon_info.bits_per_pixel);
345 }
346 if ((icon_info.number_colors != 0) || (icon_info.bits_per_pixel <= 16))
347 {
348 image->storage_class=PseudoClass;
349 image->colors=icon_info.number_colors;
350 if (image->colors == 0)
351 image->colors=one << icon_info.bits_per_pixel;
352 }
353 if (image->storage_class == PseudoClass)
354 {
355 register ssize_t
356 i;
cristy3ed852e2009-09-05 21:47:34 +0000357
cristyf054ee72011-10-05 17:04:08 +0000358 size_t
359 number_colors,
360 one;
361
362 unsigned char
363 *icon_colormap;
364
365 /*
366 Read Icon raster colormap.
367 */
368 one=1;
369 number_colors=one << icon_info.bits_per_pixel;
370 if (AcquireImageColormap(image,number_colors,exception) == MagickFalse)
371 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
372 icon_colormap=(unsigned char *) AcquireQuantumMemory((size_t)
373 image->colors,4UL*sizeof(*icon_colormap));
374 if (icon_colormap == (unsigned char *) NULL)
375 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
376 count=ReadBlob(image,(size_t) (4*image->colors),icon_colormap);
377 if (count != (ssize_t) (4*image->colors))
378 ThrowReaderException(CorruptImageError,
379 "InsufficientImageDataInFile");
380 p=icon_colormap;
381 for (i=0; i < (ssize_t) image->colors; i++)
382 {
383 image->colormap[i].blue=(Quantum) ScaleCharToQuantum(*p++);
384 image->colormap[i].green=(Quantum) ScaleCharToQuantum(*p++);
385 image->colormap[i].red=(Quantum) ScaleCharToQuantum(*p++);
386 p++;
387 }
388 icon_colormap=(unsigned char *) RelinquishMagickMemory(icon_colormap);
389 }
cristy3ed852e2009-09-05 21:47:34 +0000390 /*
391 Convert Icon raster image to pixel packets.
392 */
cristyf054ee72011-10-05 17:04:08 +0000393 if ((image_info->ping != MagickFalse) &&
394 (image_info->number_scenes != 0))
395 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
396 break;
cristy3ed852e2009-09-05 21:47:34 +0000397 bytes_per_line=(((image->columns*icon_info.bits_per_pixel)+31) &
398 ~31) >> 3;
cristyda16f162011-02-19 23:52:17 +0000399 (void) bytes_per_line;
cristy3ed852e2009-09-05 21:47:34 +0000400 scanline_pad=((((image->columns*icon_info.bits_per_pixel)+31) & ~31)-
401 (image->columns*icon_info.bits_per_pixel)) >> 3;
402 switch (icon_info.bits_per_pixel)
403 {
404 case 1:
405 {
406 /*
407 Convert bitmap scanline.
408 */
cristybb503372010-05-27 20:51:26 +0000409 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +0000410 {
411 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000412 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000413 break;
cristybb503372010-05-27 20:51:26 +0000414 for (x=0; x < (ssize_t) (image->columns-7); x+=8)
cristy3ed852e2009-09-05 21:47:34 +0000415 {
cristyf054ee72011-10-05 17:04:08 +0000416 byte=(size_t) ReadBlobByte(image);
cristy3ed852e2009-09-05 21:47:34 +0000417 for (bit=0; bit < 8; bit++)
cristy4c08aed2011-07-01 19:47:50 +0000418 {
419 SetPixelIndex(image,((byte & (0x80 >> bit)) != 0 ? 0x01 :
420 0x00),q);
cristyed231572011-07-14 02:18:59 +0000421 q+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +0000422 }
cristy3ed852e2009-09-05 21:47:34 +0000423 }
424 if ((image->columns % 8) != 0)
425 {
cristyf054ee72011-10-05 17:04:08 +0000426 byte=(size_t) ReadBlobByte(image);
cristy3ed852e2009-09-05 21:47:34 +0000427 for (bit=0; bit < (image->columns % 8); bit++)
cristy4c08aed2011-07-01 19:47:50 +0000428 {
429 SetPixelIndex(image,((byte & (0x80 >> bit)) != 0 ? 0x01 :
430 0x00),q);
cristyed231572011-07-14 02:18:59 +0000431 q+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +0000432 }
cristy3ed852e2009-09-05 21:47:34 +0000433 }
cristybb503372010-05-27 20:51:26 +0000434 for (x=0; x < (ssize_t) scanline_pad; x++)
cristyf054ee72011-10-05 17:04:08 +0000435 (void) ReadBlobByte(image);
cristy3ed852e2009-09-05 21:47:34 +0000436 if (SyncAuthenticPixels(image,exception) == MagickFalse)
437 break;
438 if (image->previous == (Image *) NULL)
439 {
440 status=SetImageProgress(image,LoadImageTag,image->rows-y-1,
441 image->rows);
442 if (status == MagickFalse)
443 break;
444 }
445 }
446 break;
447 }
448 case 4:
449 {
450 /*
451 Read 4-bit Icon scanline.
452 */
cristybb503372010-05-27 20:51:26 +0000453 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +0000454 {
455 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000456 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000457 break;
cristybb503372010-05-27 20:51:26 +0000458 for (x=0; x < ((ssize_t) image->columns-1); x+=2)
cristy3ed852e2009-09-05 21:47:34 +0000459 {
cristyf054ee72011-10-05 17:04:08 +0000460 byte=(size_t) ReadBlobByte(image);
cristy4c08aed2011-07-01 19:47:50 +0000461 SetPixelIndex(image,((byte >> 4) & 0xf),q);
cristyed231572011-07-14 02:18:59 +0000462 q+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +0000463 SetPixelIndex(image,((byte) & 0xf),q);
cristyed231572011-07-14 02:18:59 +0000464 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000465 }
466 if ((image->columns % 2) != 0)
467 {
cristyf054ee72011-10-05 17:04:08 +0000468 byte=(size_t) ReadBlobByte(image);
cristy4c08aed2011-07-01 19:47:50 +0000469 SetPixelIndex(image,((byte >> 4) & 0xf),q);
cristyed231572011-07-14 02:18:59 +0000470 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000471 }
cristybb503372010-05-27 20:51:26 +0000472 for (x=0; x < (ssize_t) scanline_pad; x++)
cristyf054ee72011-10-05 17:04:08 +0000473 (void) ReadBlobByte(image);
cristy3ed852e2009-09-05 21:47:34 +0000474 if (SyncAuthenticPixels(image,exception) == MagickFalse)
475 break;
476 if (image->previous == (Image *) NULL)
477 {
478 status=SetImageProgress(image,LoadImageTag,image->rows-y-1,
479 image->rows);
480 if (status == MagickFalse)
481 break;
482 }
483 }
484 break;
485 }
486 case 8:
487 {
488 /*
489 Convert PseudoColor scanline.
490 */
cristybb503372010-05-27 20:51:26 +0000491 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +0000492 {
493 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000494 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000495 break;
cristybb503372010-05-27 20:51:26 +0000496 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000497 {
cristyf054ee72011-10-05 17:04:08 +0000498 byte=(size_t) ReadBlobByte(image);
cristy4c08aed2011-07-01 19:47:50 +0000499 SetPixelIndex(image,byte,q);
cristyed231572011-07-14 02:18:59 +0000500 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000501 }
cristybb503372010-05-27 20:51:26 +0000502 for (x=0; x < (ssize_t) scanline_pad; x++)
cristyf054ee72011-10-05 17:04:08 +0000503 (void) ReadBlobByte(image);
cristy3ed852e2009-09-05 21:47:34 +0000504 if (SyncAuthenticPixels(image,exception) == MagickFalse)
505 break;
506 if (image->previous == (Image *) NULL)
507 {
508 status=SetImageProgress(image,LoadImageTag,image->rows-y-1,
509 image->rows);
510 if (status == MagickFalse)
511 break;
512 }
513 }
514 break;
515 }
516 case 16:
517 {
518 /*
519 Convert PseudoColor scanline.
520 */
cristybb503372010-05-27 20:51:26 +0000521 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +0000522 {
523 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000524 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000525 break;
cristybb503372010-05-27 20:51:26 +0000526 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000527 {
cristyf054ee72011-10-05 17:04:08 +0000528 byte=(size_t) ReadBlobByte(image);
529 byte|=(size_t) (ReadBlobByte(image) << 8);
cristy4c08aed2011-07-01 19:47:50 +0000530 SetPixelIndex(image,byte,q);
cristyed231572011-07-14 02:18:59 +0000531 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000532 }
cristybb503372010-05-27 20:51:26 +0000533 for (x=0; x < (ssize_t) scanline_pad; x++)
cristyf054ee72011-10-05 17:04:08 +0000534 (void) ReadBlobByte(image);
cristy3ed852e2009-09-05 21:47:34 +0000535 if (SyncAuthenticPixels(image,exception) == MagickFalse)
536 break;
537 if (image->previous == (Image *) NULL)
538 {
539 status=SetImageProgress(image,LoadImageTag,image->rows-y-1,
540 image->rows);
541 if (status == MagickFalse)
542 break;
543 }
544 }
545 break;
546 }
547 case 24:
548 case 32:
549 {
550 /*
551 Convert DirectColor scanline.
552 */
cristybb503372010-05-27 20:51:26 +0000553 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +0000554 {
555 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000556 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000557 break;
cristybb503372010-05-27 20:51:26 +0000558 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000559 {
cristyf054ee72011-10-05 17:04:08 +0000560 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
561 ReadBlobByte(image)),q);
562 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
563 ReadBlobByte(image)),q);
564 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
565 ReadBlobByte(image)),q);
cristy3ed852e2009-09-05 21:47:34 +0000566 if (icon_info.bits_per_pixel == 32)
cristyf054ee72011-10-05 17:04:08 +0000567 SetPixelAlpha(image,ScaleCharToQuantum((unsigned char)
568 ReadBlobByte(image)),q);
cristyed231572011-07-14 02:18:59 +0000569 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000570 }
571 if (icon_info.bits_per_pixel == 24)
cristybb503372010-05-27 20:51:26 +0000572 for (x=0; x < (ssize_t) scanline_pad; x++)
cristyf054ee72011-10-05 17:04:08 +0000573 (void) ReadBlobByte(image);
cristy3ed852e2009-09-05 21:47:34 +0000574 if (SyncAuthenticPixels(image,exception) == MagickFalse)
575 break;
576 if (image->previous == (Image *) NULL)
577 {
578 status=SetImageProgress(image,LoadImageTag,image->rows-y-1,
579 image->rows);
580 if (status == MagickFalse)
581 break;
582 }
583 }
584 break;
585 }
586 default:
587 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
588 }
cristy5dd71882010-08-01 20:53:13 +0000589 if (image_info->ping == MagickFalse)
cristyea1a8aa2011-10-20 13:24:06 +0000590 (void) SyncImage(image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000591 if (icon_info.bits_per_pixel != 32)
592 {
593 /*
594 Read the ICON alpha mask.
595 */
596 image->storage_class=DirectClass;
cristybb503372010-05-27 20:51:26 +0000597 for (y=(ssize_t) image->rows-1; y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +0000598 {
599 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000600 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000601 break;
cristybb503372010-05-27 20:51:26 +0000602 for (x=0; x < ((ssize_t) image->columns-7); x+=8)
cristy3ed852e2009-09-05 21:47:34 +0000603 {
cristyf054ee72011-10-05 17:04:08 +0000604 byte=(size_t) ReadBlobByte(image);
cristy3ed852e2009-09-05 21:47:34 +0000605 for (bit=0; bit < 8; bit++)
cristy4c08aed2011-07-01 19:47:50 +0000606 {
607 SetPixelAlpha(image,(((byte & (0x80 >> bit)) != 0) ?
608 TransparentAlpha : OpaqueAlpha),q);
cristyed231572011-07-14 02:18:59 +0000609 q+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +0000610 }
cristy3ed852e2009-09-05 21:47:34 +0000611 }
612 if ((image->columns % 8) != 0)
613 {
cristyf054ee72011-10-05 17:04:08 +0000614 byte=(size_t) ReadBlobByte(image);
cristy3ed852e2009-09-05 21:47:34 +0000615 for (bit=0; bit < (image->columns % 8); bit++)
cristy4c08aed2011-07-01 19:47:50 +0000616 {
617 SetPixelAlpha(image,(((byte & (0x80 >> bit)) != 0) ?
618 TransparentAlpha : OpaqueAlpha),q);
cristyed231572011-07-14 02:18:59 +0000619 q+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +0000620 }
cristy3ed852e2009-09-05 21:47:34 +0000621 }
cristy0e8200f2009-09-13 21:10:06 +0000622 if ((image->columns % 32) != 0)
cristybb503372010-05-27 20:51:26 +0000623 for (x=0; x < (ssize_t) ((32-(image->columns % 32))/8); x++)
cristyf054ee72011-10-05 17:04:08 +0000624 (void) ReadBlobByte(image);
cristy3ed852e2009-09-05 21:47:34 +0000625 if (SyncAuthenticPixels(image,exception) == MagickFalse)
626 break;
627 }
628 }
629 if (EOFBlob(image) != MagickFalse)
630 {
631 ThrowFileException(exception,CorruptImageError,
632 "UnexpectedEndOfFile",image->filename);
633 break;
634 }
635 }
636 /*
637 Proceed to next image.
638 */
639 if (image_info->number_scenes != 0)
640 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
641 break;
cristybb503372010-05-27 20:51:26 +0000642 if (i < (ssize_t) (icon_file.count-1))
cristy3ed852e2009-09-05 21:47:34 +0000643 {
644 /*
645 Allocate next image structure.
646 */
cristy1f1de182011-10-05 18:41:34 +0000647 AcquireNextImage(image_info,image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000648 if (GetNextImageInList(image) == (Image *) NULL)
649 {
650 image=DestroyImageList(image);
651 return((Image *) NULL);
652 }
653 image=SyncNextImageInList(image);
654 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
655 GetBlobSize(image));
656 if (status == MagickFalse)
657 break;
658 }
659 }
660 (void) CloseBlob(image);
661 return(GetFirstImageInList(image));
662}
663
664/*
665%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
666% %
667% %
668% %
669% R e g i s t e r I C O N I m a g e %
670% %
671% %
672% %
673%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
674%
675% RegisterICONImage() adds attributes for the Icon image format to
676% the list of supported formats. The attributes include the image format
677% tag, a method to read and/or write the format, whether the format
678% supports the saving of more than one frame to the same file or blob,
679% whether the format supports native in-memory I/O, and a brief
680% description of the format.
681%
682% The format of the RegisterICONImage method is:
683%
cristybb503372010-05-27 20:51:26 +0000684% size_t RegisterICONImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000685%
686*/
cristybb503372010-05-27 20:51:26 +0000687ModuleExport size_t RegisterICONImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000688{
689 MagickInfo
690 *entry;
691
692 entry=SetMagickInfo("CUR");
693 entry->decoder=(DecodeImageHandler *) ReadICONImage;
694 entry->encoder=(EncodeImageHandler *) WriteICONImage;
695 entry->adjoin=MagickFalse;
696 entry->seekable_stream=MagickTrue;
697 entry->description=ConstantString("Microsoft icon");
698 entry->module=ConstantString("CUR");
699 (void) RegisterMagickInfo(entry);
700 entry=SetMagickInfo("ICO");
701 entry->decoder=(DecodeImageHandler *) ReadICONImage;
702 entry->encoder=(EncodeImageHandler *) WriteICONImage;
703 entry->adjoin=MagickTrue;
704 entry->seekable_stream=MagickTrue;
705 entry->description=ConstantString("Microsoft icon");
706 entry->module=ConstantString("ICON");
707 (void) RegisterMagickInfo(entry);
708 entry=SetMagickInfo("ICON");
709 entry->decoder=(DecodeImageHandler *) ReadICONImage;
710 entry->encoder=(EncodeImageHandler *) WriteICONImage;
711 entry->adjoin=MagickFalse;
712 entry->seekable_stream=MagickTrue;
713 entry->description=ConstantString("Microsoft icon");
714 entry->module=ConstantString("ICON");
715 (void) RegisterMagickInfo(entry);
716 return(MagickImageCoderSignature);
717}
718
719/*
720%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
721% %
722% %
723% %
724% U n r e g i s t e r I C O N I m a g e %
725% %
726% %
727% %
728%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
729%
730% UnregisterICONImage() removes format registrations made by the
731% ICON module from the list of supported formats.
732%
733% The format of the UnregisterICONImage method is:
734%
735% UnregisterICONImage(void)
736%
737*/
738ModuleExport void UnregisterICONImage(void)
739{
740 (void) UnregisterMagickInfo("CUR");
741 (void) UnregisterMagickInfo("ICO");
742 (void) UnregisterMagickInfo("ICON");
743}
744
745/*
746%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
747% %
748% %
749% %
750% W r i t e I C O N I m a g e %
751% %
752% %
753% %
754%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
755%
756% WriteICONImage() writes an image in Microsoft Windows bitmap encoded
757% image format, version 3 for Windows or (if the image has a matte channel)
758% version 4.
759%
glennrp4b708b82012-07-17 19:15:58 +0000760% It encodes any subimage as a compressed PNG image ("BI_PNG)",
761% only when its dimensions are 256x256 and image->compression is
762% undefined or is defined as ZipCompression.
763%
cristy3ed852e2009-09-05 21:47:34 +0000764% The format of the WriteICONImage method is:
765%
766% MagickBooleanType WriteICONImage(const ImageInfo *image_info,
cristy1e178e72011-08-28 19:44:34 +0000767% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000768%
769% A description of each parameter follows.
770%
771% o image_info: the image info.
772%
773% o image: The image.
774%
cristy1e178e72011-08-28 19:44:34 +0000775% o exception: return any errors or warnings in this structure.
776%
cristy3ed852e2009-09-05 21:47:34 +0000777*/
778static MagickBooleanType WriteICONImage(const ImageInfo *image_info,
cristy1e178e72011-08-28 19:44:34 +0000779 Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000780{
781 IconFile
782 icon_file;
783
784 IconInfo
785 icon_info;
786
787 Image
788 *next;
789
cristy3ed852e2009-09-05 21:47:34 +0000790 MagickBooleanType
791 status;
792
793 MagickOffsetType
794 offset,
795 scene;
796
cristy4c08aed2011-07-01 19:47:50 +0000797 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +0000798 *p;
799
cristybb503372010-05-27 20:51:26 +0000800 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000801 i,
802 x;
803
804 register unsigned char
805 *q;
806
cristyebc891a2011-04-24 23:04:16 +0000807 size_t
808 bytes_per_line,
809 scanline_pad;
810
811 ssize_t
812 y;
813
cristy3ed852e2009-09-05 21:47:34 +0000814 unsigned char
815 bit,
816 byte,
817 *pixels;
818
cristy3ed852e2009-09-05 21:47:34 +0000819 /*
820 Open output image file.
821 */
822 assert(image_info != (const ImageInfo *) NULL);
823 assert(image_info->signature == MagickSignature);
824 assert(image != (Image *) NULL);
825 assert(image->signature == MagickSignature);
826 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"%s",image->filename);
cristy3a37efd2011-08-28 20:31:03 +0000827 assert(exception != (ExceptionInfo *) NULL);
828 assert(exception->signature == MagickSignature);
cristy1e178e72011-08-28 19:44:34 +0000829 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +0000830 if (status == MagickFalse)
831 return(status);
832 scene=0;
833 next=image;
834 do
835 {
836 if ((image->columns > 256L) || (image->rows > 256L))
837 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
838 scene++;
839 next=SyncNextImageInList(next);
840 } while ((next != (Image *) NULL) && (image_info->adjoin != MagickFalse));
841 /*
842 Dump out a ICON header template to be properly initialized later.
843 */
844 (void) WriteBlobLSBShort(image,0);
845 (void) WriteBlobLSBShort(image,1);
846 (void) WriteBlobLSBShort(image,(unsigned char) scene);
847 (void) ResetMagickMemory(&icon_file,0,sizeof(icon_file));
848 (void) ResetMagickMemory(&icon_info,0,sizeof(icon_info));
849 scene=0;
850 next=image;
851 do
852 {
853 (void) WriteBlobByte(image,icon_file.directory[scene].width);
854 (void) WriteBlobByte(image,icon_file.directory[scene].height);
855 (void) WriteBlobByte(image,icon_file.directory[scene].colors);
856 (void) WriteBlobByte(image,icon_file.directory[scene].reserved);
857 (void) WriteBlobLSBShort(image,icon_file.directory[scene].planes);
858 (void) WriteBlobLSBShort(image,icon_file.directory[scene].bits_per_pixel);
cristy0b29b252010-05-30 01:59:46 +0000859 (void) WriteBlobLSBLong(image,(unsigned int)
860 icon_file.directory[scene].size);
861 (void) WriteBlobLSBLong(image,(unsigned int)
862 icon_file.directory[scene].offset);
cristy3ed852e2009-09-05 21:47:34 +0000863 scene++;
864 next=SyncNextImageInList(next);
865 } while ((next != (Image *) NULL) && (image_info->adjoin != MagickFalse));
866 scene=0;
867 next=image;
868 do
869 {
glennrp4b708b82012-07-17 19:15:58 +0000870 if ((next->columns > 255L) && (next->rows > 255L) &&
871 ((next->compression == UndefinedCompression) ||
872 (next->compression == ZipCompression)))
cristy3ed852e2009-09-05 21:47:34 +0000873 {
874 Image
875 *write_image;
876
877 ImageInfo
878 *write_info;
879
880 size_t
881 length;
882
883 unsigned char
884 *png;
885
cristy1e178e72011-08-28 19:44:34 +0000886 write_image=CloneImage(next,0,0,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +0000887 if (write_image == (Image *) NULL)
888 return(MagickFalse);
889 write_info=CloneImageInfo(image_info);
890 (void) CopyMagickString(write_info->filename,"PNG:",MaxTextExtent);
glennrp4b708b82012-07-17 19:15:58 +0000891
892 /* Don't write any ancillary chunks except for gAMA */
893 (void) SetImageArtifact(write_image,"png:include-chunk","none,gama");
894
895 /* Only write PNG32 formatted PNG (32-bit RGBA), 8 bits per channel */
896 (void) SetImageArtifact(write_image,"png:format","png32");
897
cristy3ed852e2009-09-05 21:47:34 +0000898 png=(unsigned char *) ImageToBlob(write_info,write_image,&length,
cristy1e178e72011-08-28 19:44:34 +0000899 exception);
cristy3ed852e2009-09-05 21:47:34 +0000900 write_image=DestroyImage(write_image);
901 write_info=DestroyImageInfo(write_info);
902 if (png == (unsigned char *) NULL)
903 return(MagickFalse);
904 icon_file.directory[scene].width=0;
905 icon_file.directory[scene].height=0;
906 icon_file.directory[scene].colors=0;
907 icon_file.directory[scene].reserved=0;
908 icon_file.directory[scene].planes=1;
909 icon_file.directory[scene].bits_per_pixel=32;
cristybb503372010-05-27 20:51:26 +0000910 icon_file.directory[scene].size=(size_t) length;
911 icon_file.directory[scene].offset=(size_t) TellBlob(image);
cristy3ed852e2009-09-05 21:47:34 +0000912 (void) WriteBlob(image,(size_t) length,png);
913 png=(unsigned char *) RelinquishMagickMemory(png);
914 }
915 else
916 {
917 /*
918 Initialize ICON raster file header.
919 */
cristy3d9f5ba2012-06-26 13:37:31 +0000920 if (IssRGBCompatibleColorspace(next->colorspace) == MagickFalse)
cristyc511e882012-04-16 21:11:14 +0000921 (void) TransformImageColorspace(next,sRGBColorspace,exception);
cristy3ed852e2009-09-05 21:47:34 +0000922 icon_info.file_size=14+12+28;
923 icon_info.offset_bits=icon_info.file_size;
924 icon_info.compression=BI_RGB;
925 if ((next->storage_class != DirectClass) && (next->colors > 256))
cristy1e178e72011-08-28 19:44:34 +0000926 (void) SetImageStorageClass(next,DirectClass,exception);
cristy3ed852e2009-09-05 21:47:34 +0000927 if (next->storage_class == DirectClass)
928 {
929 /*
930 Full color ICON raster.
931 */
932 icon_info.number_colors=0;
933 icon_info.bits_per_pixel=32;
cristybb503372010-05-27 20:51:26 +0000934 icon_info.compression=(size_t) BI_RGB;
cristy3ed852e2009-09-05 21:47:34 +0000935 }
936 else
937 {
cristy35ef8242010-06-03 16:24:13 +0000938 size_t
939 one;
940
cristy3ed852e2009-09-05 21:47:34 +0000941 /*
942 Colormapped ICON raster.
943 */
944 icon_info.bits_per_pixel=8;
945 if (next->colors <= 256)
946 icon_info.bits_per_pixel=8;
947 if (next->colors <= 16)
948 icon_info.bits_per_pixel=4;
949 if (next->colors <= 2)
950 icon_info.bits_per_pixel=1;
cristy35ef8242010-06-03 16:24:13 +0000951 one=1;
952 icon_info.number_colors=one << icon_info.bits_per_pixel;
cristy3ed852e2009-09-05 21:47:34 +0000953 if (icon_info.number_colors < next->colors)
954 {
cristy1e178e72011-08-28 19:44:34 +0000955 (void) SetImageStorageClass(next,DirectClass,exception);
cristy3ed852e2009-09-05 21:47:34 +0000956 icon_info.number_colors=0;
957 icon_info.bits_per_pixel=(unsigned short) 24;
cristybb503372010-05-27 20:51:26 +0000958 icon_info.compression=(size_t) BI_RGB;
cristy3ed852e2009-09-05 21:47:34 +0000959 }
960 else
961 {
cristy0b29b252010-05-30 01:59:46 +0000962 size_t
963 one;
964
965 one=1;
966 icon_info.file_size+=3*(one << icon_info.bits_per_pixel);
967 icon_info.offset_bits+=3*(one << icon_info.bits_per_pixel);
968 icon_info.file_size+=(one << icon_info.bits_per_pixel);
969 icon_info.offset_bits+=(one << icon_info.bits_per_pixel);
cristy3ed852e2009-09-05 21:47:34 +0000970 }
971 }
972 bytes_per_line=(((next->columns*icon_info.bits_per_pixel)+31) &
973 ~31) >> 3;
974 icon_info.ba_offset=0;
cristybb503372010-05-27 20:51:26 +0000975 icon_info.width=(ssize_t) next->columns;
976 icon_info.height=(ssize_t) next->rows;
cristy3ed852e2009-09-05 21:47:34 +0000977 icon_info.planes=1;
978 icon_info.image_size=bytes_per_line*next->rows;
979 icon_info.size=40;
980 icon_info.size+=(4*icon_info.number_colors);
981 icon_info.size+=icon_info.image_size;
982 icon_info.size+=(((icon_info.width+31) & ~31) >> 3)*icon_info.height;
983 icon_info.file_size+=icon_info.image_size;
984 icon_info.x_pixels=0;
985 icon_info.y_pixels=0;
986 switch (next->units)
987 {
988 case UndefinedResolution:
989 case PixelsPerInchResolution:
990 {
cristy2a11bef2011-10-28 18:33:11 +0000991 icon_info.x_pixels=(size_t) (100.0*next->resolution.x/2.54);
992 icon_info.y_pixels=(size_t) (100.0*next->resolution.y/2.54);
cristy3ed852e2009-09-05 21:47:34 +0000993 break;
994 }
995 case PixelsPerCentimeterResolution:
996 {
cristy2a11bef2011-10-28 18:33:11 +0000997 icon_info.x_pixels=(size_t) (100.0*next->resolution.x);
998 icon_info.y_pixels=(size_t) (100.0*next->resolution.y);
cristy3ed852e2009-09-05 21:47:34 +0000999 break;
1000 }
1001 }
1002 icon_info.colors_important=icon_info.number_colors;
1003 /*
1004 Convert MIFF to ICON raster pixels.
1005 */
1006 pixels=(unsigned char *) AcquireQuantumMemory((size_t)
1007 icon_info.image_size,sizeof(*pixels));
1008 if (pixels == (unsigned char *) NULL)
1009 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1010 (void) ResetMagickMemory(pixels,0,(size_t) icon_info.image_size);
1011 switch (icon_info.bits_per_pixel)
1012 {
1013 case 1:
1014 {
cristybb503372010-05-27 20:51:26 +00001015 size_t
cristy3ed852e2009-09-05 21:47:34 +00001016 bit,
1017 byte;
1018
1019 /*
1020 Convert PseudoClass image to a ICON monochrome image.
1021 */
cristybb503372010-05-27 20:51:26 +00001022 for (y=0; y < (ssize_t) next->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001023 {
cristy1e178e72011-08-28 19:44:34 +00001024 p=GetVirtualPixels(next,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001025 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001026 break;
cristy3ed852e2009-09-05 21:47:34 +00001027 q=pixels+(next->rows-y-1)*bytes_per_line;
1028 bit=0;
1029 byte=0;
cristybb503372010-05-27 20:51:26 +00001030 for (x=0; x < (ssize_t) next->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001031 {
1032 byte<<=1;
cristy4c08aed2011-07-01 19:47:50 +00001033 byte|=GetPixelIndex(next,p) != 0 ? 0x01 : 0x00;
cristy3ed852e2009-09-05 21:47:34 +00001034 bit++;
1035 if (bit == 8)
1036 {
1037 *q++=(unsigned char) byte;
1038 bit=0;
1039 byte=0;
1040 }
cristyed231572011-07-14 02:18:59 +00001041 p+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00001042 }
cristy3ed852e2009-09-05 21:47:34 +00001043 if (bit != 0)
1044 *q++=(unsigned char) (byte << (8-bit));
1045 if (next->previous == (Image *) NULL)
1046 {
1047 status=SetImageProgress(next,SaveImageTag,y,next->rows);
1048 if (status == MagickFalse)
1049 break;
1050 }
1051 }
1052 break;
1053 }
1054 case 4:
1055 {
cristybb503372010-05-27 20:51:26 +00001056 size_t
cristy3ed852e2009-09-05 21:47:34 +00001057 nibble,
1058 byte;
1059
1060 /*
1061 Convert PseudoClass image to a ICON monochrome image.
1062 */
cristybb503372010-05-27 20:51:26 +00001063 for (y=0; y < (ssize_t) next->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001064 {
cristy1e178e72011-08-28 19:44:34 +00001065 p=GetVirtualPixels(next,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001066 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001067 break;
cristy3ed852e2009-09-05 21:47:34 +00001068 q=pixels+(next->rows-y-1)*bytes_per_line;
1069 nibble=0;
1070 byte=0;
cristybb503372010-05-27 20:51:26 +00001071 for (x=0; x < (ssize_t) next->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001072 {
1073 byte<<=4;
cristy4c08aed2011-07-01 19:47:50 +00001074 byte|=((size_t) GetPixelIndex(next,p) & 0x0f);
cristy3ed852e2009-09-05 21:47:34 +00001075 nibble++;
1076 if (nibble == 2)
1077 {
1078 *q++=(unsigned char) byte;
1079 nibble=0;
1080 byte=0;
1081 }
cristyed231572011-07-14 02:18:59 +00001082 p+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00001083 }
cristy3ed852e2009-09-05 21:47:34 +00001084 if (nibble != 0)
1085 *q++=(unsigned char) (byte << 4);
1086 if (next->previous == (Image *) NULL)
1087 {
1088 status=SetImageProgress(next,SaveImageTag,y,next->rows);
1089 if (status == MagickFalse)
1090 break;
1091 }
1092 }
1093 break;
1094 }
1095 case 8:
1096 {
1097 /*
1098 Convert PseudoClass packet to ICON pixel.
1099 */
cristybb503372010-05-27 20:51:26 +00001100 for (y=0; y < (ssize_t) next->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001101 {
cristy1e178e72011-08-28 19:44:34 +00001102 p=GetVirtualPixels(next,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001103 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001104 break;
cristy3ed852e2009-09-05 21:47:34 +00001105 q=pixels+(next->rows-y-1)*bytes_per_line;
cristybb503372010-05-27 20:51:26 +00001106 for (x=0; x < (ssize_t) next->columns; x++)
cristy4c08aed2011-07-01 19:47:50 +00001107 {
1108 *q++=(unsigned char) GetPixelIndex(next,p);
cristyed231572011-07-14 02:18:59 +00001109 p+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00001110 }
cristy3ed852e2009-09-05 21:47:34 +00001111 if (next->previous == (Image *) NULL)
1112 {
1113 status=SetImageProgress(next,SaveImageTag,y,next->rows);
1114 if (status == MagickFalse)
1115 break;
1116 }
1117 }
1118 break;
1119 }
1120 case 24:
1121 case 32:
1122 {
1123 /*
1124 Convert DirectClass packet to ICON BGR888 or BGRA8888 pixel.
1125 */
cristybb503372010-05-27 20:51:26 +00001126 for (y=0; y < (ssize_t) next->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001127 {
cristy1e178e72011-08-28 19:44:34 +00001128 p=GetVirtualPixels(next,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001129 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001130 break;
1131 q=pixels+(next->rows-y-1)*bytes_per_line;
cristybb503372010-05-27 20:51:26 +00001132 for (x=0; x < (ssize_t) next->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001133 {
cristy4c08aed2011-07-01 19:47:50 +00001134 *q++=ScaleQuantumToChar(GetPixelBlue(next,p));
1135 *q++=ScaleQuantumToChar(GetPixelGreen(next,p));
1136 *q++=ScaleQuantumToChar(GetPixelRed(next,p));
cristy3ed852e2009-09-05 21:47:34 +00001137 if (next->matte == MagickFalse)
1138 *q++=ScaleQuantumToChar(QuantumRange);
1139 else
cristy4c08aed2011-07-01 19:47:50 +00001140 *q++=ScaleQuantumToChar(GetPixelAlpha(next,p));
cristyed231572011-07-14 02:18:59 +00001141 p+=GetPixelChannels(next);
cristy3ed852e2009-09-05 21:47:34 +00001142 }
1143 if (icon_info.bits_per_pixel == 24)
cristybb503372010-05-27 20:51:26 +00001144 for (x=3L*(ssize_t) next->columns; x < (ssize_t) bytes_per_line; x++)
cristy3ed852e2009-09-05 21:47:34 +00001145 *q++=0x00;
1146 if (next->previous == (Image *) NULL)
1147 {
1148 status=SetImageProgress(next,SaveImageTag,y,next->rows);
1149 if (status == MagickFalse)
1150 break;
1151 }
1152 }
1153 break;
1154 }
1155 }
1156 /*
1157 Write 40-byte version 3+ bitmap header.
1158 */
1159 icon_file.directory[scene].width=(unsigned char) icon_info.width;
1160 icon_file.directory[scene].height=(unsigned char) icon_info.height;
1161 icon_file.directory[scene].colors=(unsigned char)
1162 icon_info.number_colors;
1163 icon_file.directory[scene].reserved=0;
1164 icon_file.directory[scene].planes=icon_info.planes;
1165 icon_file.directory[scene].bits_per_pixel=icon_info.bits_per_pixel;
1166 icon_file.directory[scene].size=icon_info.size;
cristybb503372010-05-27 20:51:26 +00001167 icon_file.directory[scene].offset=(size_t) TellBlob(image);
cristy35ef8242010-06-03 16:24:13 +00001168 (void) WriteBlobLSBLong(image,(unsigned int) 40);
1169 (void) WriteBlobLSBLong(image,(unsigned int) icon_info.width);
1170 (void) WriteBlobLSBLong(image,(unsigned int) icon_info.height*2);
cristy3ed852e2009-09-05 21:47:34 +00001171 (void) WriteBlobLSBShort(image,icon_info.planes);
1172 (void) WriteBlobLSBShort(image,icon_info.bits_per_pixel);
cristy35ef8242010-06-03 16:24:13 +00001173 (void) WriteBlobLSBLong(image,(unsigned int) icon_info.compression);
1174 (void) WriteBlobLSBLong(image,(unsigned int) icon_info.image_size);
1175 (void) WriteBlobLSBLong(image,(unsigned int) icon_info.x_pixels);
1176 (void) WriteBlobLSBLong(image,(unsigned int) icon_info.y_pixels);
1177 (void) WriteBlobLSBLong(image,(unsigned int) icon_info.number_colors);
1178 (void) WriteBlobLSBLong(image,(unsigned int) icon_info.colors_important);
cristy3ed852e2009-09-05 21:47:34 +00001179 if (next->storage_class == PseudoClass)
1180 {
1181 unsigned char
1182 *icon_colormap;
1183
1184 /*
1185 Dump colormap to file.
1186 */
1187 icon_colormap=(unsigned char *) AcquireQuantumMemory((size_t)
1188 (1UL << icon_info.bits_per_pixel),4UL*sizeof(*icon_colormap));
1189 if (icon_colormap == (unsigned char *) NULL)
1190 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1191 q=icon_colormap;
cristybb503372010-05-27 20:51:26 +00001192 for (i=0; i < (ssize_t) next->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00001193 {
1194 *q++=ScaleQuantumToChar(next->colormap[i].blue);
1195 *q++=ScaleQuantumToChar(next->colormap[i].green);
1196 *q++=ScaleQuantumToChar(next->colormap[i].red);
1197 *q++=(unsigned char) 0x0;
1198 }
cristybb503372010-05-27 20:51:26 +00001199 for ( ; i < (ssize_t) (1UL << icon_info.bits_per_pixel); i++)
cristy3ed852e2009-09-05 21:47:34 +00001200 {
1201 *q++=(unsigned char) 0x00;
1202 *q++=(unsigned char) 0x00;
1203 *q++=(unsigned char) 0x00;
1204 *q++=(unsigned char) 0x00;
1205 }
1206 (void) WriteBlob(image,(size_t) (4UL*(1UL <<
1207 icon_info.bits_per_pixel)),icon_colormap);
1208 icon_colormap=(unsigned char *) RelinquishMagickMemory(
1209 icon_colormap);
1210 }
1211 (void) WriteBlob(image,(size_t) icon_info.image_size,pixels);
1212 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1213 /*
1214 Write matte mask.
1215 */
1216 scanline_pad=(((next->columns+31) & ~31)-next->columns) >> 3;
cristybb503372010-05-27 20:51:26 +00001217 for (y=((ssize_t) next->rows - 1); y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +00001218 {
cristy1e178e72011-08-28 19:44:34 +00001219 p=GetVirtualPixels(next,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001220 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001221 break;
1222 bit=0;
1223 byte=0;
cristybb503372010-05-27 20:51:26 +00001224 for (x=0; x < (ssize_t) next->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001225 {
1226 byte<<=1;
1227 if ((next->matte == MagickTrue) &&
cristy4c08aed2011-07-01 19:47:50 +00001228 (GetPixelAlpha(next,p) == (Quantum) TransparentAlpha))
cristy3ed852e2009-09-05 21:47:34 +00001229 byte|=0x01;
1230 bit++;
1231 if (bit == 8)
1232 {
1233 (void) WriteBlobByte(image,(unsigned char) byte);
1234 bit=0;
1235 byte=0;
1236 }
cristyed231572011-07-14 02:18:59 +00001237 p+=GetPixelChannels(next);
cristy3ed852e2009-09-05 21:47:34 +00001238 }
1239 if (bit != 0)
1240 (void) WriteBlobByte(image,(unsigned char) (byte << (8-bit)));
cristybb503372010-05-27 20:51:26 +00001241 for (i=0; i < (ssize_t) scanline_pad; i++)
cristy3ed852e2009-09-05 21:47:34 +00001242 (void) WriteBlobByte(image,(unsigned char) 0);
1243 }
1244 }
1245 if (GetNextImageInList(next) == (Image *) NULL)
1246 break;
1247 next=SyncNextImageInList(next);
1248 status=SetImageProgress(next,SaveImagesTag,scene++,
1249 GetImageListLength(next));
1250 if (status == MagickFalse)
1251 break;
1252 } while ((next != (Image *) NULL) && (image_info->adjoin != MagickFalse));
1253 offset=SeekBlob(image,0,SEEK_SET);
cristyda16f162011-02-19 23:52:17 +00001254 (void) offset;
cristy3ed852e2009-09-05 21:47:34 +00001255 (void) WriteBlobLSBShort(image,0);
1256 (void) WriteBlobLSBShort(image,1);
1257 (void) WriteBlobLSBShort(image,(unsigned short) (scene+1));
1258 scene=0;
1259 next=image;
1260 do
1261 {
1262 (void) WriteBlobByte(image,icon_file.directory[scene].width);
1263 (void) WriteBlobByte(image,icon_file.directory[scene].height);
1264 (void) WriteBlobByte(image,icon_file.directory[scene].colors);
1265 (void) WriteBlobByte(image,icon_file.directory[scene].reserved);
1266 (void) WriteBlobLSBShort(image,icon_file.directory[scene].planes);
1267 (void) WriteBlobLSBShort(image,icon_file.directory[scene].bits_per_pixel);
cristy0b29b252010-05-30 01:59:46 +00001268 (void) WriteBlobLSBLong(image,(unsigned int)
1269 icon_file.directory[scene].size);
1270 (void) WriteBlobLSBLong(image,(unsigned int)
1271 icon_file.directory[scene].offset);
cristy3ed852e2009-09-05 21:47:34 +00001272 scene++;
1273 next=SyncNextImageInList(next);
1274 } while ((next != (Image *) NULL) && (image_info->adjoin != MagickFalse));
1275 (void) CloseBlob(image);
1276 return(MagickTrue);
1277}