/src/imagemagick/coders/icon.c
Line | Count | Source |
1 | | /* |
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 | | % Cristy % |
17 | | % July 1992 % |
18 | | % % |
19 | | % % |
20 | | % Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization % |
21 | | % 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 | | % https://imagemagick.org/license/ % |
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 | | */ |
42 | | #include "MagickCore/studio.h" |
43 | | #include "MagickCore/artifact.h" |
44 | | #include "MagickCore/attribute.h" |
45 | | #include "MagickCore/blob.h" |
46 | | #include "MagickCore/blob-private.h" |
47 | | #include "MagickCore/cache.h" |
48 | | #include "MagickCore/colormap.h" |
49 | | #include "MagickCore/colorspace.h" |
50 | | #include "MagickCore/colorspace-private.h" |
51 | | #include "MagickCore/exception.h" |
52 | | #include "MagickCore/exception-private.h" |
53 | | #include "MagickCore/image.h" |
54 | | #include "MagickCore/image-private.h" |
55 | | #include "MagickCore/list.h" |
56 | | #include "MagickCore/log.h" |
57 | | #include "MagickCore/magick.h" |
58 | | #include "MagickCore/memory_.h" |
59 | | #include "MagickCore/monitor.h" |
60 | | #include "MagickCore/monitor-private.h" |
61 | | #include "MagickCore/nt-base-private.h" |
62 | | #include "MagickCore/option.h" |
63 | | #include "MagickCore/pixel-accessor.h" |
64 | | #include "MagickCore/quantize.h" |
65 | | #include "MagickCore/quantum-private.h" |
66 | | #include "MagickCore/static.h" |
67 | | #include "MagickCore/string_.h" |
68 | | #include "MagickCore/string-private.h" |
69 | | #include "MagickCore/module.h" |
70 | | |
71 | | /* |
72 | | Define declarations. |
73 | | */ |
74 | 278 | #define IconRgbCompression (size_t) 0 |
75 | 7.25k | #define MaxIcons 1024 |
76 | | |
77 | | /* |
78 | | Typedef declarations. |
79 | | */ |
80 | | typedef 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 | | |
92 | | size_t |
93 | | size, |
94 | | offset; |
95 | | } IconEntry; |
96 | | |
97 | | typedef struct _IconDirectory |
98 | | { |
99 | | size_t |
100 | | count; |
101 | | |
102 | | IconEntry |
103 | | **icons; |
104 | | } IconDirectory; |
105 | | |
106 | | /* |
107 | | Forward declarations. |
108 | | */ |
109 | | static MagickBooleanType |
110 | | WriteICONImage(const ImageInfo *,Image *,ExceptionInfo *); |
111 | | |
112 | | static IconDirectory *RelinquishIconDirectory(IconDirectory *directory) |
113 | 7.52k | { |
114 | 7.52k | ssize_t |
115 | 7.52k | i; |
116 | | |
117 | 7.52k | assert(directory != (IconDirectory *) NULL); |
118 | | |
119 | 7.52k | if (directory->icons != (IconEntry **) NULL) |
120 | 7.51k | { |
121 | 45.0k | for (i=0; i < (ssize_t) directory->count; i++) |
122 | 37.4k | { |
123 | 37.4k | if (directory->icons[i] != (IconEntry *) NULL) |
124 | 37.4k | directory->icons[i]=(IconEntry *) RelinquishMagickMemory( |
125 | 37.4k | directory->icons[i]); |
126 | 37.4k | } |
127 | 7.51k | directory->icons=(IconEntry **) RelinquishMagickMemory(directory->icons); |
128 | 7.51k | } |
129 | 7.52k | directory=(IconDirectory *) RelinquishMagickMemory(directory); |
130 | 7.52k | return(directory); |
131 | 7.52k | } |
132 | | |
133 | | static IconDirectory *AcquireIconDirectory(size_t count) |
134 | 7.52k | { |
135 | 7.52k | IconDirectory |
136 | 7.52k | *directory; |
137 | | |
138 | 7.52k | ssize_t |
139 | 7.52k | i; |
140 | | |
141 | 7.52k | directory=(IconDirectory*) AcquireMagickMemory(sizeof(*directory)); |
142 | 7.52k | if (directory == (IconDirectory*) NULL) |
143 | 0 | return(directory); |
144 | 7.52k | directory->icons=(IconEntry **) AcquireQuantumMemory(count, |
145 | 7.52k | sizeof(*directory->icons)); |
146 | 7.52k | if (directory->icons == (IconEntry **) NULL) |
147 | 3 | return(RelinquishIconDirectory(directory)); |
148 | 7.51k | memset(directory->icons,0,count*sizeof(*directory->icons)); |
149 | 7.51k | directory->count=0; |
150 | 45.0k | for (i=0; i < (ssize_t) count; i++) |
151 | 37.4k | { |
152 | 37.4k | directory->icons[i]=(IconEntry *) AcquireMagickMemory( |
153 | 37.4k | sizeof(**directory->icons)); |
154 | 37.4k | if (directory->icons[i] == (IconEntry *) NULL) |
155 | 0 | return(RelinquishIconDirectory(directory)); |
156 | 37.4k | directory->count++; |
157 | 37.4k | } |
158 | 7.51k | return(directory); |
159 | 7.51k | } |
160 | | |
161 | | /* |
162 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
163 | | % % |
164 | | % % |
165 | | % % |
166 | | % R e a d I C O N I m a g e % |
167 | | % % |
168 | | % % |
169 | | % % |
170 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
171 | | % |
172 | | % ReadICONImage() reads a Microsoft icon image file and returns it. It |
173 | | % allocates the memory necessary for the new Image structure and returns a |
174 | | % pointer to the new image. |
175 | | % |
176 | | % The format of the ReadICONImage method is: |
177 | | % |
178 | | % Image *ReadICONImage(const ImageInfo *image_info, |
179 | | % ExceptionInfo *exception) |
180 | | % |
181 | | % A description of each parameter follows: |
182 | | % |
183 | | % o image_info: the image info. |
184 | | % |
185 | | % o exception: return any errors or warnings in this structure. |
186 | | % |
187 | | */ |
188 | | |
189 | | static Image *Read1XImage(Image *image,ExceptionInfo *exception) |
190 | 92 | { |
191 | 92 | size_t |
192 | 92 | columns, |
193 | 92 | rows; |
194 | | |
195 | 92 | ssize_t |
196 | 92 | i; |
197 | | |
198 | | /* |
199 | | Read Windows 1.0 Icon. |
200 | | */ |
201 | 92 | (void) ReadBlobLSBLong(image); /* hot spot X/Y */ |
202 | 92 | columns=(size_t) ReadBlobLSBShort(image); |
203 | 92 | rows=(size_t) (ReadBlobLSBShort(image)); |
204 | 92 | (void) ReadBlobLSBShort(image); /* width of bitmap in bytes */ |
205 | 92 | (void) ReadBlobLSBShort(image); /* cursor color */ |
206 | 92 | if (((rows != 32) && (rows != 64)) || ((columns != 32) && (columns != 64))) |
207 | 57 | { |
208 | 57 | (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError, |
209 | 57 | "ImproperImageHeader","`%s'",image->filename); |
210 | 57 | return(DestroyImageList(image)); |
211 | 57 | } |
212 | | /* |
213 | | Convert bitmap scanline. |
214 | | */ |
215 | 35 | if (SetImageExtent(image,columns,rows,exception) == MagickFalse) |
216 | 0 | return(DestroyImageList(image)); |
217 | 35 | image->alpha_trait=BlendPixelTrait; |
218 | 35 | if (AcquireImageColormap(image,3,exception) == MagickFalse) |
219 | 0 | return(DestroyImageList(image)); |
220 | 35 | image->colormap[1].alpha=TransparentAlpha; |
221 | 105 | for (i=0; i < 2; i++) |
222 | 70 | { |
223 | 70 | ssize_t |
224 | 70 | y; |
225 | | |
226 | 2.63k | for (y=0; y < (ssize_t) image->columns; y++) |
227 | 2.56k | { |
228 | 2.56k | Quantum |
229 | 2.56k | *q; |
230 | | |
231 | 2.56k | ssize_t |
232 | 2.56k | x; |
233 | | |
234 | 2.56k | q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); |
235 | 2.56k | if (q == (Quantum *) NULL) |
236 | 4 | break; |
237 | 15.8k | for (x=0; x < (ssize_t) (image->columns-7); x+=8) |
238 | 13.3k | { |
239 | 13.3k | size_t |
240 | 13.3k | bit, |
241 | 13.3k | byte; |
242 | | |
243 | 13.3k | byte=(size_t) ReadBlobByte(image); |
244 | 119k | for (bit=0; bit < 8; bit++) |
245 | 106k | { |
246 | 106k | Quantum |
247 | 106k | index; |
248 | | |
249 | 106k | index=(Quantum) ((byte & (0x80 >> bit)) != 0 ? (i == 0 ? 0x01 : 0x02) : 0x00); |
250 | 106k | if (i == 0) |
251 | 53.2k | SetPixelIndex(image,index,q); |
252 | 53.2k | else |
253 | 53.2k | if (GetPixelIndex(image,q) != 0x01) |
254 | 4.29k | SetPixelIndex(image,index,q); |
255 | 106k | q+=(ptrdiff_t) GetPixelChannels(image); |
256 | 106k | } |
257 | 13.3k | } |
258 | 2.56k | if (SyncAuthenticPixels(image,exception) == MagickFalse) |
259 | 0 | break; |
260 | 2.56k | } |
261 | 70 | } |
262 | 35 | if (SyncImage(image,exception) == MagickFalse) |
263 | 0 | return(DestroyImageList(image)); |
264 | 35 | if (CloseBlob(image) == MagickFalse) |
265 | 0 | return(DestroyImageList(image)); |
266 | 35 | return(image); |
267 | 35 | } |
268 | | |
269 | | static inline size_t GetICONSize(size_t directory_size,size_t image_size) |
270 | 3.52k | { |
271 | 3.52k | if (image_size != 0) |
272 | 3.04k | return(image_size); |
273 | 482 | if (directory_size != 0) |
274 | 386 | return(directory_size); |
275 | 96 | return(256); |
276 | 482 | } |
277 | | |
278 | | static Image *ReadICONImage(const ImageInfo *image_info, |
279 | | ExceptionInfo *exception) |
280 | 7.39k | { |
281 | 7.39k | #define ThrowICONReaderException(exception,message) \ |
282 | 27 | { \ |
283 | 27 | directory=RelinquishIconDirectory(directory); \ |
284 | 731 | ThrowReaderException(exception,message) \ |
285 | 731 | } |
286 | | |
287 | 7.39k | IconDirectory |
288 | 7.39k | *directory; |
289 | | |
290 | 7.39k | Image |
291 | 7.39k | *image; |
292 | | |
293 | 7.39k | MagickBooleanType |
294 | 7.39k | status; |
295 | | |
296 | 7.39k | MagickSizeType |
297 | 7.39k | extent; |
298 | | |
299 | 7.39k | Quantum |
300 | 7.39k | *q; |
301 | | |
302 | 7.39k | short |
303 | 7.39k | reserved, |
304 | 7.39k | resource_type; |
305 | | |
306 | 7.39k | size_t |
307 | 7.39k | bit, |
308 | 7.39k | byte, |
309 | 7.39k | bytes_per_line, |
310 | 7.39k | one, |
311 | 7.39k | scanline_pad; |
312 | | |
313 | 7.39k | ssize_t |
314 | 7.39k | i, |
315 | 7.39k | offset, |
316 | 7.39k | x, |
317 | 7.39k | y; |
318 | | |
319 | 7.39k | unsigned char |
320 | 7.39k | *p; |
321 | | |
322 | 7.39k | unsigned short |
323 | 7.39k | icon_count; |
324 | | |
325 | | /* |
326 | | Open image file. |
327 | | */ |
328 | 7.39k | assert(image_info != (const ImageInfo *) NULL); |
329 | 7.39k | assert(image_info->signature == MagickCoreSignature); |
330 | 7.39k | (void) LogMagickEvent(CoderEvent,GetMagickModule(),"%s",image_info->filename); |
331 | 7.39k | assert(exception != (ExceptionInfo *) NULL); |
332 | 7.39k | assert(exception->signature == MagickCoreSignature); |
333 | 7.39k | image=AcquireImage(image_info,exception); |
334 | 7.39k | status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); |
335 | 7.39k | if (status == MagickFalse) |
336 | 0 | { |
337 | 0 | image=DestroyImageList(image); |
338 | 0 | return((Image *) NULL); |
339 | 0 | } |
340 | 7.39k | reserved=(short) ReadBlobLSBShort(image); |
341 | 7.39k | if ((reserved == 0x0001) || (reserved == 0x0101) || (reserved == 0x0201)) |
342 | 92 | return(Read1XImage(image,exception)); |
343 | 7.30k | resource_type=(short) ReadBlobLSBShort(image); |
344 | 7.30k | icon_count=ReadBlobLSBShort(image); |
345 | 7.30k | if ((reserved != 0) || ((resource_type != 1) && (resource_type != 2)) || |
346 | 7.25k | (icon_count > MaxIcons)) |
347 | 7.24k | ThrowReaderException(CorruptImageError,"ImproperImageHeader"); |
348 | 7.24k | directory=AcquireIconDirectory((size_t) icon_count); |
349 | 7.24k | if (directory == (IconDirectory *) NULL) |
350 | 7.24k | ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); |
351 | 7.24k | extent=0; |
352 | 21.2k | for (i=0; i < (ssize_t) directory->count; i++) |
353 | 14.1k | { |
354 | 14.1k | directory->icons[i]->width=(unsigned char) ReadBlobByte(image); |
355 | 14.1k | directory->icons[i]->height=(unsigned char) ReadBlobByte(image); |
356 | 14.1k | directory->icons[i]->colors=(unsigned char) ReadBlobByte(image); |
357 | 14.1k | directory->icons[i]->reserved=(unsigned char) ReadBlobByte(image); |
358 | 14.1k | directory->icons[i]->planes=(unsigned short) ReadBlobLSBShort(image); |
359 | 14.1k | directory->icons[i]->bits_per_pixel=(unsigned short) |
360 | 14.1k | ReadBlobLSBShort(image); |
361 | 14.1k | directory->icons[i]->size=ReadBlobLSBLong(image); |
362 | 14.1k | directory->icons[i]->offset=ReadBlobLSBLong(image); |
363 | 14.1k | if (EOFBlob(image) != MagickFalse) |
364 | 95 | break; |
365 | 14.0k | extent=MagickMax(extent,directory->icons[i]->size); |
366 | 14.0k | } |
367 | 7.24k | if ((EOFBlob(image) != MagickFalse) || (extent > GetBlobSize(image))) |
368 | 7.08k | ThrowICONReaderException(CorruptImageError,"UnexpectedEndOfFile"); |
369 | 7.08k | one=1; |
370 | 12.0k | for (i=0; i < (ssize_t) directory->count; i++) |
371 | 10.6k | { |
372 | 10.6k | size_t |
373 | 10.6k | size; |
374 | | |
375 | 10.6k | ssize_t |
376 | 10.6k | count, |
377 | 10.6k | height, |
378 | 10.6k | width; |
379 | | |
380 | 10.6k | unsigned short |
381 | 10.6k | bits_per_pixel, |
382 | 10.6k | planes; |
383 | | |
384 | | /* |
385 | | Verify Icon identifier. |
386 | | */ |
387 | 10.6k | offset=(ssize_t) SeekBlob(image,(MagickOffsetType) |
388 | 10.6k | directory->icons[i]->offset,SEEK_SET); |
389 | 10.6k | if (offset < 0) |
390 | 10.6k | ThrowICONReaderException(CorruptImageError,"ImproperImageHeader"); |
391 | 10.6k | size=ReadBlobLSBLong(image); |
392 | 10.6k | width=ReadBlobLSBSignedLong(image); |
393 | 10.6k | height=(ReadBlobLSBSignedLong(image)/2); |
394 | 10.6k | planes=ReadBlobLSBShort(image); |
395 | 10.6k | bits_per_pixel=ReadBlobLSBShort(image); |
396 | 10.6k | if (EOFBlob(image) != MagickFalse) |
397 | 374 | { |
398 | 374 | ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", |
399 | 374 | image->filename); |
400 | 374 | break; |
401 | 374 | } |
402 | 10.2k | if (((planes == 18505) && (bits_per_pixel == 21060)) || |
403 | 2.73k | (size == 0x474e5089)) |
404 | 8.16k | { |
405 | 8.16k | Image |
406 | 8.16k | *icon_image; |
407 | | |
408 | 8.16k | ImageInfo |
409 | 8.16k | *read_info; |
410 | | |
411 | 8.16k | size_t |
412 | 8.16k | length; |
413 | | |
414 | 8.16k | unsigned char |
415 | 8.16k | *png; |
416 | | |
417 | | /* |
418 | | Icon image encoded as a compressed PNG image. |
419 | | */ |
420 | 8.16k | length=directory->icons[i]->size; |
421 | 8.16k | if ((length < 16) || (~length < 16)) |
422 | 8.13k | ThrowICONReaderException(ResourceLimitError,"MemoryAllocationFailed"); |
423 | 8.13k | png=(unsigned char *) AcquireQuantumMemory(length,sizeof(*png)); |
424 | 8.13k | if (png == (unsigned char *) NULL) |
425 | 8.13k | ThrowICONReaderException(ResourceLimitError,"MemoryAllocationFailed"); |
426 | 8.13k | (void) memcpy(png,"\211PNG\r\n\032\n\000\000\000\015",12); |
427 | 8.13k | png[12]=(unsigned char) planes; |
428 | 8.13k | png[13]=(unsigned char) (planes >> 8); |
429 | 8.13k | png[14]=(unsigned char) bits_per_pixel; |
430 | 8.13k | png[15]=(unsigned char) (bits_per_pixel >> 8); |
431 | 8.13k | count=ReadBlob(image,length-16,png+16); |
432 | 8.13k | if (count != (ssize_t) (length-16)) |
433 | 74 | { |
434 | 74 | png=(unsigned char *) RelinquishMagickMemory(png); |
435 | 74 | ThrowICONReaderException(CorruptImageError, |
436 | 74 | "InsufficientImageDataInFile"); |
437 | 0 | } |
438 | 8.05k | read_info=CloneImageInfo(image_info); |
439 | 8.05k | (void) CopyMagickString(read_info->magick,"PNG",MagickPathExtent); |
440 | 8.05k | icon_image=BlobToImage(read_info,png,length,exception); |
441 | 8.05k | read_info=DestroyImageInfo(read_info); |
442 | 8.05k | png=(unsigned char *) RelinquishMagickMemory(png); |
443 | 8.05k | if (icon_image == (Image *) NULL) |
444 | 4.17k | { |
445 | 4.17k | directory=RelinquishIconDirectory(directory); |
446 | 4.17k | return(DestroyImageList(image)); |
447 | 4.17k | } |
448 | 3.88k | DestroyBlob(icon_image); |
449 | 3.88k | icon_image->blob=ReferenceBlob(image->blob); |
450 | 3.88k | ReplaceImageInList(&image,icon_image); |
451 | 3.88k | icon_image->scene=(size_t) i; |
452 | 3.88k | } |
453 | 2.09k | else |
454 | 2.09k | { |
455 | 2.09k | size_t |
456 | 2.09k | number_colors; |
457 | | |
458 | 2.09k | if (bits_per_pixel > 32) |
459 | 1.81k | ThrowICONReaderException(CorruptImageError,"ImproperImageHeader"); |
460 | 1.81k | (void) ReadBlobLSBLong(image); /* compression */ |
461 | 1.81k | (void) ReadBlobLSBLong(image); /* image_size */ |
462 | 1.81k | (void) ReadBlobLSBLong(image); /* x_pixels */ |
463 | 1.81k | (void) ReadBlobLSBLong(image); /* y_pixels */ |
464 | 1.81k | number_colors=ReadBlobLSBLong(image); |
465 | 1.81k | if (number_colors > GetBlobSize(image)) |
466 | 48 | ThrowICONReaderException(CorruptImageError, |
467 | 1.81k | "InsufficientImageDataInFile"); |
468 | 1.76k | (void) ReadBlobLSBLong(image); /* colors_important */ |
469 | 1.76k | image->alpha_trait=BlendPixelTrait; |
470 | 1.76k | image->columns=(size_t) GetICONSize( directory->icons[i]->width, |
471 | 1.76k | (size_t) width); |
472 | 1.76k | image->rows=(size_t) GetICONSize(directory->icons[i]->height, |
473 | 1.76k | (size_t) height); |
474 | 1.76k | image->depth=bits_per_pixel; |
475 | 1.76k | if (image->depth > 16) |
476 | 682 | image->depth=8; |
477 | 1.76k | if (image->debug != MagickFalse) |
478 | 0 | { |
479 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
480 | 0 | " scene = %.20g",(double) i); |
481 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
482 | 0 | " size = %.20g",(double) size); |
483 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
484 | 0 | " width = %.20g",(double) image->columns); |
485 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
486 | 0 | " height = %.20g",(double) image->rows); |
487 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
488 | 0 | " colors = %.20g",(double ) number_colors); |
489 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
490 | 0 | " planes = %.20g",(double) planes); |
491 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
492 | 0 | " bpp = %.20g",(double) bits_per_pixel); |
493 | 0 | } |
494 | 1.76k | if ((number_colors != 0) || (bits_per_pixel <= 16U)) |
495 | 1.24k | { |
496 | 1.24k | image->storage_class=PseudoClass; |
497 | 1.24k | image->colors=number_colors; |
498 | 1.24k | if ((image->colors == 0) || (image->colors > 256)) |
499 | 660 | image->colors=one << bits_per_pixel; |
500 | 1.24k | } |
501 | 1.76k | if (image->storage_class == PseudoClass) |
502 | 1.24k | { |
503 | 1.24k | ssize_t |
504 | 1.24k | j; |
505 | | |
506 | 1.24k | unsigned char |
507 | 1.24k | *icon_colormap; |
508 | | |
509 | | /* |
510 | | Read Icon raster colormap. |
511 | | */ |
512 | 1.24k | if (image->colors > GetBlobSize(image)) |
513 | 33 | ThrowICONReaderException(CorruptImageError, |
514 | 1.24k | "InsufficientImageDataInFile"); |
515 | 1.21k | if (AcquireImageColormap(image,image->colors,exception) == MagickFalse) |
516 | 0 | ThrowICONReaderException(ResourceLimitError, |
517 | 1.21k | "MemoryAllocationFailed"); |
518 | 1.21k | icon_colormap=(unsigned char *) AcquireQuantumMemory((size_t) |
519 | 1.21k | image->colors,4UL*sizeof(*icon_colormap)); |
520 | 1.21k | if (icon_colormap == (unsigned char *) NULL) |
521 | 0 | ThrowICONReaderException(ResourceLimitError, |
522 | 1.21k | "MemoryAllocationFailed"); |
523 | 1.21k | count=ReadBlob(image,(size_t) (4*image->colors),icon_colormap); |
524 | 1.21k | if (count != (ssize_t) (4*image->colors)) |
525 | 74 | { |
526 | 74 | icon_colormap=(unsigned char *) RelinquishMagickMemory( |
527 | 74 | icon_colormap); |
528 | 74 | ThrowICONReaderException(CorruptImageError, |
529 | 74 | "InsufficientImageDataInFile"); |
530 | 0 | } |
531 | 1.14k | p=icon_colormap; |
532 | 7.08k | for (j=0; j < (ssize_t) image->colors; j++) |
533 | 5.94k | { |
534 | 5.94k | image->colormap[j].blue=(Quantum) ScaleCharToQuantum(*p++); |
535 | 5.94k | image->colormap[j].green=(Quantum) ScaleCharToQuantum(*p++); |
536 | 5.94k | image->colormap[j].red=(Quantum) ScaleCharToQuantum(*p++); |
537 | 5.94k | p++; |
538 | 5.94k | } |
539 | 1.14k | icon_colormap=(unsigned char *) RelinquishMagickMemory(icon_colormap); |
540 | 1.14k | } |
541 | | /* |
542 | | Convert Icon raster image to pixel packets. |
543 | | */ |
544 | 1.65k | if ((image_info->ping != MagickFalse) && |
545 | 0 | (image_info->number_scenes != 0)) |
546 | 0 | if (image->scene >= (image_info->scene+image_info->number_scenes-1)) |
547 | 0 | break; |
548 | 1.65k | status=SetImageExtent(image,image->columns,image->rows,exception); |
549 | 1.65k | if (status == MagickFalse) |
550 | 219 | { |
551 | 219 | directory=RelinquishIconDirectory(directory); |
552 | 219 | return(DestroyImageList(image)); |
553 | 219 | } |
554 | 1.43k | bytes_per_line=(((image->columns*bits_per_pixel)+31U) & ~31U) >> 3; |
555 | 1.43k | (void) bytes_per_line; |
556 | 1.43k | scanline_pad=((((image->columns*bits_per_pixel)+31U) & ~31U)- |
557 | 1.43k | (image->columns*bits_per_pixel)) >> 3; |
558 | 1.43k | switch (bits_per_pixel) |
559 | 1.43k | { |
560 | 589 | case 1: |
561 | 589 | { |
562 | | /* |
563 | | Convert bitmap scanline. |
564 | | */ |
565 | 39.3k | for (y=(ssize_t) image->rows-1; y >= 0; y--) |
566 | 38.8k | { |
567 | 38.8k | q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); |
568 | 38.8k | if (q == (Quantum *) NULL) |
569 | 0 | break; |
570 | 1.66M | for (x=0; x < (ssize_t) (image->columns-7); x+=8) |
571 | 1.62M | { |
572 | 1.62M | byte=(size_t) ReadBlobByte(image); |
573 | 14.6M | for (bit=0; bit < 8; bit++) |
574 | 12.9M | { |
575 | 12.9M | SetPixelIndex(image,(Quantum) ((byte & (0x80 >> bit)) != 0 ? |
576 | 12.6M | 0x01 : 0x00),q); |
577 | 12.9M | q+=(ptrdiff_t) GetPixelChannels(image); |
578 | 12.9M | } |
579 | 1.62M | } |
580 | 38.8k | if ((image->columns % 8) != 0) |
581 | 33.7k | { |
582 | 33.7k | byte=(size_t) ReadBlobByte(image); |
583 | 120k | for (bit=0; bit < (image->columns % 8); bit++) |
584 | 86.9k | { |
585 | 86.9k | SetPixelIndex(image,(Quantum) ((byte & (0x80 >> bit)) != 0 ? |
586 | 50.8k | 0x01 : 0x00),q); |
587 | 86.9k | q+=(ptrdiff_t) GetPixelChannels(image); |
588 | 86.9k | } |
589 | 33.7k | } |
590 | 102k | for (x=0; x < (ssize_t) scanline_pad; x++) |
591 | 63.3k | (void) ReadBlobByte(image); |
592 | 38.8k | if (SyncAuthenticPixels(image,exception) == MagickFalse) |
593 | 0 | break; |
594 | 38.8k | if (image->previous == (Image *) NULL) |
595 | 21.7k | { |
596 | 21.7k | status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) |
597 | 21.7k | image->rows-y-1,(MagickSizeType) image->rows); |
598 | 21.7k | if (status == MagickFalse) |
599 | 0 | break; |
600 | 21.7k | } |
601 | 38.8k | } |
602 | 589 | break; |
603 | 0 | } |
604 | 178 | case 4: |
605 | 178 | { |
606 | | /* |
607 | | Read 4-bit Icon scanline. |
608 | | */ |
609 | 40.8k | for (y=(ssize_t) image->rows-1; y >= 0; y--) |
610 | 40.6k | { |
611 | 40.6k | q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); |
612 | 40.6k | if (q == (Quantum *) NULL) |
613 | 0 | break; |
614 | 23.5M | for (x=0; x < ((ssize_t) image->columns-1); x+=2) |
615 | 23.5M | { |
616 | 23.5M | byte=(size_t) ReadBlobByte(image); |
617 | 23.5M | SetPixelIndex(image,(Quantum) ((byte >> 4) & 0xf),q); |
618 | 23.5M | q+=(ptrdiff_t) GetPixelChannels(image); |
619 | 23.5M | SetPixelIndex(image,(Quantum) ((byte) & 0xf),q); |
620 | 23.5M | q+=(ptrdiff_t) GetPixelChannels(image); |
621 | 23.5M | } |
622 | 40.6k | if ((image->columns % 2) != 0) |
623 | 29.3k | { |
624 | 29.3k | byte=(size_t) ReadBlobByte(image); |
625 | 29.3k | SetPixelIndex(image,(Quantum) ((byte >> 4) & 0xf),q); |
626 | 29.3k | q+=(ptrdiff_t) GetPixelChannels(image); |
627 | 29.3k | } |
628 | 94.8k | for (x=0; x < (ssize_t) scanline_pad; x++) |
629 | 54.1k | (void) ReadBlobByte(image); |
630 | 40.6k | if (SyncAuthenticPixels(image,exception) == MagickFalse) |
631 | 0 | break; |
632 | 40.6k | if (image->previous == (Image *) NULL) |
633 | 39.7k | { |
634 | 39.7k | status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) |
635 | 39.7k | image->rows-y-1,(MagickSizeType) image->rows); |
636 | 39.7k | if (status == MagickFalse) |
637 | 0 | break; |
638 | 39.7k | } |
639 | 40.6k | } |
640 | 178 | break; |
641 | 0 | } |
642 | 58 | case 8: |
643 | 58 | { |
644 | | /* |
645 | | Convert PseudoColor scanline. |
646 | | */ |
647 | 15.5k | for (y=(ssize_t) image->rows-1; y >= 0; y--) |
648 | 15.5k | { |
649 | 15.5k | q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); |
650 | 15.5k | if (q == (Quantum *) NULL) |
651 | 0 | break; |
652 | 7.98M | for (x=0; x < (ssize_t) image->columns; x++) |
653 | 7.96M | { |
654 | 7.96M | byte=(size_t) ReadBlobByte(image); |
655 | 7.96M | SetPixelIndex(image,(Quantum) byte,q); |
656 | 7.96M | q+=(ptrdiff_t) GetPixelChannels(image); |
657 | 7.96M | } |
658 | 52.9k | for (x=0; x < (ssize_t) scanline_pad; x++) |
659 | 37.3k | (void) ReadBlobByte(image); |
660 | 15.5k | if (SyncAuthenticPixels(image,exception) == MagickFalse) |
661 | 0 | break; |
662 | 15.5k | if (image->previous == (Image *) NULL) |
663 | 15.1k | { |
664 | 15.1k | status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) |
665 | 15.1k | image->rows-y-1,(MagickSizeType) image->rows); |
666 | 15.1k | if (status == MagickFalse) |
667 | 0 | break; |
668 | 15.1k | } |
669 | 15.5k | } |
670 | 58 | break; |
671 | 0 | } |
672 | 82 | case 16: |
673 | 82 | { |
674 | | /* |
675 | | Convert PseudoColor scanline. |
676 | | */ |
677 | 10.3k | for (y=(ssize_t) image->rows-1; y >= 0; y--) |
678 | 10.2k | { |
679 | 10.2k | q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); |
680 | 10.2k | if (q == (Quantum *) NULL) |
681 | 0 | break; |
682 | 6.78M | for (x=0; x < (ssize_t) image->columns; x++) |
683 | 6.77M | { |
684 | 6.77M | byte=(size_t) ReadBlobByte(image); |
685 | 6.77M | byte|=((size_t) ReadBlobByte(image) << 8); |
686 | 6.77M | SetPixelIndex(image,(Quantum) byte,q); |
687 | 6.77M | q+=(ptrdiff_t) GetPixelChannels(image); |
688 | 6.77M | } |
689 | 24.8k | for (x=0; x < (ssize_t) scanline_pad; x++) |
690 | 14.5k | (void) ReadBlobByte(image); |
691 | 10.2k | if (SyncAuthenticPixels(image,exception) == MagickFalse) |
692 | 0 | break; |
693 | 10.2k | if (image->previous == (Image *) NULL) |
694 | 9.71k | { |
695 | 9.71k | status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) |
696 | 9.71k | image->rows-y-1,(MagickSizeType) image->rows); |
697 | 9.71k | if (status == MagickFalse) |
698 | 0 | break; |
699 | 9.71k | } |
700 | 10.2k | } |
701 | 82 | break; |
702 | 0 | } |
703 | 180 | case 24: |
704 | 504 | case 32: |
705 | 504 | { |
706 | | /* |
707 | | Convert DirectColor scanline. |
708 | | */ |
709 | 70.5k | for (y=(ssize_t) image->rows-1; y >= 0; y--) |
710 | 70.0k | { |
711 | 70.0k | q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); |
712 | 70.0k | if (q == (Quantum *) NULL) |
713 | 0 | break; |
714 | 44.7M | for (x=0; x < (ssize_t) image->columns; x++) |
715 | 44.6M | { |
716 | 44.6M | SetPixelBlue(image,ScaleCharToQuantum((unsigned char) |
717 | 44.6M | ReadBlobByte(image)),q); |
718 | 44.6M | SetPixelGreen(image,ScaleCharToQuantum((unsigned char) |
719 | 44.6M | ReadBlobByte(image)),q); |
720 | 44.6M | SetPixelRed(image,ScaleCharToQuantum((unsigned char) |
721 | 44.6M | ReadBlobByte(image)),q); |
722 | 44.6M | if (bits_per_pixel == 32) |
723 | 6.73M | SetPixelAlpha(image,ScaleCharToQuantum((unsigned char) |
724 | 6.73M | ReadBlobByte(image)),q); |
725 | 44.6M | q+=(ptrdiff_t) GetPixelChannels(image); |
726 | 44.6M | } |
727 | 70.0k | if (bits_per_pixel == 24) |
728 | 150k | for (x=0; x < (ssize_t) scanline_pad; x++) |
729 | 90.9k | (void) ReadBlobByte(image); |
730 | 70.0k | if (SyncAuthenticPixels(image,exception) == MagickFalse) |
731 | 0 | break; |
732 | 70.0k | if (image->previous == (Image *) NULL) |
733 | 69.3k | { |
734 | 69.3k | status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) |
735 | 69.3k | image->rows-y-1,(MagickSizeType) image->rows); |
736 | 69.3k | if (status == MagickFalse) |
737 | 0 | break; |
738 | 69.3k | } |
739 | 70.0k | } |
740 | 504 | break; |
741 | 180 | } |
742 | 27 | default: |
743 | 27 | ThrowICONReaderException(CorruptImageError,"ImproperImageHeader"); |
744 | 1.43k | } |
745 | 1.41k | if ((image_info->ping == MagickFalse) && (bits_per_pixel <= 16)) |
746 | 907 | (void) SyncImage(image,exception); |
747 | 1.41k | if (bits_per_pixel != 32) |
748 | 1.08k | { |
749 | | /* |
750 | | Read the ICON alpha mask. |
751 | | */ |
752 | 1.08k | image->storage_class=DirectClass; |
753 | 165k | for (y=(ssize_t) image->rows-1; y >= 0; y--) |
754 | 164k | { |
755 | 164k | q=GetAuthenticPixels(image,0,y,image->columns,1,exception); |
756 | 164k | if (q == (Quantum *) NULL) |
757 | 0 | break; |
758 | 14.2M | for (x=0; x < ((ssize_t) image->columns-7); x+=8) |
759 | 14.0M | { |
760 | 14.0M | byte=(size_t) ReadBlobByte(image); |
761 | 126M | for (bit=0; bit < 8; bit++) |
762 | 112M | { |
763 | 112M | SetPixelAlpha(image,(((byte & (0x80 >> bit)) != 0) ? |
764 | 111M | TransparentAlpha : OpaqueAlpha),q); |
765 | 112M | q+=(ptrdiff_t) GetPixelChannels(image); |
766 | 112M | } |
767 | 14.0M | } |
768 | 164k | if ((image->columns % 8) != 0) |
769 | 143k | { |
770 | 143k | byte=(size_t) ReadBlobByte(image); |
771 | 653k | for (bit=0; bit < (image->columns % 8); bit++) |
772 | 509k | { |
773 | 509k | SetPixelAlpha(image,(((byte & (0x80 >> bit)) != 0) ? |
774 | 472k | TransparentAlpha : OpaqueAlpha),q); |
775 | 509k | q+=(ptrdiff_t) GetPixelChannels(image); |
776 | 509k | } |
777 | 143k | } |
778 | 164k | if ((image->columns % 32) != 0) |
779 | 421k | for (x=0; x < (ssize_t) ((32-(image->columns % 32))/8); x++) |
780 | 266k | (void) ReadBlobByte(image); |
781 | 164k | if (SyncAuthenticPixels(image,exception) == MagickFalse) |
782 | 0 | break; |
783 | 164k | } |
784 | 1.08k | } |
785 | 1.41k | if (EOFBlob(image) != MagickFalse) |
786 | 327 | { |
787 | 327 | ThrowFileException(exception,CorruptImageError, |
788 | 327 | "UnexpectedEndOfFile",image->filename); |
789 | 327 | break; |
790 | 327 | } |
791 | 1.41k | } |
792 | | /* |
793 | | Proceed to next image. |
794 | | */ |
795 | 4.96k | if (image_info->number_scenes != 0) |
796 | 0 | if (image->scene >= (image_info->scene+image_info->number_scenes-1)) |
797 | 0 | break; |
798 | 4.96k | if (i < ((ssize_t) directory->count-1)) |
799 | 3.55k | { |
800 | | /* |
801 | | Allocate next image structure. |
802 | | */ |
803 | 3.55k | AcquireNextImage(image_info,image,exception); |
804 | 3.55k | if (GetNextImageInList(image) == (Image *) NULL) |
805 | 0 | { |
806 | 0 | status=MagickFalse; |
807 | 0 | break; |
808 | 0 | } |
809 | 3.55k | image=SyncNextImageInList(image); |
810 | 3.55k | status=SetImageProgress(image,LoadImagesTag,TellBlob(image), |
811 | 3.55k | GetBlobSize(image)); |
812 | 3.55k | if (status == MagickFalse) |
813 | 0 | break; |
814 | 3.55k | } |
815 | 4.96k | } |
816 | 2.12k | directory=RelinquishIconDirectory(directory); |
817 | 2.12k | (void) CloseBlob(image); |
818 | 2.12k | if (status == MagickFalse) |
819 | 0 | return(DestroyImageList(image)); |
820 | 2.12k | return(GetFirstImageInList(image)); |
821 | 2.12k | } |
822 | | |
823 | | /* |
824 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
825 | | % % |
826 | | % % |
827 | | % % |
828 | | % R e g i s t e r I C O N I m a g e % |
829 | | % % |
830 | | % % |
831 | | % % |
832 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
833 | | % |
834 | | % RegisterICONImage() adds attributes for the Icon image format to |
835 | | % the list of supported formats. The attributes include the image format |
836 | | % tag, a method to read and/or write the format, whether the format |
837 | | % supports the saving of more than one frame to the same file or blob, |
838 | | % whether the format supports native in-memory I/O, and a brief |
839 | | % description of the format. |
840 | | % |
841 | | % The format of the RegisterICONImage method is: |
842 | | % |
843 | | % size_t RegisterICONImage(void) |
844 | | % |
845 | | */ |
846 | | ModuleExport size_t RegisterICONImage(void) |
847 | 8 | { |
848 | 8 | MagickInfo |
849 | 8 | *entry; |
850 | | |
851 | 8 | entry=AcquireMagickInfo("ICON","CUR","Microsoft icon"); |
852 | 8 | entry->decoder=(DecodeImageHandler *) ReadICONImage; |
853 | 8 | entry->encoder=(EncodeImageHandler *) WriteICONImage; |
854 | 8 | entry->flags^=CoderAdjoinFlag; |
855 | 8 | entry->flags|=CoderDecoderSeekableStreamFlag; |
856 | 8 | entry->flags|=CoderEncoderSeekableStreamFlag; |
857 | 8 | (void) RegisterMagickInfo(entry); |
858 | 8 | entry=AcquireMagickInfo("ICON","ICO","Microsoft icon"); |
859 | 8 | entry->decoder=(DecodeImageHandler *) ReadICONImage; |
860 | 8 | entry->encoder=(EncodeImageHandler *) WriteICONImage; |
861 | 8 | entry->flags|=CoderDecoderSeekableStreamFlag; |
862 | 8 | entry->flags|=CoderEncoderSeekableStreamFlag; |
863 | 8 | (void) RegisterMagickInfo(entry); |
864 | 8 | entry=AcquireMagickInfo("ICON","ICN","Microsoft icon"); |
865 | 8 | entry->decoder=(DecodeImageHandler *) ReadICONImage; |
866 | 8 | entry->encoder=(EncodeImageHandler *) WriteICONImage; |
867 | 8 | entry->flags ^= CoderAdjoinFlag; |
868 | 8 | entry->flags|=CoderDecoderSeekableStreamFlag; |
869 | 8 | entry->flags|=CoderEncoderSeekableStreamFlag; |
870 | 8 | (void) RegisterMagickInfo(entry); |
871 | 8 | entry=AcquireMagickInfo("ICON","ICON","Microsoft icon"); |
872 | 8 | entry->decoder=(DecodeImageHandler *) ReadICONImage; |
873 | 8 | entry->encoder=(EncodeImageHandler *) WriteICONImage; |
874 | 8 | entry->flags^=CoderAdjoinFlag; |
875 | 8 | entry->flags|=CoderDecoderSeekableStreamFlag; |
876 | 8 | entry->flags|=CoderEncoderSeekableStreamFlag; |
877 | 8 | (void) RegisterMagickInfo(entry); |
878 | 8 | return(MagickImageCoderSignature); |
879 | 8 | } |
880 | | |
881 | | /* |
882 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
883 | | % % |
884 | | % % |
885 | | % % |
886 | | % U n r e g i s t e r I C O N I m a g e % |
887 | | % % |
888 | | % % |
889 | | % % |
890 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
891 | | % |
892 | | % UnregisterICONImage() removes format registrations made by the |
893 | | % ICON module from the list of supported formats. |
894 | | % |
895 | | % The format of the UnregisterICONImage method is: |
896 | | % |
897 | | % UnregisterICONImage(void) |
898 | | % |
899 | | */ |
900 | | ModuleExport void UnregisterICONImage(void) |
901 | 0 | { |
902 | 0 | (void) UnregisterMagickInfo("CUR"); |
903 | 0 | (void) UnregisterMagickInfo("ICO"); |
904 | 0 | (void) UnregisterMagickInfo("ICON"); |
905 | 0 | } |
906 | | |
907 | | /* |
908 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
909 | | % % |
910 | | % % |
911 | | % % |
912 | | % W r i t e I C O N I m a g e % |
913 | | % % |
914 | | % % |
915 | | % % |
916 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
917 | | % |
918 | | % WriteICONImage() writes an image in Microsoft Windows bitmap encoded |
919 | | % image format, version 3 for Windows or (if the image has a matte channel) |
920 | | % version 4. |
921 | | % |
922 | | % It encodes any subimage as a compressed PNG image ("BI_PNG)", only when its |
923 | | % dimensions are larger than 256x256 and image->compression is undefined or |
924 | | % is defined as ZipCompression. |
925 | | % |
926 | | % The format of the WriteICONImage method is: |
927 | | % |
928 | | % MagickBooleanType WriteICONImage(const ImageInfo *image_info, |
929 | | % Image *image,ExceptionInfo *exception) |
930 | | % |
931 | | % A description of each parameter follows. |
932 | | % |
933 | | % o image_info: the image info. |
934 | | % |
935 | | % o image: The image. |
936 | | % |
937 | | % o exception: return any errors or warnings in this structure. |
938 | | % |
939 | | */ |
940 | | |
941 | | static Image *AutoResizeImage(const Image *image,const char *option, |
942 | | MagickOffsetType *count,ExceptionInfo *exception) |
943 | 0 | { |
944 | 0 | #define MAX_SIZES 16 |
945 | |
|
946 | 0 | char |
947 | 0 | *q; |
948 | |
|
949 | 0 | const char |
950 | 0 | *p; |
951 | |
|
952 | 0 | Image |
953 | 0 | *images, |
954 | 0 | *resized; |
955 | |
|
956 | 0 | size_t |
957 | 0 | sizes[MAX_SIZES] = { 256, 192, 128, 96, 64, 48, 40, 32, 24, 16 }; |
958 | |
|
959 | 0 | ssize_t |
960 | 0 | i; |
961 | |
|
962 | 0 | images=NULL; |
963 | 0 | *count=0; |
964 | 0 | i=0; |
965 | 0 | p=option; |
966 | 0 | while ((*p != '\0') && (i < MAX_SIZES)) |
967 | 0 | { |
968 | 0 | size_t |
969 | 0 | size; |
970 | |
|
971 | 0 | while ((isspace((int) ((unsigned char) *p)) != 0)) |
972 | 0 | p++; |
973 | 0 | size=(size_t) strtol(p,&q,10); |
974 | 0 | if ((p == q) || (size < 16) || (size > 512)) |
975 | 0 | return((Image *) NULL); |
976 | 0 | p=q; |
977 | 0 | sizes[i++]=size; |
978 | 0 | while ((isspace((int) ((unsigned char) *p)) != 0) || (*p == ',')) |
979 | 0 | p++; |
980 | 0 | } |
981 | 0 | if (i == 0) |
982 | 0 | i=10; /* the number of sizes when they are not specified by the user */ |
983 | 0 | *count=i; |
984 | 0 | for (i=0; i < *count; i++) |
985 | 0 | { |
986 | 0 | resized=ResizeImage(image,sizes[i],sizes[i],image->filter,exception); |
987 | 0 | if (resized == (Image *) NULL) |
988 | 0 | return(DestroyImageList(images)); |
989 | 0 | if (images == (Image *) NULL) |
990 | 0 | images=resized; |
991 | 0 | else |
992 | 0 | AppendImageToList(&images,resized); |
993 | 0 | } |
994 | 0 | return(images); |
995 | 0 | } |
996 | | |
997 | | static inline MagickBooleanType ShouldCompressAsPng(const Image* image, |
998 | | const size_t png_size) |
999 | 278 | { |
1000 | 278 | if ((png_size != 0) && (image->columns >= png_size) && |
1001 | 0 | (image->rows >= png_size)) |
1002 | 0 | return(MagickTrue); |
1003 | 278 | if ((image->columns > 256L) && (image->rows > 256L) && |
1004 | 0 | ((image->compression == UndefinedCompression) || |
1005 | 0 | (image->compression == ZipCompression))) |
1006 | 0 | return(MagickTrue); |
1007 | 278 | return(MagickFalse); |
1008 | 278 | } |
1009 | | |
1010 | | static MagickBooleanType WriteICONImage(const ImageInfo *image_info, |
1011 | | Image *image,ExceptionInfo *exception) |
1012 | 280 | { |
1013 | 280 | #define ThrowICONWriterException(exception,message) \ |
1014 | 0 | { \ |
1015 | 0 | directory=RelinquishIconDirectory(directory); \ |
1016 | 0 | images=DestroyImageList(images); \ |
1017 | 0 | ThrowWriterException(exception,message) \ |
1018 | 0 | } |
1019 | | |
1020 | 280 | const char |
1021 | 280 | *option; |
1022 | | |
1023 | 280 | const Quantum |
1024 | 280 | *p; |
1025 | | |
1026 | 280 | IconDirectory |
1027 | 280 | *directory; |
1028 | | |
1029 | 280 | Image |
1030 | 280 | *images, |
1031 | 280 | *frame; |
1032 | | |
1033 | 280 | MagickBooleanType |
1034 | 280 | adjoin, |
1035 | 280 | status; |
1036 | | |
1037 | 280 | MagickOffsetType |
1038 | 280 | offset, |
1039 | 280 | scene; |
1040 | | |
1041 | 280 | size_t |
1042 | 280 | bytes_per_line, |
1043 | 280 | number_scenes, |
1044 | 280 | png_size, |
1045 | 280 | scanline_pad; |
1046 | | |
1047 | 280 | ssize_t |
1048 | 280 | i, |
1049 | 280 | x, |
1050 | 280 | y; |
1051 | | |
1052 | 280 | unsigned char |
1053 | 280 | *pixels, |
1054 | 280 | *q; |
1055 | | |
1056 | | /* |
1057 | | Open output image file. |
1058 | | */ |
1059 | 280 | assert(image_info != (const ImageInfo *) NULL); |
1060 | 280 | assert(image_info->signature == MagickCoreSignature); |
1061 | 280 | assert(image != (Image *) NULL); |
1062 | 280 | assert(image->signature == MagickCoreSignature); |
1063 | 280 | (void) LogMagickEvent(CoderEvent,GetMagickModule(),"%s",image->filename); |
1064 | 280 | assert(exception != (ExceptionInfo *) NULL); |
1065 | 280 | assert(exception->signature == MagickCoreSignature); |
1066 | 280 | status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); |
1067 | 280 | if (status == MagickFalse) |
1068 | 0 | return(status); |
1069 | 280 | images=(Image *) NULL; |
1070 | 280 | adjoin=image_info->adjoin; |
1071 | 280 | option=GetImageOption(image_info,"icon:auto-resize"); |
1072 | 280 | if (option != (const char *) NULL) |
1073 | 0 | { |
1074 | 0 | images=AutoResizeImage(image,option,&scene,exception); |
1075 | 0 | if (images == (Image *) NULL) |
1076 | 0 | ThrowWriterException(ImageError,"InvalidDimensions"); |
1077 | 0 | adjoin=MagickTrue; |
1078 | 0 | } |
1079 | 280 | else |
1080 | 280 | { |
1081 | 280 | scene=0; |
1082 | 280 | frame=image; |
1083 | 280 | do |
1084 | 280 | { |
1085 | 280 | if ((image->columns > 512L) || (image->rows > 512L)) |
1086 | 278 | ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit"); |
1087 | 278 | scene++; |
1088 | 278 | frame=SyncNextImageInList(frame); |
1089 | 278 | } while ((frame != (Image *) NULL) && (adjoin != MagickFalse)); |
1090 | 280 | } |
1091 | | /* |
1092 | | Dump out a ICON header template to be properly initialized later. |
1093 | | */ |
1094 | 278 | (void) WriteBlobLSBShort(image,0); |
1095 | 278 | (void) WriteBlobLSBShort(image,1); |
1096 | 278 | (void) WriteBlobLSBShort(image,(unsigned char) scene); |
1097 | 278 | frame=(images != (Image *) NULL) ? images : image; |
1098 | 278 | number_scenes=0; |
1099 | 278 | do |
1100 | 278 | { |
1101 | 278 | number_scenes++; |
1102 | 278 | (void) WriteBlobByte(image,0); /* width */ |
1103 | 278 | (void) WriteBlobByte(image,0); /* height */ |
1104 | 278 | (void) WriteBlobByte(image,0); /* colors */ |
1105 | 278 | (void) WriteBlobByte(image,0); /* reserved */ |
1106 | 278 | (void) WriteBlobLSBShort(image,0); /* planes */ |
1107 | 278 | (void) WriteBlobLSBShort(image,0); /* bits_per_pixel */ |
1108 | 278 | (void) WriteBlobLSBLong(image,0); /* size */ |
1109 | 278 | (void) WriteBlobLSBLong(image,0); /* offset */ |
1110 | 278 | frame=SyncNextImageInList(frame); |
1111 | 278 | } while ((frame != (Image *) NULL) && (adjoin != MagickFalse)); |
1112 | 278 | scene=0; |
1113 | 278 | frame=(images != (Image *) NULL) ? images : image; |
1114 | 278 | directory=AcquireIconDirectory(number_scenes); |
1115 | 278 | if (directory == (IconDirectory *) NULL) |
1116 | 278 | ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); |
1117 | 278 | png_size=0; |
1118 | 278 | option=GetImageOption(image_info,"icon:png-compression-size"); |
1119 | 278 | if (option != (const char*)NULL) |
1120 | 0 | png_size=(size_t) StringToDouble(option,(char**) NULL); |
1121 | 278 | do |
1122 | 278 | { |
1123 | 278 | size_t |
1124 | 278 | size; |
1125 | | |
1126 | 278 | unsigned short |
1127 | 278 | bits_per_pixel, |
1128 | 278 | planes; |
1129 | | |
1130 | 278 | if (ShouldCompressAsPng(frame,png_size) != MagickFalse) |
1131 | 0 | { |
1132 | 0 | Image |
1133 | 0 | *write_image; |
1134 | |
|
1135 | 0 | ImageInfo |
1136 | 0 | *write_info; |
1137 | |
|
1138 | 0 | size_t |
1139 | 0 | length; |
1140 | |
|
1141 | 0 | unsigned char |
1142 | 0 | *png; |
1143 | |
|
1144 | 0 | write_image=CloneImage(frame,0,0,MagickTrue,exception); |
1145 | 0 | if (write_image == (Image *) NULL) |
1146 | 0 | { |
1147 | 0 | directory=RelinquishIconDirectory(directory); |
1148 | 0 | images=DestroyImageList(images); |
1149 | 0 | return(MagickFalse); |
1150 | 0 | } |
1151 | 0 | write_info=CloneImageInfo(image_info); |
1152 | 0 | length=0; |
1153 | | /* |
1154 | | Don't write any ancillary chunks except for gAMA,tRNS. |
1155 | | */ |
1156 | 0 | (void) SetImageArtifact(write_image,"png:include-chunk", |
1157 | 0 | "none,gama,tRNS"); |
1158 | | /* |
1159 | | Only write PNG32 formatted PNG (32-bit RGBA), 8 bits per channel. |
1160 | | */ |
1161 | 0 | (void) CopyMagickString(write_info->magick,"PNG32",MagickPathExtent); |
1162 | 0 | png=(unsigned char *) ImageToBlob(write_info,write_image,&length, |
1163 | 0 | exception); |
1164 | 0 | write_image=DestroyImageList(write_image); |
1165 | 0 | write_info=DestroyImageInfo(write_info); |
1166 | 0 | if (png == (unsigned char *) NULL) |
1167 | 0 | { |
1168 | 0 | directory=RelinquishIconDirectory(directory); |
1169 | 0 | images=DestroyImageList(images); |
1170 | 0 | return(MagickFalse); |
1171 | 0 | } |
1172 | 0 | directory->icons[scene]->width=0; |
1173 | 0 | directory->icons[scene]->height=0; |
1174 | 0 | directory->icons[scene]->colors=0; |
1175 | 0 | directory->icons[scene]->reserved=0; |
1176 | 0 | directory->icons[scene]->planes=1; |
1177 | 0 | directory->icons[scene]->bits_per_pixel=32; |
1178 | 0 | directory->icons[scene]->size=(size_t) length; |
1179 | 0 | directory->icons[scene]->offset=(size_t) TellBlob(image); |
1180 | 0 | (void) WriteBlob(image,(size_t) length,png); |
1181 | 0 | png=(unsigned char *) RelinquishMagickMemory(png); |
1182 | 0 | } |
1183 | 278 | else |
1184 | 278 | { |
1185 | 278 | size_t |
1186 | 278 | image_size, |
1187 | 278 | number_colors, |
1188 | 278 | x_pixels, |
1189 | 278 | y_pixels; |
1190 | | |
1191 | 278 | ssize_t |
1192 | 278 | width, |
1193 | 278 | height; |
1194 | | |
1195 | | /* |
1196 | | Initialize ICON raster file header. |
1197 | | */ |
1198 | 278 | (void) TransformImageColorspace(frame,sRGBColorspace,exception); |
1199 | 278 | if ((frame->storage_class != DirectClass) && (frame->colors > 256)) |
1200 | 0 | (void) SetImageStorageClass(frame,DirectClass,exception); |
1201 | 278 | if (frame->storage_class == DirectClass) |
1202 | 148 | { |
1203 | | /* |
1204 | | Full color ICON raster. |
1205 | | */ |
1206 | 148 | number_colors=0; |
1207 | 148 | bits_per_pixel=32; |
1208 | 148 | } |
1209 | 130 | else |
1210 | 130 | { |
1211 | | /* |
1212 | | Colormapped ICON raster. |
1213 | | */ |
1214 | 130 | bits_per_pixel=8; |
1215 | 130 | if (frame->colors <= 16) |
1216 | 94 | bits_per_pixel=4; |
1217 | 130 | if (frame->colors <= 2) |
1218 | 33 | bits_per_pixel=1; |
1219 | 130 | number_colors=(size_t) 1 << bits_per_pixel; |
1220 | 130 | if (number_colors < frame->colors) |
1221 | 0 | { |
1222 | 0 | (void) SetImageStorageClass(frame,DirectClass,exception); |
1223 | 0 | number_colors=0; |
1224 | 0 | bits_per_pixel=(unsigned short) 24; |
1225 | 0 | } |
1226 | 130 | } |
1227 | 278 | bytes_per_line=(((frame->columns*bits_per_pixel)+31U) & |
1228 | 278 | ~31U) >> 3; |
1229 | 278 | width=(ssize_t) frame->columns; |
1230 | 278 | height=(ssize_t) frame->rows; |
1231 | 278 | planes=1; |
1232 | 278 | image_size=bytes_per_line*frame->rows; |
1233 | 278 | size=40; |
1234 | 278 | size+=(4*number_colors); |
1235 | 278 | size+=image_size; |
1236 | 278 | size+=(size_t) ((((width+31U) & ~31U) >> 3)*height); |
1237 | 278 | x_pixels=0; |
1238 | 278 | y_pixels=0; |
1239 | 278 | switch (frame->units) |
1240 | 278 | { |
1241 | 278 | case UndefinedResolution: |
1242 | 278 | case PixelsPerInchResolution: |
1243 | 278 | { |
1244 | 278 | x_pixels=(size_t) (100.0*frame->resolution.x/2.54); |
1245 | 278 | y_pixels=(size_t) (100.0*frame->resolution.y/2.54); |
1246 | 278 | break; |
1247 | 278 | } |
1248 | 0 | case PixelsPerCentimeterResolution: |
1249 | 0 | { |
1250 | 0 | x_pixels=(size_t) (100.0*frame->resolution.x); |
1251 | 0 | y_pixels=(size_t) (100.0*frame->resolution.y); |
1252 | 0 | break; |
1253 | 278 | } |
1254 | 278 | } |
1255 | | /* |
1256 | | Convert MIFF to ICON raster pixels. |
1257 | | */ |
1258 | 278 | pixels=(unsigned char *) AcquireQuantumMemory(image_size, |
1259 | 278 | sizeof(*pixels)); |
1260 | 278 | if (pixels == (unsigned char *) NULL) |
1261 | 278 | ThrowICONWriterException(ResourceLimitError,"MemoryAllocationFailed"); |
1262 | 278 | (void) memset(pixels,0,image_size); |
1263 | 278 | switch (bits_per_pixel) |
1264 | 278 | { |
1265 | 33 | case 1: |
1266 | 33 | { |
1267 | 33 | size_t |
1268 | 33 | bit, |
1269 | 33 | byte; |
1270 | | |
1271 | | /* |
1272 | | Convert PseudoClass image to a ICON monochrome image. |
1273 | | */ |
1274 | 628 | for (y=0; y < (ssize_t) frame->rows; y++) |
1275 | 595 | { |
1276 | 595 | p=GetVirtualPixels(frame,0,y,frame->columns,1,exception); |
1277 | 595 | if (p == (const Quantum *) NULL) |
1278 | 0 | break; |
1279 | 595 | q=pixels+((ssize_t) frame->rows-y-1)*(ssize_t) bytes_per_line; |
1280 | 595 | bit=0; |
1281 | 595 | byte=0; |
1282 | 3.03k | for (x=0; x < (ssize_t) frame->columns; x++) |
1283 | 2.44k | { |
1284 | 2.44k | byte<<=1; |
1285 | 2.44k | byte|=(size_t) (GetPixelIndex(frame,p) != 0 ? 0x01 : 0x00); |
1286 | 2.44k | bit++; |
1287 | 2.44k | if (bit == 8) |
1288 | 254 | { |
1289 | 254 | *q++=(unsigned char) byte; |
1290 | 254 | bit=0; |
1291 | 254 | byte=0; |
1292 | 254 | } |
1293 | 2.44k | p+=(ptrdiff_t) GetPixelChannels(frame); |
1294 | 2.44k | } |
1295 | 595 | if (bit != 0) |
1296 | 397 | *q++=(unsigned char) (byte << (8-bit)); |
1297 | 595 | if (frame->previous == (Image *) NULL) |
1298 | 595 | { |
1299 | 595 | status=SetImageProgress(frame,SaveImageTag,y,frame->rows); |
1300 | 595 | if (status == MagickFalse) |
1301 | 0 | break; |
1302 | 595 | } |
1303 | 595 | } |
1304 | 33 | break; |
1305 | 0 | } |
1306 | 61 | case 4: |
1307 | 61 | { |
1308 | 61 | size_t |
1309 | 61 | nibble, |
1310 | 61 | byte; |
1311 | | |
1312 | | /* |
1313 | | Convert PseudoClass image to a ICON monochrome image. |
1314 | | */ |
1315 | 1.43k | for (y=0; y < (ssize_t) frame->rows; y++) |
1316 | 1.37k | { |
1317 | 1.37k | p=GetVirtualPixels(frame,0,y,frame->columns,1,exception); |
1318 | 1.37k | if (p == (const Quantum *) NULL) |
1319 | 0 | break; |
1320 | 1.37k | q=pixels+((ssize_t) frame->rows-y-1)*(ssize_t) bytes_per_line; |
1321 | 1.37k | nibble=0; |
1322 | 1.37k | byte=0; |
1323 | 33.0k | for (x=0; x < (ssize_t) frame->columns; x++) |
1324 | 31.6k | { |
1325 | 31.6k | byte<<=4; |
1326 | 31.6k | byte|=((size_t) GetPixelIndex(frame,p) & 0x0f); |
1327 | 31.6k | nibble++; |
1328 | 31.6k | if (nibble == 2) |
1329 | 15.5k | { |
1330 | 15.5k | *q++=(unsigned char) byte; |
1331 | 15.5k | nibble=0; |
1332 | 15.5k | byte=0; |
1333 | 15.5k | } |
1334 | 31.6k | p+=(ptrdiff_t) GetPixelChannels(frame); |
1335 | 31.6k | } |
1336 | 1.37k | if (nibble != 0) |
1337 | 485 | *q++=(unsigned char) (byte << 4); |
1338 | 1.37k | if (frame->previous == (Image *) NULL) |
1339 | 1.37k | { |
1340 | 1.37k | status=SetImageProgress(frame,SaveImageTag,y,frame->rows); |
1341 | 1.37k | if (status == MagickFalse) |
1342 | 0 | break; |
1343 | 1.37k | } |
1344 | 1.37k | } |
1345 | 61 | break; |
1346 | 0 | } |
1347 | 36 | case 8: |
1348 | 36 | { |
1349 | | /* |
1350 | | Convert PseudoClass packet to ICON pixel. |
1351 | | */ |
1352 | 866 | for (y=0; y < (ssize_t) frame->rows; y++) |
1353 | 830 | { |
1354 | 830 | p=GetVirtualPixels(frame,0,y,frame->columns,1,exception); |
1355 | 830 | if (p == (const Quantum *) NULL) |
1356 | 0 | break; |
1357 | 830 | q=pixels+((ssize_t) frame->rows-y-1)*(ssize_t) bytes_per_line; |
1358 | 1.85k | for (x=0; x < (ssize_t) frame->columns; x++) |
1359 | 1.02k | { |
1360 | 1.02k | *q++=(unsigned char) GetPixelIndex(frame,p); |
1361 | 1.02k | p+=(ptrdiff_t) GetPixelChannels(frame); |
1362 | 1.02k | } |
1363 | 830 | if (frame->previous == (Image *) NULL) |
1364 | 830 | { |
1365 | 830 | status=SetImageProgress(frame,SaveImageTag,y,frame->rows); |
1366 | 830 | if (status == MagickFalse) |
1367 | 0 | break; |
1368 | 830 | } |
1369 | 830 | } |
1370 | 36 | break; |
1371 | 0 | } |
1372 | 0 | case 24: |
1373 | 148 | case 32: |
1374 | 148 | { |
1375 | | /* |
1376 | | Convert DirectClass packet to ICON BGR888 or BGRA8888 pixel. |
1377 | | */ |
1378 | 4.17k | for (y=0; y < (ssize_t) frame->rows; y++) |
1379 | 4.02k | { |
1380 | 4.02k | p=GetVirtualPixels(frame,0,y,frame->columns,1,exception); |
1381 | 4.02k | if (p == (const Quantum *) NULL) |
1382 | 0 | break; |
1383 | 4.02k | q=pixels+((ssize_t) frame->rows-y-1)*(ssize_t) bytes_per_line; |
1384 | 187k | for (x=0; x < (ssize_t) frame->columns; x++) |
1385 | 183k | { |
1386 | 183k | *q++=ScaleQuantumToChar(GetPixelBlue(frame,p)); |
1387 | 183k | *q++=ScaleQuantumToChar(GetPixelGreen(frame,p)); |
1388 | 183k | *q++=ScaleQuantumToChar(GetPixelRed(frame,p)); |
1389 | 183k | if (frame->alpha_trait == UndefinedPixelTrait) |
1390 | 273 | *q++=ScaleQuantumToChar(QuantumRange); |
1391 | 183k | else |
1392 | 183k | *q++=ScaleQuantumToChar(GetPixelAlpha(frame,p)); |
1393 | 183k | p+=(ptrdiff_t) GetPixelChannels(frame); |
1394 | 183k | } |
1395 | 4.02k | if (bits_per_pixel == 24) |
1396 | 0 | for (x=3L*(ssize_t) frame->columns; x < (ssize_t) bytes_per_line; x++) |
1397 | 0 | *q++=0x00; |
1398 | 4.02k | if (frame->previous == (Image *) NULL) |
1399 | 4.02k | { |
1400 | 4.02k | status=SetImageProgress(frame,SaveImageTag,y,frame->rows); |
1401 | 4.02k | if (status == MagickFalse) |
1402 | 0 | break; |
1403 | 4.02k | } |
1404 | 4.02k | } |
1405 | 148 | break; |
1406 | 0 | } |
1407 | 278 | } |
1408 | | /* |
1409 | | Write 40-byte version 3+ bitmap header. |
1410 | | */ |
1411 | | /* The value 0 is accepted as representing a width of 256 */ |
1412 | 278 | directory->icons[scene]->width=(unsigned char) width % 256; |
1413 | 278 | directory->icons[scene]->height=(unsigned char) height % 256; |
1414 | 278 | directory->icons[scene]->colors=(unsigned char) number_colors; |
1415 | 278 | directory->icons[scene]->reserved=0; |
1416 | 278 | directory->icons[scene]->planes=planes; |
1417 | 278 | directory->icons[scene]->bits_per_pixel=bits_per_pixel; |
1418 | 278 | directory->icons[scene]->size=size; |
1419 | 278 | directory->icons[scene]->offset=(size_t) TellBlob(image); |
1420 | 278 | (void) WriteBlobLSBLong(image,(unsigned int) 40); |
1421 | 278 | (void) WriteBlobLSBLong(image,(unsigned int) width); |
1422 | 278 | (void) WriteBlobLSBLong(image,(unsigned int) height*2); |
1423 | 278 | (void) WriteBlobLSBShort(image,planes); |
1424 | 278 | (void) WriteBlobLSBShort(image,bits_per_pixel); |
1425 | 278 | (void) WriteBlobLSBLong(image,(unsigned int) IconRgbCompression); |
1426 | 278 | (void) WriteBlobLSBLong(image,(unsigned int) image_size); |
1427 | 278 | (void) WriteBlobLSBLong(image,(unsigned int) x_pixels); |
1428 | 278 | (void) WriteBlobLSBLong(image,(unsigned int) y_pixels); |
1429 | 278 | (void) WriteBlobLSBLong(image,(unsigned int) number_colors); |
1430 | 278 | (void) WriteBlobLSBLong(image,(unsigned int) number_colors); |
1431 | 278 | if (frame->storage_class == PseudoClass) |
1432 | 130 | { |
1433 | 130 | unsigned char |
1434 | 130 | *icon_colormap; |
1435 | | |
1436 | | /* |
1437 | | Dump colormap to file. |
1438 | | */ |
1439 | 130 | icon_colormap=(unsigned char *) AcquireQuantumMemory((size_t) 1UL |
1440 | 130 | << bits_per_pixel,4UL*sizeof(*icon_colormap)); |
1441 | 130 | if (icon_colormap == (unsigned char *) NULL) |
1442 | 0 | ThrowICONWriterException(ResourceLimitError, |
1443 | 130 | "MemoryAllocationFailed"); |
1444 | 130 | q=icon_colormap; |
1445 | 2.77k | for (i=0; i < (ssize_t) frame->colors; i++) |
1446 | 2.64k | { |
1447 | 2.64k | *q++=ScaleQuantumToChar((Quantum) frame->colormap[i].blue); |
1448 | 2.64k | *q++=ScaleQuantumToChar((Quantum) frame->colormap[i].green); |
1449 | 2.64k | *q++=ScaleQuantumToChar((Quantum) frame->colormap[i].red); |
1450 | 2.64k | *q++=(unsigned char) 0x00; |
1451 | 2.64k | } |
1452 | 7.74k | for ( ; i < (ssize_t) 1UL << bits_per_pixel; i++) |
1453 | 7.61k | { |
1454 | 7.61k | *q++=(unsigned char) 0x00; |
1455 | 7.61k | *q++=(unsigned char) 0x00; |
1456 | 7.61k | *q++=(unsigned char) 0x00; |
1457 | 7.61k | *q++=(unsigned char) 0x00; |
1458 | 7.61k | } |
1459 | 130 | (void) WriteBlob(image,(size_t) (4UL*(1UL << bits_per_pixel)), |
1460 | 130 | icon_colormap); |
1461 | 130 | icon_colormap=(unsigned char *) RelinquishMagickMemory( |
1462 | 130 | icon_colormap); |
1463 | 130 | } |
1464 | 278 | (void) WriteBlob(image,image_size,pixels); |
1465 | 278 | pixels=(unsigned char *) RelinquishMagickMemory(pixels); |
1466 | | /* |
1467 | | Write matte mask. |
1468 | | */ |
1469 | 278 | scanline_pad=(((frame->columns+31U) & ~31U)-frame->columns) >> 3; |
1470 | 7.10k | for (y=((ssize_t) frame->rows - 1); y >= 0; y--) |
1471 | 6.82k | { |
1472 | 6.82k | unsigned char |
1473 | 6.82k | bit, |
1474 | 6.82k | byte; |
1475 | | |
1476 | 6.82k | p=GetVirtualPixels(frame,0,y,frame->columns,1,exception); |
1477 | 6.82k | if (p == (const Quantum *) NULL) |
1478 | 0 | break; |
1479 | 6.82k | bit=0; |
1480 | 6.82k | byte=0; |
1481 | 225k | for (x=0; x < (ssize_t) frame->columns; x++) |
1482 | 219k | { |
1483 | 219k | byte<<=1; |
1484 | 219k | if ((frame->alpha_trait != UndefinedPixelTrait) && |
1485 | 218k | (GetPixelAlpha(frame,p) == (Quantum) TransparentAlpha)) |
1486 | 96.1k | byte|=0x01; |
1487 | 219k | bit++; |
1488 | 219k | if (bit == 8) |
1489 | 26.4k | { |
1490 | 26.4k | (void) WriteBlobByte(image,(unsigned char) byte); |
1491 | 26.4k | bit=0; |
1492 | 26.4k | byte=0; |
1493 | 26.4k | } |
1494 | 219k | p+=(ptrdiff_t) GetPixelChannels(frame); |
1495 | 219k | } |
1496 | 6.82k | if (bit != 0) |
1497 | 4.73k | (void) WriteBlobByte(image,(unsigned char) (byte << (8-bit))); |
1498 | 20.4k | for (i=0; i < (ssize_t) scanline_pad; i++) |
1499 | 13.5k | (void) WriteBlobByte(image,(unsigned char) 0); |
1500 | 6.82k | } |
1501 | 278 | } |
1502 | 278 | if (GetNextImageInList(frame) == (Image *) NULL) |
1503 | 278 | break; |
1504 | 0 | status=SetImageProgress(frame,SaveImagesTag,scene++,number_scenes); |
1505 | 0 | if (status == MagickFalse) |
1506 | 0 | break; |
1507 | 0 | frame=SyncNextImageInList(frame); |
1508 | 0 | } while ((frame != (Image *) NULL) && (adjoin != MagickFalse)); |
1509 | 278 | offset=SeekBlob(image,0,SEEK_SET); |
1510 | 278 | (void) offset; |
1511 | 278 | (void) WriteBlobLSBShort(image,0); |
1512 | 278 | (void) WriteBlobLSBShort(image,1); |
1513 | 278 | (void) WriteBlobLSBShort(image,(unsigned short) (scene+1)); |
1514 | 278 | scene=0; |
1515 | 278 | frame=(images != (Image *) NULL) ? images : image; |
1516 | 278 | do |
1517 | 278 | { |
1518 | 278 | (void) WriteBlobByte(image,directory->icons[scene]->width); |
1519 | 278 | (void) WriteBlobByte(image,directory->icons[scene]->height); |
1520 | 278 | (void) WriteBlobByte(image,directory->icons[scene]->colors); |
1521 | 278 | (void) WriteBlobByte(image,directory->icons[scene]->reserved); |
1522 | 278 | (void) WriteBlobLSBShort(image,directory->icons[scene]->planes); |
1523 | 278 | (void) WriteBlobLSBShort(image,directory->icons[scene]->bits_per_pixel); |
1524 | 278 | (void) WriteBlobLSBLong(image,(unsigned int) |
1525 | 278 | directory->icons[scene]->size); |
1526 | 278 | (void) WriteBlobLSBLong(image,(unsigned int) |
1527 | 278 | directory->icons[scene]->offset); |
1528 | 278 | scene++; |
1529 | 278 | frame=SyncNextImageInList(frame); |
1530 | 278 | } while ((frame != (Image *) NULL) && (adjoin != MagickFalse)); |
1531 | 278 | directory=RelinquishIconDirectory(directory); |
1532 | 278 | (void) CloseBlob(image); |
1533 | 278 | images=DestroyImageList(images); |
1534 | 278 | return(MagickTrue); |
1535 | 278 | } |