blob: 63eec997d0f332e4e964307ab6e4d27d36ac69a9 [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 {
cristy85336bc2012-02-01 21:10:23 +0000865 if ((next->columns > 256L) && (next->rows > 256L) &&
866 (next->compression == ZipCompression))
cristy3ed852e2009-09-05 21:47:34 +0000867 {
868 Image
869 *write_image;
870
871 ImageInfo
872 *write_info;
873
874 size_t
875 length;
876
877 unsigned char
878 *png;
879
880 /*
881 Icon image encoded as a compressed PNG image.
882 */
cristy1e178e72011-08-28 19:44:34 +0000883 write_image=CloneImage(next,0,0,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +0000884 if (write_image == (Image *) NULL)
885 return(MagickFalse);
886 write_info=CloneImageInfo(image_info);
887 (void) CopyMagickString(write_info->filename,"PNG:",MaxTextExtent);
cristyd603d972012-02-01 21:12:03 +0000888 /*
889 Don't write any ancillary chunks except for gAMA and tRNS.
890 */
glennrpaa192b12012-01-17 21:35:21 +0000891 (void) SetImageArtifact(write_image,"png:include-chunk",
892 "none,trns,gama");
cristy3ed852e2009-09-05 21:47:34 +0000893 png=(unsigned char *) ImageToBlob(write_info,write_image,&length,
cristy1e178e72011-08-28 19:44:34 +0000894 exception);
cristy3ed852e2009-09-05 21:47:34 +0000895 write_image=DestroyImage(write_image);
896 write_info=DestroyImageInfo(write_info);
897 if (png == (unsigned char *) NULL)
898 return(MagickFalse);
899 icon_file.directory[scene].width=0;
900 icon_file.directory[scene].height=0;
901 icon_file.directory[scene].colors=0;
902 icon_file.directory[scene].reserved=0;
903 icon_file.directory[scene].planes=1;
904 icon_file.directory[scene].bits_per_pixel=32;
cristybb503372010-05-27 20:51:26 +0000905 icon_file.directory[scene].size=(size_t) length;
906 icon_file.directory[scene].offset=(size_t) TellBlob(image);
cristy3ed852e2009-09-05 21:47:34 +0000907 (void) WriteBlob(image,(size_t) length,png);
908 png=(unsigned char *) RelinquishMagickMemory(png);
909 }
910 else
911 {
912 /*
913 Initialize ICON raster file header.
914 */
915 if (next->colorspace != RGBColorspace)
cristye941a752011-10-15 01:52:48 +0000916 (void) TransformImageColorspace(next,RGBColorspace,exception);
cristy3ed852e2009-09-05 21:47:34 +0000917 icon_info.file_size=14+12+28;
918 icon_info.offset_bits=icon_info.file_size;
919 icon_info.compression=BI_RGB;
920 if ((next->storage_class != DirectClass) && (next->colors > 256))
cristy1e178e72011-08-28 19:44:34 +0000921 (void) SetImageStorageClass(next,DirectClass,exception);
cristy3ed852e2009-09-05 21:47:34 +0000922 if (next->storage_class == DirectClass)
923 {
924 /*
925 Full color ICON raster.
926 */
927 icon_info.number_colors=0;
928 icon_info.bits_per_pixel=32;
cristybb503372010-05-27 20:51:26 +0000929 icon_info.compression=(size_t) BI_RGB;
cristy3ed852e2009-09-05 21:47:34 +0000930 }
931 else
932 {
cristy35ef8242010-06-03 16:24:13 +0000933 size_t
934 one;
935
cristy3ed852e2009-09-05 21:47:34 +0000936 /*
937 Colormapped ICON raster.
938 */
939 icon_info.bits_per_pixel=8;
940 if (next->colors <= 256)
941 icon_info.bits_per_pixel=8;
942 if (next->colors <= 16)
943 icon_info.bits_per_pixel=4;
944 if (next->colors <= 2)
945 icon_info.bits_per_pixel=1;
cristy35ef8242010-06-03 16:24:13 +0000946 one=1;
947 icon_info.number_colors=one << icon_info.bits_per_pixel;
cristy3ed852e2009-09-05 21:47:34 +0000948 if (icon_info.number_colors < next->colors)
949 {
cristy1e178e72011-08-28 19:44:34 +0000950 (void) SetImageStorageClass(next,DirectClass,exception);
cristy3ed852e2009-09-05 21:47:34 +0000951 icon_info.number_colors=0;
952 icon_info.bits_per_pixel=(unsigned short) 24;
cristybb503372010-05-27 20:51:26 +0000953 icon_info.compression=(size_t) BI_RGB;
cristy3ed852e2009-09-05 21:47:34 +0000954 }
955 else
956 {
cristy0b29b252010-05-30 01:59:46 +0000957 size_t
958 one;
959
960 one=1;
961 icon_info.file_size+=3*(one << icon_info.bits_per_pixel);
962 icon_info.offset_bits+=3*(one << icon_info.bits_per_pixel);
963 icon_info.file_size+=(one << icon_info.bits_per_pixel);
964 icon_info.offset_bits+=(one << icon_info.bits_per_pixel);
cristy3ed852e2009-09-05 21:47:34 +0000965 }
966 }
967 bytes_per_line=(((next->columns*icon_info.bits_per_pixel)+31) &
968 ~31) >> 3;
969 icon_info.ba_offset=0;
cristybb503372010-05-27 20:51:26 +0000970 icon_info.width=(ssize_t) next->columns;
971 icon_info.height=(ssize_t) next->rows;
cristy3ed852e2009-09-05 21:47:34 +0000972 icon_info.planes=1;
973 icon_info.image_size=bytes_per_line*next->rows;
974 icon_info.size=40;
975 icon_info.size+=(4*icon_info.number_colors);
976 icon_info.size+=icon_info.image_size;
977 icon_info.size+=(((icon_info.width+31) & ~31) >> 3)*icon_info.height;
978 icon_info.file_size+=icon_info.image_size;
979 icon_info.x_pixels=0;
980 icon_info.y_pixels=0;
981 switch (next->units)
982 {
983 case UndefinedResolution:
984 case PixelsPerInchResolution:
985 {
cristy2a11bef2011-10-28 18:33:11 +0000986 icon_info.x_pixels=(size_t) (100.0*next->resolution.x/2.54);
987 icon_info.y_pixels=(size_t) (100.0*next->resolution.y/2.54);
cristy3ed852e2009-09-05 21:47:34 +0000988 break;
989 }
990 case PixelsPerCentimeterResolution:
991 {
cristy2a11bef2011-10-28 18:33:11 +0000992 icon_info.x_pixels=(size_t) (100.0*next->resolution.x);
993 icon_info.y_pixels=(size_t) (100.0*next->resolution.y);
cristy3ed852e2009-09-05 21:47:34 +0000994 break;
995 }
996 }
997 icon_info.colors_important=icon_info.number_colors;
998 /*
999 Convert MIFF to ICON raster pixels.
1000 */
1001 pixels=(unsigned char *) AcquireQuantumMemory((size_t)
1002 icon_info.image_size,sizeof(*pixels));
1003 if (pixels == (unsigned char *) NULL)
1004 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1005 (void) ResetMagickMemory(pixels,0,(size_t) icon_info.image_size);
1006 switch (icon_info.bits_per_pixel)
1007 {
1008 case 1:
1009 {
cristybb503372010-05-27 20:51:26 +00001010 size_t
cristy3ed852e2009-09-05 21:47:34 +00001011 bit,
1012 byte;
1013
1014 /*
1015 Convert PseudoClass image to a ICON monochrome image.
1016 */
cristybb503372010-05-27 20:51:26 +00001017 for (y=0; y < (ssize_t) next->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001018 {
cristy1e178e72011-08-28 19:44:34 +00001019 p=GetVirtualPixels(next,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001020 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001021 break;
cristy3ed852e2009-09-05 21:47:34 +00001022 q=pixels+(next->rows-y-1)*bytes_per_line;
1023 bit=0;
1024 byte=0;
cristybb503372010-05-27 20:51:26 +00001025 for (x=0; x < (ssize_t) next->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001026 {
1027 byte<<=1;
cristy4c08aed2011-07-01 19:47:50 +00001028 byte|=GetPixelIndex(next,p) != 0 ? 0x01 : 0x00;
cristy3ed852e2009-09-05 21:47:34 +00001029 bit++;
1030 if (bit == 8)
1031 {
1032 *q++=(unsigned char) byte;
1033 bit=0;
1034 byte=0;
1035 }
cristyed231572011-07-14 02:18:59 +00001036 p+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00001037 }
cristy3ed852e2009-09-05 21:47:34 +00001038 if (bit != 0)
1039 *q++=(unsigned char) (byte << (8-bit));
1040 if (next->previous == (Image *) NULL)
1041 {
1042 status=SetImageProgress(next,SaveImageTag,y,next->rows);
1043 if (status == MagickFalse)
1044 break;
1045 }
1046 }
1047 break;
1048 }
1049 case 4:
1050 {
cristybb503372010-05-27 20:51:26 +00001051 size_t
cristy3ed852e2009-09-05 21:47:34 +00001052 nibble,
1053 byte;
1054
1055 /*
1056 Convert PseudoClass image to a ICON monochrome image.
1057 */
cristybb503372010-05-27 20:51:26 +00001058 for (y=0; y < (ssize_t) next->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001059 {
cristy1e178e72011-08-28 19:44:34 +00001060 p=GetVirtualPixels(next,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001061 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001062 break;
cristy3ed852e2009-09-05 21:47:34 +00001063 q=pixels+(next->rows-y-1)*bytes_per_line;
1064 nibble=0;
1065 byte=0;
cristybb503372010-05-27 20:51:26 +00001066 for (x=0; x < (ssize_t) next->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001067 {
1068 byte<<=4;
cristy4c08aed2011-07-01 19:47:50 +00001069 byte|=((size_t) GetPixelIndex(next,p) & 0x0f);
cristy3ed852e2009-09-05 21:47:34 +00001070 nibble++;
1071 if (nibble == 2)
1072 {
1073 *q++=(unsigned char) byte;
1074 nibble=0;
1075 byte=0;
1076 }
cristyed231572011-07-14 02:18:59 +00001077 p+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00001078 }
cristy3ed852e2009-09-05 21:47:34 +00001079 if (nibble != 0)
1080 *q++=(unsigned char) (byte << 4);
1081 if (next->previous == (Image *) NULL)
1082 {
1083 status=SetImageProgress(next,SaveImageTag,y,next->rows);
1084 if (status == MagickFalse)
1085 break;
1086 }
1087 }
1088 break;
1089 }
1090 case 8:
1091 {
1092 /*
1093 Convert PseudoClass packet to ICON pixel.
1094 */
cristybb503372010-05-27 20:51:26 +00001095 for (y=0; y < (ssize_t) next->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001096 {
cristy1e178e72011-08-28 19:44:34 +00001097 p=GetVirtualPixels(next,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001098 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001099 break;
cristy3ed852e2009-09-05 21:47:34 +00001100 q=pixels+(next->rows-y-1)*bytes_per_line;
cristybb503372010-05-27 20:51:26 +00001101 for (x=0; x < (ssize_t) next->columns; x++)
cristy4c08aed2011-07-01 19:47:50 +00001102 {
1103 *q++=(unsigned char) GetPixelIndex(next,p);
cristyed231572011-07-14 02:18:59 +00001104 p+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00001105 }
cristy3ed852e2009-09-05 21:47:34 +00001106 if (next->previous == (Image *) NULL)
1107 {
1108 status=SetImageProgress(next,SaveImageTag,y,next->rows);
1109 if (status == MagickFalse)
1110 break;
1111 }
1112 }
1113 break;
1114 }
1115 case 24:
1116 case 32:
1117 {
1118 /*
1119 Convert DirectClass packet to ICON BGR888 or BGRA8888 pixel.
1120 */
cristybb503372010-05-27 20:51:26 +00001121 for (y=0; y < (ssize_t) next->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001122 {
cristy1e178e72011-08-28 19:44:34 +00001123 p=GetVirtualPixels(next,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001124 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001125 break;
1126 q=pixels+(next->rows-y-1)*bytes_per_line;
cristybb503372010-05-27 20:51:26 +00001127 for (x=0; x < (ssize_t) next->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001128 {
cristy4c08aed2011-07-01 19:47:50 +00001129 *q++=ScaleQuantumToChar(GetPixelBlue(next,p));
1130 *q++=ScaleQuantumToChar(GetPixelGreen(next,p));
1131 *q++=ScaleQuantumToChar(GetPixelRed(next,p));
cristy3ed852e2009-09-05 21:47:34 +00001132 if (next->matte == MagickFalse)
1133 *q++=ScaleQuantumToChar(QuantumRange);
1134 else
cristy4c08aed2011-07-01 19:47:50 +00001135 *q++=ScaleQuantumToChar(GetPixelAlpha(next,p));
cristyed231572011-07-14 02:18:59 +00001136 p+=GetPixelChannels(next);
cristy3ed852e2009-09-05 21:47:34 +00001137 }
1138 if (icon_info.bits_per_pixel == 24)
cristybb503372010-05-27 20:51:26 +00001139 for (x=3L*(ssize_t) next->columns; x < (ssize_t) bytes_per_line; x++)
cristy3ed852e2009-09-05 21:47:34 +00001140 *q++=0x00;
1141 if (next->previous == (Image *) NULL)
1142 {
1143 status=SetImageProgress(next,SaveImageTag,y,next->rows);
1144 if (status == MagickFalse)
1145 break;
1146 }
1147 }
1148 break;
1149 }
1150 }
1151 /*
1152 Write 40-byte version 3+ bitmap header.
1153 */
1154 icon_file.directory[scene].width=(unsigned char) icon_info.width;
1155 icon_file.directory[scene].height=(unsigned char) icon_info.height;
1156 icon_file.directory[scene].colors=(unsigned char)
1157 icon_info.number_colors;
1158 icon_file.directory[scene].reserved=0;
1159 icon_file.directory[scene].planes=icon_info.planes;
1160 icon_file.directory[scene].bits_per_pixel=icon_info.bits_per_pixel;
1161 icon_file.directory[scene].size=icon_info.size;
cristybb503372010-05-27 20:51:26 +00001162 icon_file.directory[scene].offset=(size_t) TellBlob(image);
cristy35ef8242010-06-03 16:24:13 +00001163 (void) WriteBlobLSBLong(image,(unsigned int) 40);
1164 (void) WriteBlobLSBLong(image,(unsigned int) icon_info.width);
1165 (void) WriteBlobLSBLong(image,(unsigned int) icon_info.height*2);
cristy3ed852e2009-09-05 21:47:34 +00001166 (void) WriteBlobLSBShort(image,icon_info.planes);
1167 (void) WriteBlobLSBShort(image,icon_info.bits_per_pixel);
cristy35ef8242010-06-03 16:24:13 +00001168 (void) WriteBlobLSBLong(image,(unsigned int) icon_info.compression);
1169 (void) WriteBlobLSBLong(image,(unsigned int) icon_info.image_size);
1170 (void) WriteBlobLSBLong(image,(unsigned int) icon_info.x_pixels);
1171 (void) WriteBlobLSBLong(image,(unsigned int) icon_info.y_pixels);
1172 (void) WriteBlobLSBLong(image,(unsigned int) icon_info.number_colors);
1173 (void) WriteBlobLSBLong(image,(unsigned int) icon_info.colors_important);
cristy3ed852e2009-09-05 21:47:34 +00001174 if (next->storage_class == PseudoClass)
1175 {
1176 unsigned char
1177 *icon_colormap;
1178
1179 /*
1180 Dump colormap to file.
1181 */
1182 icon_colormap=(unsigned char *) AcquireQuantumMemory((size_t)
1183 (1UL << icon_info.bits_per_pixel),4UL*sizeof(*icon_colormap));
1184 if (icon_colormap == (unsigned char *) NULL)
1185 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1186 q=icon_colormap;
cristybb503372010-05-27 20:51:26 +00001187 for (i=0; i < (ssize_t) next->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00001188 {
1189 *q++=ScaleQuantumToChar(next->colormap[i].blue);
1190 *q++=ScaleQuantumToChar(next->colormap[i].green);
1191 *q++=ScaleQuantumToChar(next->colormap[i].red);
1192 *q++=(unsigned char) 0x0;
1193 }
cristybb503372010-05-27 20:51:26 +00001194 for ( ; i < (ssize_t) (1UL << icon_info.bits_per_pixel); i++)
cristy3ed852e2009-09-05 21:47:34 +00001195 {
1196 *q++=(unsigned char) 0x00;
1197 *q++=(unsigned char) 0x00;
1198 *q++=(unsigned char) 0x00;
1199 *q++=(unsigned char) 0x00;
1200 }
1201 (void) WriteBlob(image,(size_t) (4UL*(1UL <<
1202 icon_info.bits_per_pixel)),icon_colormap);
1203 icon_colormap=(unsigned char *) RelinquishMagickMemory(
1204 icon_colormap);
1205 }
1206 (void) WriteBlob(image,(size_t) icon_info.image_size,pixels);
1207 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1208 /*
1209 Write matte mask.
1210 */
1211 scanline_pad=(((next->columns+31) & ~31)-next->columns) >> 3;
cristybb503372010-05-27 20:51:26 +00001212 for (y=((ssize_t) next->rows - 1); y >= 0; y--)
cristy3ed852e2009-09-05 21:47:34 +00001213 {
cristy1e178e72011-08-28 19:44:34 +00001214 p=GetVirtualPixels(next,0,y,next->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001215 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001216 break;
1217 bit=0;
1218 byte=0;
cristybb503372010-05-27 20:51:26 +00001219 for (x=0; x < (ssize_t) next->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001220 {
1221 byte<<=1;
1222 if ((next->matte == MagickTrue) &&
cristy4c08aed2011-07-01 19:47:50 +00001223 (GetPixelAlpha(next,p) == (Quantum) TransparentAlpha))
cristy3ed852e2009-09-05 21:47:34 +00001224 byte|=0x01;
1225 bit++;
1226 if (bit == 8)
1227 {
1228 (void) WriteBlobByte(image,(unsigned char) byte);
1229 bit=0;
1230 byte=0;
1231 }
cristyed231572011-07-14 02:18:59 +00001232 p+=GetPixelChannels(next);
cristy3ed852e2009-09-05 21:47:34 +00001233 }
1234 if (bit != 0)
1235 (void) WriteBlobByte(image,(unsigned char) (byte << (8-bit)));
cristybb503372010-05-27 20:51:26 +00001236 for (i=0; i < (ssize_t) scanline_pad; i++)
cristy3ed852e2009-09-05 21:47:34 +00001237 (void) WriteBlobByte(image,(unsigned char) 0);
1238 }
1239 }
1240 if (GetNextImageInList(next) == (Image *) NULL)
1241 break;
1242 next=SyncNextImageInList(next);
1243 status=SetImageProgress(next,SaveImagesTag,scene++,
1244 GetImageListLength(next));
1245 if (status == MagickFalse)
1246 break;
1247 } while ((next != (Image *) NULL) && (image_info->adjoin != MagickFalse));
1248 offset=SeekBlob(image,0,SEEK_SET);
cristyda16f162011-02-19 23:52:17 +00001249 (void) offset;
cristy3ed852e2009-09-05 21:47:34 +00001250 (void) WriteBlobLSBShort(image,0);
1251 (void) WriteBlobLSBShort(image,1);
1252 (void) WriteBlobLSBShort(image,(unsigned short) (scene+1));
1253 scene=0;
1254 next=image;
1255 do
1256 {
1257 (void) WriteBlobByte(image,icon_file.directory[scene].width);
1258 (void) WriteBlobByte(image,icon_file.directory[scene].height);
1259 (void) WriteBlobByte(image,icon_file.directory[scene].colors);
1260 (void) WriteBlobByte(image,icon_file.directory[scene].reserved);
1261 (void) WriteBlobLSBShort(image,icon_file.directory[scene].planes);
1262 (void) WriteBlobLSBShort(image,icon_file.directory[scene].bits_per_pixel);
cristy0b29b252010-05-30 01:59:46 +00001263 (void) WriteBlobLSBLong(image,(unsigned int)
1264 icon_file.directory[scene].size);
1265 (void) WriteBlobLSBLong(image,(unsigned int)
1266 icon_file.directory[scene].offset);
cristy3ed852e2009-09-05 21:47:34 +00001267 scene++;
1268 next=SyncNextImageInList(next);
1269 } while ((next != (Image *) NULL) && (image_info->adjoin != MagickFalse));
1270 (void) CloseBlob(image);
1271 return(MagickTrue);
1272}