blob: 34db833654b129572dbe2de55cd228e2eb728c70 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% M M IIIII FFFFF FFFFF %
7% MM MM I F F %
8% M M M I FFF FFF %
9% M M I F F %
10% M M IIIII F F %
11% %
12% %
13% Read/Write MIFF Image 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"
43#include "MagickCore/attribute.h"
44#include "MagickCore/blob.h"
45#include "MagickCore/blob-private.h"
46#include "MagickCore/cache.h"
47#include "MagickCore/color.h"
48#include "MagickCore/color-private.h"
49#include "MagickCore/colormap.h"
50#include "MagickCore/colormap-private.h"
51#include "MagickCore/colorspace.h"
cristy325cfdc2012-04-28 01:00:09 +000052#include "MagickCore/colorspace-private.h"
cristy4c08aed2011-07-01 19:47:50 +000053#include "MagickCore/constitute.h"
54#include "MagickCore/exception.h"
55#include "MagickCore/exception-private.h"
56#include "MagickCore/hashmap.h"
57#include "MagickCore/geometry.h"
58#include "MagickCore/image.h"
59#include "MagickCore/image-private.h"
60#include "MagickCore/list.h"
61#include "MagickCore/magick.h"
62#include "MagickCore/memory_.h"
63#include "MagickCore/module.h"
64#include "MagickCore/monitor.h"
65#include "MagickCore/monitor-private.h"
66#include "MagickCore/option.h"
67#include "MagickCore/pixel.h"
68#include "MagickCore/pixel-accessor.h"
69#include "MagickCore/profile.h"
70#include "MagickCore/property.h"
71#include "MagickCore/quantum-private.h"
72#include "MagickCore/static.h"
73#include "MagickCore/statistic.h"
74#include "MagickCore/string_.h"
75#include "MagickCore/string-private.h"
cristy3ed852e2009-09-05 21:47:34 +000076#if defined(MAGICKCORE_BZLIB_DELEGATE)
77#include "bzlib.h"
78#endif
cristy26377172010-12-20 19:01:58 +000079#if defined(MAGICKCORE_LZMA_DELEGATE)
80#include "lzma.h"
81#endif
82#if defined(MAGICKCORE_ZLIB_DELEGATE)
83#include "zlib.h"
84#endif
cristy3ed852e2009-09-05 21:47:34 +000085
86/*
cristya7a341e2010-12-22 20:28:51 +000087 Define declarations.
88*/
89#if !defined(LZMA_OK)
90#define LZMA_OK 0
91#endif
92
93/*
cristy3ed852e2009-09-05 21:47:34 +000094 Forward declarations.
95*/
96static MagickBooleanType
cristy1e178e72011-08-28 19:44:34 +000097 WriteMIFFImage(const ImageInfo *,Image *,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +000098
99/*
100%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
101% %
102% %
103% %
104% I s M I F F %
105% %
106% %
107% %
108%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
109%
110% IsMIFF() returns MagickTrue if the image format type, identified by the
111% magick string, is MIFF.
112%
113% The format of the IsMIFF method is:
114%
115% MagickBooleanType IsMIFF(const unsigned char *magick,const size_t length)
116%
117% A description of each parameter follows:
118%
119% o magick: compare image format pattern against these bytes.
120%
121% o length: Specifies the length of the magick string.
122%
123*/
124static MagickBooleanType IsMIFF(const unsigned char *magick,const size_t length)
125{
126 if (length < 14)
127 return(MagickFalse);
128 if (LocaleNCompare((const char *) magick,"id=ImageMagick",14) == 0)
129 return(MagickTrue);
130 return(MagickFalse);
131}
132
133/*
134%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
135% %
136% %
137% %
138% R e a d M I F F I m a g e %
139% %
140% %
141% %
142%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
143%
144% ReadMIFFImage() reads a MIFF image file and returns it. It allocates the
145% memory necessary for the new Image structure and returns a pointer to the
146% new image.
147%
148% The format of the ReadMIFFImage method is:
149%
150% Image *ReadMIFFImage(const ImageInfo *image_info,
151% ExceptionInfo *exception)
152%
153% Decompression code contributed by Kyle Shorter.
154%
155% A description of each parameter follows:
156%
157% o image_info: the image info.
158%
159% o exception: return any errors or warnings in this structure.
160%
161*/
162
163#if defined(MAGICKCORE_BZLIB_DELEGATE)
164static void *AcquireBZIPMemory(void *context,int items,int size)
165{
166 (void) context;
167 return((void *) AcquireQuantumMemory((size_t) items,(size_t) size));
168}
169#endif
170
cristy4b46dba2010-12-20 19:18:20 +0000171#if defined(MAGICKCORE_LZMA_DELEGATE)
172static void *AcquireLZMAMemory(void *context,size_t items,size_t size)
173{
174 (void) context;
175 return((void *) AcquireQuantumMemory((size_t) items,(size_t) size));
176}
177#endif
178
cristy3ed852e2009-09-05 21:47:34 +0000179#if defined(MAGICKCORE_ZLIB_DELEGATE)
180static voidpf AcquireZIPMemory(voidpf context,unsigned int items,
181 unsigned int size)
182{
183 (void) context;
184 return((voidpf) AcquireQuantumMemory(items,size));
185}
186#endif
187
188static inline size_t MagickMax(const size_t x,const size_t y)
189{
190 if (x > y)
191 return(x);
192 return(y);
193}
194
195static inline size_t MagickMin(const size_t x,const size_t y)
196{
197 if (x < y)
198 return(x);
199 return(y);
200}
201
202static void PushRunlengthPacket(Image *image,const unsigned char *pixels,
cristyc82a27b2011-10-21 01:07:16 +0000203 size_t *length,PixelInfo *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000204{
205 const unsigned char
206 *p;
207
208 p=pixels;
209 if (image->storage_class == PseudoClass)
210 {
cristy4c08aed2011-07-01 19:47:50 +0000211 pixel->index=0;
cristy3ed852e2009-09-05 21:47:34 +0000212 switch (image->depth)
213 {
214 case 32:
215 {
cristy4c08aed2011-07-01 19:47:50 +0000216 pixel->index=ConstrainColormapIndex(image,
cristyc82a27b2011-10-21 01:07:16 +0000217 (*p << 24) | (*(p+1) << 16) | (*(p+2) << 8) | *(p+3),exception);
cristy3ed852e2009-09-05 21:47:34 +0000218 p+=4;
219 break;
220 }
221 case 16:
222 {
cristyc82a27b2011-10-21 01:07:16 +0000223 pixel->index=ConstrainColormapIndex(image,(*p << 8) | *(p+1),
224 exception);
cristy3ed852e2009-09-05 21:47:34 +0000225 p+=2;
226 break;
227 }
228 case 8:
229 {
cristyc82a27b2011-10-21 01:07:16 +0000230 pixel->index=ConstrainColormapIndex(image,*p,exception);
cristy3ed852e2009-09-05 21:47:34 +0000231 p++;
232 break;
233 }
234 default:
cristyc82a27b2011-10-21 01:07:16 +0000235 (void) ThrowMagickException(exception,GetMagickModule(),
cristy3ed852e2009-09-05 21:47:34 +0000236 CorruptImageError,"ImageDepthNotSupported","`%s'",image->filename);
237 }
cristy3ed852e2009-09-05 21:47:34 +0000238 switch (image->depth)
239 {
240 case 8:
241 {
242 unsigned char
243 quantum;
244
245 if (image->matte != MagickFalse)
246 {
247 p=PushCharPixel(p,&quantum);
cristy4c08aed2011-07-01 19:47:50 +0000248 pixel->alpha=ScaleCharToQuantum(quantum);
cristy3ed852e2009-09-05 21:47:34 +0000249 }
250 break;
251 }
252 case 16:
253 {
254 unsigned short
255 quantum;
256
257 if (image->matte != MagickFalse)
258 {
259 p=PushShortPixel(MSBEndian,p,&quantum);
cristy4c08aed2011-07-01 19:47:50 +0000260 pixel->alpha=(Quantum) (quantum >> (image->depth-
cristy3ed852e2009-09-05 21:47:34 +0000261 MAGICKCORE_QUANTUM_DEPTH));
262 }
263 break;
264 }
265 case 32:
266 {
cristy4cb162a2010-05-30 03:04:47 +0000267 unsigned int
cristy3ed852e2009-09-05 21:47:34 +0000268 quantum;
269
270 if (image->matte != MagickFalse)
271 {
272 p=PushLongPixel(MSBEndian,p,&quantum);
cristy4c08aed2011-07-01 19:47:50 +0000273 pixel->alpha=(Quantum) (quantum >> (image->depth-
cristy3ed852e2009-09-05 21:47:34 +0000274 MAGICKCORE_QUANTUM_DEPTH));
275 }
276 break;
277 }
278 default:
cristyc82a27b2011-10-21 01:07:16 +0000279 (void) ThrowMagickException(exception,GetMagickModule(),
cristy3ed852e2009-09-05 21:47:34 +0000280 CorruptImageError,"ImageDepthNotSupported","`%s'",image->filename);
281 }
282 *length=(size_t) (*p++)+1;
283 return;
284 }
285 switch (image->depth)
286 {
287 case 8:
288 {
289 unsigned char
290 quantum;
291
292 p=PushCharPixel(p,&quantum);
cristy4c08aed2011-07-01 19:47:50 +0000293 pixel->red=ScaleCharToQuantum(quantum);
cristy325cfdc2012-04-28 01:00:09 +0000294 pixel->green=pixel->red;
295 pixel->blue=pixel->red;
296 if (IsGrayColorspace(image->colorspace) == MagickFalse)
297 {
298 p=PushCharPixel(p,&quantum);
299 pixel->green=ScaleCharToQuantum(quantum);
300 p=PushCharPixel(p,&quantum);
301 pixel->blue=ScaleCharToQuantum(quantum);
302 }
cristy3ed852e2009-09-05 21:47:34 +0000303 if (image->colorspace == CMYKColorspace)
304 {
305 p=PushCharPixel(p,&quantum);
cristy4c08aed2011-07-01 19:47:50 +0000306 pixel->black=ScaleCharToQuantum(quantum);
307 }
308 if (image->matte != MagickFalse)
309 {
310 p=PushCharPixel(p,&quantum);
311 pixel->alpha=ScaleCharToQuantum(quantum);
cristy3ed852e2009-09-05 21:47:34 +0000312 }
313 break;
314 }
315 case 16:
316 {
317 unsigned short
318 quantum;
319
320 p=PushShortPixel(MSBEndian,p,&quantum);
cristy4c08aed2011-07-01 19:47:50 +0000321 pixel->red=quantum >> (image->depth-MAGICKCORE_QUANTUM_DEPTH);
cristy325cfdc2012-04-28 01:00:09 +0000322 pixel->green=pixel->red;
323 pixel->blue=pixel->red;
324 if (IsGrayColorspace(image->colorspace) == MagickFalse)
325 {
326 p=PushShortPixel(MSBEndian,p,&quantum);
327 pixel->green=quantum >> (image->depth-MAGICKCORE_QUANTUM_DEPTH);
328 p=PushShortPixel(MSBEndian,p,&quantum);
329 pixel->blue=quantum >> (image->depth-MAGICKCORE_QUANTUM_DEPTH);
330 }
cristy3ed852e2009-09-05 21:47:34 +0000331 if (image->colorspace == CMYKColorspace)
332 {
333 p=PushShortPixel(MSBEndian,p,&quantum);
cristy4c08aed2011-07-01 19:47:50 +0000334 pixel->black=quantum >> (image->depth-MAGICKCORE_QUANTUM_DEPTH);
335 }
336 if (image->matte != MagickFalse)
337 {
338 p=PushShortPixel(MSBEndian,p,&quantum);
339 pixel->alpha=quantum >> (image->depth-MAGICKCORE_QUANTUM_DEPTH);
cristy3ed852e2009-09-05 21:47:34 +0000340 }
341 break;
342 }
343 case 32:
344 {
cristy4cb162a2010-05-30 03:04:47 +0000345 unsigned int
cristy3ed852e2009-09-05 21:47:34 +0000346 quantum;
347
348 p=PushLongPixel(MSBEndian,p,&quantum);
cristy4c08aed2011-07-01 19:47:50 +0000349 pixel->red=quantum >> (image->depth-MAGICKCORE_QUANTUM_DEPTH);
cristy325cfdc2012-04-28 01:00:09 +0000350 pixel->green=pixel->red;
351 pixel->blue=pixel->red;
352 if (IsGrayColorspace(image->colorspace) == MagickFalse)
353 {
354 p=PushLongPixel(MSBEndian,p,&quantum);
355 pixel->green=quantum >> (image->depth-MAGICKCORE_QUANTUM_DEPTH);
356 p=PushLongPixel(MSBEndian,p,&quantum);
357 pixel->blue=quantum >> (image->depth-MAGICKCORE_QUANTUM_DEPTH);
358 }
cristy3ed852e2009-09-05 21:47:34 +0000359 if (image->colorspace == CMYKColorspace)
360 {
361 p=PushLongPixel(MSBEndian,p,&quantum);
cristy4c08aed2011-07-01 19:47:50 +0000362 pixel->black=quantum >> (image->depth-MAGICKCORE_QUANTUM_DEPTH);
363 }
364 if (image->matte != MagickFalse)
365 {
366 p=PushLongPixel(MSBEndian,p,&quantum);
367 pixel->alpha=quantum >> (image->depth-MAGICKCORE_QUANTUM_DEPTH);
cristy3ed852e2009-09-05 21:47:34 +0000368 }
369 break;
370 }
371 default:
cristyc82a27b2011-10-21 01:07:16 +0000372 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
373 "ImageDepthNotSupported","`%s'",image->filename);
cristy3ed852e2009-09-05 21:47:34 +0000374 }
375 *length=(size_t) (*p++)+1;
376}
377
cristy4b46dba2010-12-20 19:18:20 +0000378#if defined(MAGICKCORE_BZLIB_DELEGATE)
379static void RelinquishBZIPMemory(void *context,void *memory)
cristy3ed852e2009-09-05 21:47:34 +0000380{
381 (void) context;
382 memory=RelinquishMagickMemory(memory);
383}
384#endif
385
cristy4b46dba2010-12-20 19:18:20 +0000386#if defined(MAGICKCORE_LZMA_DELEGATE)
387static void RelinquishLZMAMemory(void *context,void *memory)
388{
389 (void) context;
390 memory=RelinquishMagickMemory(memory);
391}
392#endif
393
394#if defined(MAGICKCORE_ZLIB_DELEGATE)
395static void RelinquishZIPMemory(voidpf context,voidpf memory)
cristy3ed852e2009-09-05 21:47:34 +0000396{
397 (void) context;
398 memory=RelinquishMagickMemory(memory);
399}
400#endif
401
402static Image *ReadMIFFImage(const ImageInfo *image_info,
403 ExceptionInfo *exception)
404{
405#define BZipMaxExtent(x) ((x)+((x)/100)+600)
cristy26377172010-12-20 19:01:58 +0000406#define LZMAMaxExtent(x) ((x)+((x)/3)+128)
cristy3ed852e2009-09-05 21:47:34 +0000407#define ZipMaxExtent(x) ((x)+(((x)+7) >> 3)+(((x)+63) >> 6)+11)
408
409#if defined(MAGICKCORE_BZLIB_DELEGATE)
410 bz_stream
411 bzip_info;
412#endif
413
414 char
415 id[MaxTextExtent],
416 keyword[MaxTextExtent],
417 *options;
418
419 const unsigned char
420 *p;
421
422 double
423 version;
424
425 GeometryInfo
426 geometry_info;
427
428 Image
429 *image;
430
cristy3ed852e2009-09-05 21:47:34 +0000431 int
cristy3a99dcf2011-12-17 01:29:40 +0000432 c;
cristy3ed852e2009-09-05 21:47:34 +0000433
cristyde626a22012-05-13 00:39:00 +0000434 LinkedListInfo
435 *profiles;
436
cristy26377172010-12-20 19:01:58 +0000437#if defined(MAGICKCORE_LZMA_DELEGATE)
438 lzma_stream
cristy330af6c2010-12-21 14:36:06 +0000439 initialize_lzma = LZMA_STREAM_INIT,
440 lzma_info;
cristy4b46dba2010-12-20 19:18:20 +0000441
442 lzma_allocator
443 allocator;
cristy26377172010-12-20 19:01:58 +0000444#endif
445
cristy3ed852e2009-09-05 21:47:34 +0000446 MagickBooleanType
447 status;
448
cristy4c08aed2011-07-01 19:47:50 +0000449 PixelInfo
450 pixel;
451
cristy3ed852e2009-09-05 21:47:34 +0000452 MagickStatusType
453 flags;
454
cristy3ed852e2009-09-05 21:47:34 +0000455 QuantumFormatType
456 quantum_format;
457
458 QuantumInfo
459 *quantum_info;
460
461 QuantumType
462 quantum_type;
463
cristybb503372010-05-27 20:51:26 +0000464 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000465 i;
466
467 size_t
468 length,
469 packet_size;
470
471 ssize_t
472 count;
473
474 unsigned char
475 *compress_pixels,
476 *pixels;
477
cristybb503372010-05-27 20:51:26 +0000478 size_t
cristy3ed852e2009-09-05 21:47:34 +0000479 colors;
480
cristy26377172010-12-20 19:01:58 +0000481 ssize_t
482 y;
483
cristy3ed852e2009-09-05 21:47:34 +0000484#if defined(MAGICKCORE_ZLIB_DELEGATE)
485 z_stream
486 zip_info;
487#endif
488
489 /*
490 Open image file.
491 */
492 assert(image_info != (const ImageInfo *) NULL);
493 assert(image_info->signature == MagickSignature);
494 if (image_info->debug != MagickFalse)
495 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
496 image_info->filename);
497 assert(exception != (ExceptionInfo *) NULL);
498 assert(exception->signature == MagickSignature);
cristy9950d572011-10-01 18:22:35 +0000499 image=AcquireImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +0000500 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
501 if (status == MagickFalse)
502 {
503 image=DestroyImageList(image);
504 return((Image *) NULL);
505 }
506 /*
507 Decode image header; header terminates one character beyond a ':'.
508 */
509 c=ReadBlobByte(image);
510 if (c == EOF)
511 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
cristy3ed852e2009-09-05 21:47:34 +0000512 *id='\0';
513 (void) ResetMagickMemory(keyword,0,sizeof(keyword));
514 version=0.0;
cristy51f4b1b2012-02-21 13:56:07 +0000515 (void) version;
cristy3ed852e2009-09-05 21:47:34 +0000516 do
517 {
518 /*
519 Decode image header; header terminates one character beyond a ':'.
520 */
521 length=MaxTextExtent;
522 options=AcquireString((char *) NULL);
523 quantum_format=UndefinedQuantumFormat;
524 profiles=(LinkedListInfo *) NULL;
525 colors=0;
526 image->depth=8UL;
527 image->compression=NoCompression;
528 while ((isgraph(c) != MagickFalse) && (c != (int) ':'))
529 {
530 register char
531 *p;
532
533 if (c == (int) '{')
534 {
535 char
536 *comment;
537
538 /*
539 Read comment-- any text between { }.
540 */
541 length=MaxTextExtent;
542 comment=AcquireString((char *) NULL);
543 for (p=comment; comment != (char *) NULL; p++)
544 {
545 c=ReadBlobByte(image);
cristyb880ee82012-04-07 15:08:14 +0000546 if (c == (int) '\\')
547 c=ReadBlobByte(image);
548 else
549 if ((c == EOF) || (c == (int) '}'))
550 break;
cristy3ed852e2009-09-05 21:47:34 +0000551 if ((size_t) (p-comment+1) >= length)
552 {
553 *p='\0';
554 length<<=1;
555 comment=(char *) ResizeQuantumMemory(comment,length+
556 MaxTextExtent,sizeof(*comment));
557 if (comment == (char *) NULL)
558 break;
559 p=comment+strlen(comment);
560 }
561 *p=(char) c;
562 }
563 if (comment == (char *) NULL)
564 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
565 *p='\0';
cristyd15e6592011-10-15 00:13:06 +0000566 (void) SetImageProperty(image,"comment",comment,exception);
cristy3ed852e2009-09-05 21:47:34 +0000567 comment=DestroyString(comment);
568 c=ReadBlobByte(image);
569 }
570 else
571 if (isalnum(c) != MagickFalse)
572 {
573 /*
574 Get the keyword.
575 */
576 p=keyword;
577 do
578 {
cristy3ed852e2009-09-05 21:47:34 +0000579 if (c == (int) '=')
580 break;
581 if ((size_t) (p-keyword) < (MaxTextExtent-1))
582 *p++=(char) c;
583 c=ReadBlobByte(image);
584 } while (c != EOF);
585 *p='\0';
586 p=options;
cristy93505cf2010-08-10 21:37:49 +0000587 while ((isspace((int) ((unsigned char) c)) != 0) && (c != EOF))
cristy3ed852e2009-09-05 21:47:34 +0000588 c=ReadBlobByte(image);
589 if (c == (int) '=')
590 {
591 /*
592 Get the keyword value.
593 */
594 c=ReadBlobByte(image);
595 while ((c != (int) '}') && (c != EOF))
596 {
597 if ((size_t) (p-options+1) >= length)
598 {
599 *p='\0';
600 length<<=1;
601 options=(char *) ResizeQuantumMemory(options,length+
602 MaxTextExtent,sizeof(*options));
603 if (options == (char *) NULL)
604 break;
605 p=options+strlen(options);
606 }
607 if (options == (char *) NULL)
608 ThrowReaderException(ResourceLimitError,
609 "MemoryAllocationFailed");
610 *p++=(char) c;
611 c=ReadBlobByte(image);
cristyb880ee82012-04-07 15:08:14 +0000612 if (c == '\\')
613 {
614 c=ReadBlobByte(image);
615 if (c == (int) '}')
616 {
617 *p++=(char) c;
618 c=ReadBlobByte(image);
619 }
620 }
cristy3ed852e2009-09-05 21:47:34 +0000621 if (*options != '{')
622 if (isspace((int) ((unsigned char) c)) != 0)
623 break;
624 }
625 }
626 *p='\0';
627 if (*options == '{')
cristyadbbfc42012-05-20 15:13:57 +0000628 (void) strcpy(options,options+1);
cristy3ed852e2009-09-05 21:47:34 +0000629 /*
630 Assign a value to the specified keyword.
631 */
632 switch (*keyword)
633 {
634 case 'b':
635 case 'B':
636 {
637 if (LocaleCompare(keyword,"background-color") == 0)
638 {
cristy9950d572011-10-01 18:22:35 +0000639 (void) QueryColorCompliance(options,AllCompliance,
640 &image->background_color,exception);
cristy3ed852e2009-09-05 21:47:34 +0000641 break;
642 }
643 if (LocaleCompare(keyword,"blue-primary") == 0)
644 {
645 flags=ParseGeometry(options,&geometry_info);
646 image->chromaticity.blue_primary.x=geometry_info.rho;
647 image->chromaticity.blue_primary.y=geometry_info.sigma;
648 if ((flags & SigmaValue) == 0)
649 image->chromaticity.blue_primary.y=
650 image->chromaticity.blue_primary.x;
651 break;
652 }
653 if (LocaleCompare(keyword,"border-color") == 0)
654 {
cristy9950d572011-10-01 18:22:35 +0000655 (void) QueryColorCompliance(options,AllCompliance,
656 &image->border_color,exception);
cristy3ed852e2009-09-05 21:47:34 +0000657 break;
658 }
cristyd15e6592011-10-15 00:13:06 +0000659 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000660 break;
661 }
662 case 'c':
663 case 'C':
664 {
665 if (LocaleCompare(keyword,"class") == 0)
666 {
cristybb503372010-05-27 20:51:26 +0000667 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000668 storage_class;
669
cristy042ee782011-04-22 18:48:30 +0000670 storage_class=ParseCommandOption(MagickClassOptions,
cristy3ed852e2009-09-05 21:47:34 +0000671 MagickFalse,options);
672 if (storage_class < 0)
673 break;
674 image->storage_class=(ClassType) storage_class;
675 break;
676 }
677 if (LocaleCompare(keyword,"colors") == 0)
678 {
cristye27293e2009-12-18 02:53:20 +0000679 colors=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000680 break;
681 }
682 if (LocaleCompare(keyword,"colorspace") == 0)
683 {
cristybb503372010-05-27 20:51:26 +0000684 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000685 colorspace;
686
cristy042ee782011-04-22 18:48:30 +0000687 colorspace=ParseCommandOption(MagickColorspaceOptions,
cristy3ed852e2009-09-05 21:47:34 +0000688 MagickFalse,options);
689 if (colorspace < 0)
690 break;
691 image->colorspace=(ColorspaceType) colorspace;
692 break;
693 }
694 if (LocaleCompare(keyword,"compression") == 0)
695 {
cristybb503372010-05-27 20:51:26 +0000696 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000697 compression;
698
cristy042ee782011-04-22 18:48:30 +0000699 compression=ParseCommandOption(MagickCompressOptions,
cristy3ed852e2009-09-05 21:47:34 +0000700 MagickFalse,options);
701 if (compression < 0)
702 break;
703 image->compression=(CompressionType) compression;
704 break;
705 }
706 if (LocaleCompare(keyword,"columns") == 0)
707 {
cristye27293e2009-12-18 02:53:20 +0000708 image->columns=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000709 break;
710 }
cristyd15e6592011-10-15 00:13:06 +0000711 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000712 break;
713 }
714 case 'd':
715 case 'D':
716 {
717 if (LocaleCompare(keyword,"delay") == 0)
718 {
cristye27293e2009-12-18 02:53:20 +0000719 image->delay=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000720 break;
721 }
722 if (LocaleCompare(keyword,"depth") == 0)
723 {
cristye27293e2009-12-18 02:53:20 +0000724 image->depth=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000725 break;
726 }
727 if (LocaleCompare(keyword,"dispose") == 0)
728 {
cristybb503372010-05-27 20:51:26 +0000729 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000730 dispose;
731
cristy042ee782011-04-22 18:48:30 +0000732 dispose=ParseCommandOption(MagickDisposeOptions,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000733 options);
734 if (dispose < 0)
735 break;
736 image->dispose=(DisposeType) dispose;
737 break;
738 }
cristyd15e6592011-10-15 00:13:06 +0000739 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000740 break;
741 }
742 case 'e':
743 case 'E':
744 {
745 if (LocaleCompare(keyword,"endian") == 0)
746 {
cristybb503372010-05-27 20:51:26 +0000747 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000748 endian;
749
cristy042ee782011-04-22 18:48:30 +0000750 endian=ParseCommandOption(MagickEndianOptions,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000751 options);
752 if (endian < 0)
753 break;
754 image->endian=(EndianType) endian;
755 break;
756 }
cristyd15e6592011-10-15 00:13:06 +0000757 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000758 break;
759 }
760 case 'g':
761 case 'G':
762 {
763 if (LocaleCompare(keyword,"gamma") == 0)
764 {
cristydbdd0e32011-11-04 23:29:40 +0000765 image->gamma=StringToDouble(options,(char **) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000766 break;
767 }
768 if (LocaleCompare(keyword,"gravity") == 0)
769 {
cristybb503372010-05-27 20:51:26 +0000770 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000771 gravity;
772
cristy042ee782011-04-22 18:48:30 +0000773 gravity=ParseCommandOption(MagickGravityOptions,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000774 options);
775 if (gravity < 0)
776 break;
777 image->gravity=(GravityType) gravity;
778 break;
779 }
780 if (LocaleCompare(keyword,"green-primary") == 0)
781 {
782 flags=ParseGeometry(options,&geometry_info);
783 image->chromaticity.green_primary.x=geometry_info.rho;
784 image->chromaticity.green_primary.y=geometry_info.sigma;
785 if ((flags & SigmaValue) == 0)
786 image->chromaticity.green_primary.y=
787 image->chromaticity.green_primary.x;
788 break;
789 }
cristyd15e6592011-10-15 00:13:06 +0000790 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000791 break;
792 }
793 case 'i':
794 case 'I':
795 {
796 if (LocaleCompare(keyword,"id") == 0)
797 {
798 (void) CopyMagickString(id,options,MaxTextExtent);
799 break;
800 }
801 if (LocaleCompare(keyword,"iterations") == 0)
802 {
cristye27293e2009-12-18 02:53:20 +0000803 image->iterations=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000804 break;
805 }
cristyd15e6592011-10-15 00:13:06 +0000806 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000807 break;
808 }
809 case 'm':
810 case 'M':
811 {
812 if (LocaleCompare(keyword,"matte") == 0)
813 {
cristybb503372010-05-27 20:51:26 +0000814 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000815 matte;
816
cristy042ee782011-04-22 18:48:30 +0000817 matte=ParseCommandOption(MagickBooleanOptions,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000818 options);
819 if (matte < 0)
820 break;
821 image->matte=(MagickBooleanType) matte;
822 break;
823 }
824 if (LocaleCompare(keyword,"matte-color") == 0)
825 {
cristy9950d572011-10-01 18:22:35 +0000826 (void) QueryColorCompliance(options,AllCompliance,
827 &image->matte_color,exception);
cristy3ed852e2009-09-05 21:47:34 +0000828 break;
829 }
830 if (LocaleCompare(keyword,"montage") == 0)
831 {
832 (void) CloneString(&image->montage,options);
833 break;
834 }
cristyd15e6592011-10-15 00:13:06 +0000835 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000836 break;
837 }
838 case 'o':
839 case 'O':
840 {
841 if (LocaleCompare(keyword,"opaque") == 0)
842 {
cristybb503372010-05-27 20:51:26 +0000843 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000844 matte;
845
cristy042ee782011-04-22 18:48:30 +0000846 matte=ParseCommandOption(MagickBooleanOptions,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000847 options);
848 if (matte < 0)
849 break;
850 image->matte=(MagickBooleanType) matte;
851 break;
852 }
853 if (LocaleCompare(keyword,"orientation") == 0)
854 {
cristybb503372010-05-27 20:51:26 +0000855 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000856 orientation;
857
cristy042ee782011-04-22 18:48:30 +0000858 orientation=ParseCommandOption(MagickOrientationOptions,
cristy3ed852e2009-09-05 21:47:34 +0000859 MagickFalse,options);
860 if (orientation < 0)
861 break;
862 image->orientation=(OrientationType) orientation;
863 break;
864 }
cristyd15e6592011-10-15 00:13:06 +0000865 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000866 break;
867 }
868 case 'p':
869 case 'P':
870 {
871 if (LocaleCompare(keyword,"page") == 0)
872 {
873 char
874 *geometry;
875
876 geometry=GetPageGeometry(options);
877 (void) ParseAbsoluteGeometry(geometry,&image->page);
878 geometry=DestroyString(geometry);
879 break;
880 }
881 if ((LocaleNCompare(keyword,"profile:",8) == 0) ||
882 (LocaleNCompare(keyword,"profile-",8) == 0))
883 {
884 StringInfo
885 *profile;
886
887 if (profiles == (LinkedListInfo *) NULL)
888 profiles=NewLinkedList(0);
889 (void) AppendValueToLinkedList(profiles,
890 AcquireString(keyword+8));
cristy63f9b8e2011-09-01 13:40:50 +0000891 profile=BlobToStringInfo((const void *) NULL,(size_t)
892 StringToLong(options));
cristy49f5e9f2011-09-01 13:44:57 +0000893 if (profile == (StringInfo *) NULL)
cristy63f9b8e2011-09-01 13:40:50 +0000894 ThrowReaderException(ResourceLimitError,
895 "MemoryAllocationFailed");
cristyd15e6592011-10-15 00:13:06 +0000896 (void) SetImageProfile(image,keyword+8,profile,exception);
cristy3ed852e2009-09-05 21:47:34 +0000897 profile=DestroyStringInfo(profile);
898 break;
899 }
cristyd15e6592011-10-15 00:13:06 +0000900 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000901 break;
902 }
903 case 'q':
904 case 'Q':
905 {
906 if (LocaleCompare(keyword,"quality") == 0)
907 {
cristye27293e2009-12-18 02:53:20 +0000908 image->quality=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000909 break;
910 }
911 if ((LocaleCompare(keyword,"quantum-format") == 0) ||
912 (LocaleCompare(keyword,"quantum:format") == 0))
913 {
cristybb503372010-05-27 20:51:26 +0000914 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000915 format;
916
cristy042ee782011-04-22 18:48:30 +0000917 format=ParseCommandOption(MagickQuantumFormatOptions,
cristy3ed852e2009-09-05 21:47:34 +0000918 MagickFalse,options);
919 if (format < 0)
920 break;
921 quantum_format=(QuantumFormatType) format;
922 break;
923 }
cristyd15e6592011-10-15 00:13:06 +0000924 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000925 break;
926 }
927 case 'r':
928 case 'R':
929 {
930 if (LocaleCompare(keyword,"red-primary") == 0)
931 {
932 flags=ParseGeometry(options,&geometry_info);
933 image->chromaticity.red_primary.x=geometry_info.rho;
934 image->chromaticity.red_primary.y=geometry_info.sigma;
935 if ((flags & SigmaValue) == 0)
936 image->chromaticity.red_primary.y=
937 image->chromaticity.red_primary.x;
938 break;
939 }
940 if (LocaleCompare(keyword,"rendering-intent") == 0)
941 {
cristybb503372010-05-27 20:51:26 +0000942 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000943 rendering_intent;
944
cristy042ee782011-04-22 18:48:30 +0000945 rendering_intent=ParseCommandOption(MagickIntentOptions,
cristy3ed852e2009-09-05 21:47:34 +0000946 MagickFalse,options);
947 if (rendering_intent < 0)
948 break;
949 image->rendering_intent=(RenderingIntent) rendering_intent;
950 break;
951 }
952 if (LocaleCompare(keyword,"resolution") == 0)
953 {
954 flags=ParseGeometry(options,&geometry_info);
cristy2a11bef2011-10-28 18:33:11 +0000955 image->resolution.x=geometry_info.rho;
956 image->resolution.y=geometry_info.sigma;
cristy3ed852e2009-09-05 21:47:34 +0000957 if ((flags & SigmaValue) == 0)
cristy2a11bef2011-10-28 18:33:11 +0000958 image->resolution.y=image->resolution.x;
cristy3ed852e2009-09-05 21:47:34 +0000959 break;
960 }
961 if (LocaleCompare(keyword,"rows") == 0)
962 {
cristye27293e2009-12-18 02:53:20 +0000963 image->rows=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000964 break;
965 }
cristyd15e6592011-10-15 00:13:06 +0000966 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000967 break;
968 }
969 case 's':
970 case 'S':
971 {
972 if (LocaleCompare(keyword,"scene") == 0)
973 {
cristye27293e2009-12-18 02:53:20 +0000974 image->scene=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000975 break;
976 }
cristyd15e6592011-10-15 00:13:06 +0000977 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000978 break;
979 }
980 case 't':
981 case 'T':
982 {
983 if (LocaleCompare(keyword,"ticks-per-second") == 0)
984 {
cristy15893a42010-11-20 18:57:15 +0000985 image->ticks_per_second=(ssize_t) StringToLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000986 break;
987 }
988 if (LocaleCompare(keyword,"tile-offset") == 0)
989 {
990 char
991 *geometry;
992
993 geometry=GetPageGeometry(options);
994 (void) ParseAbsoluteGeometry(geometry,&image->tile_offset);
995 geometry=DestroyString(geometry);
996 break;
997 }
998 if (LocaleCompare(keyword,"type") == 0)
999 {
cristybb503372010-05-27 20:51:26 +00001000 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001001 type;
1002
cristy042ee782011-04-22 18:48:30 +00001003 type=ParseCommandOption(MagickTypeOptions,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +00001004 options);
1005 if (type < 0)
1006 break;
1007 image->type=(ImageType) type;
1008 break;
1009 }
cristyd15e6592011-10-15 00:13:06 +00001010 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +00001011 break;
1012 }
1013 case 'u':
1014 case 'U':
1015 {
1016 if (LocaleCompare(keyword,"units") == 0)
1017 {
cristybb503372010-05-27 20:51:26 +00001018 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001019 units;
1020
cristyfbbafc92011-05-05 01:22:11 +00001021 units=ParseCommandOption(MagickResolutionOptions,
1022 MagickFalse,options);
cristy3ed852e2009-09-05 21:47:34 +00001023 if (units < 0)
1024 break;
1025 image->units=(ResolutionType) units;
1026 break;
1027 }
cristyd15e6592011-10-15 00:13:06 +00001028 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +00001029 break;
1030 }
1031 case 'v':
1032 case 'V':
1033 {
1034 if (LocaleCompare(keyword,"version") == 0)
1035 {
cristydbdd0e32011-11-04 23:29:40 +00001036 version=StringToDouble(options,(char **) NULL);
cristy3ed852e2009-09-05 21:47:34 +00001037 break;
1038 }
cristyd15e6592011-10-15 00:13:06 +00001039 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +00001040 break;
1041 }
1042 case 'w':
1043 case 'W':
1044 {
1045 if (LocaleCompare(keyword,"white-point") == 0)
1046 {
1047 flags=ParseGeometry(options,&geometry_info);
1048 image->chromaticity.white_point.x=geometry_info.rho;
cristy37f88d92012-05-04 11:14:52 +00001049 image->chromaticity.white_point.y=geometry_info.sigma;
cristy3ed852e2009-09-05 21:47:34 +00001050 if ((flags & SigmaValue) != 0)
1051 image->chromaticity.white_point.y=
1052 image->chromaticity.white_point.x;
1053 break;
1054 }
cristyd15e6592011-10-15 00:13:06 +00001055 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +00001056 break;
1057 }
1058 default:
1059 {
cristyd15e6592011-10-15 00:13:06 +00001060 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +00001061 break;
1062 }
1063 }
1064 }
1065 else
1066 c=ReadBlobByte(image);
1067 while (isspace((int) ((unsigned char) c)) != 0)
1068 c=ReadBlobByte(image);
1069 }
1070 options=DestroyString(options);
1071 (void) ReadBlobByte(image);
1072 /*
1073 Verify that required image information is defined.
1074 */
1075 if ((LocaleCompare(id,"ImageMagick") != 0) ||
1076 (image->storage_class == UndefinedClass) ||
1077 (image->columns == 0) || (image->rows == 0))
1078 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1079 if (image->montage != (char *) NULL)
1080 {
1081 register char
1082 *p;
1083
1084 /*
1085 Image directory.
1086 */
1087 length=MaxTextExtent;
1088 image->directory=AcquireString((char *) NULL);
1089 p=image->directory;
1090 do
1091 {
1092 *p='\0';
1093 if ((strlen(image->directory)+MaxTextExtent) >= length)
1094 {
1095 /*
1096 Allocate more memory for the image directory.
1097 */
1098 length<<=1;
1099 image->directory=(char *) ResizeQuantumMemory(image->directory,
1100 length+MaxTextExtent,sizeof(*image->directory));
1101 if (image->directory == (char *) NULL)
1102 ThrowReaderException(CorruptImageError,"UnableToReadImageData");
1103 p=image->directory+strlen(image->directory);
1104 }
1105 c=ReadBlobByte(image);
1106 *p++=(char) c;
1107 } while (c != (int) '\0');
1108 }
1109 if (profiles != (LinkedListInfo *) NULL)
1110 {
1111 const char
1112 *name;
1113
1114 const StringInfo
1115 *profile;
1116
1117 /*
1118 Read image profiles.
1119 */
1120 ResetLinkedListIterator(profiles);
1121 name=(const char *) GetNextValueInLinkedList(profiles);
1122 while (name != (const char *) NULL)
1123 {
1124 profile=GetImageProfile(image,name);
1125 if (profile != (StringInfo *) NULL)
1126 {
1127 register unsigned char
1128 *p;
1129
1130 p=GetStringInfoDatum(profile);
1131 count=ReadBlob(image,GetStringInfoLength(profile),p);
cristyda16f162011-02-19 23:52:17 +00001132 (void) count;
cristy3ed852e2009-09-05 21:47:34 +00001133 }
1134 name=(const char *) GetNextValueInLinkedList(profiles);
1135 }
1136 profiles=DestroyLinkedList(profiles,RelinquishMagickMemory);
1137 }
1138 image->depth=GetImageQuantumDepth(image,MagickFalse);
1139 if (image->storage_class == PseudoClass)
1140 {
1141 /*
1142 Create image colormap.
1143 */
cristy018f07f2011-09-04 21:15:19 +00001144 status=AcquireImageColormap(image,colors != 0 ? colors : 256,exception);
cristy3ed852e2009-09-05 21:47:34 +00001145 if (status == MagickFalse)
1146 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1147 if (colors != 0)
1148 {
1149 size_t
1150 packet_size;
1151
1152 unsigned char
1153 *colormap;
1154
1155 /*
1156 Read image colormap from file.
1157 */
1158 packet_size=(size_t) (3UL*image->depth/8UL);
1159 colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
1160 packet_size*sizeof(*colormap));
1161 if (colormap == (unsigned char *) NULL)
1162 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1163 count=ReadBlob(image,packet_size*image->colors,colormap);
1164 p=colormap;
1165 switch (image->depth)
1166 {
1167 default:
1168 ThrowReaderException(CorruptImageError,
1169 "ImageDepthNotSupported");
1170 case 8:
1171 {
1172 unsigned char
1173 pixel;
1174
cristybb503372010-05-27 20:51:26 +00001175 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00001176 {
1177 p=PushCharPixel(p,&pixel);
1178 image->colormap[i].red=ScaleCharToQuantum(pixel);
1179 p=PushCharPixel(p,&pixel);
1180 image->colormap[i].green=ScaleCharToQuantum(pixel);
1181 p=PushCharPixel(p,&pixel);
1182 image->colormap[i].blue=ScaleCharToQuantum(pixel);
1183 }
1184 break;
1185 }
1186 case 16:
1187 {
1188 unsigned short
1189 pixel;
1190
cristybb503372010-05-27 20:51:26 +00001191 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00001192 {
1193 p=PushShortPixel(MSBEndian,p,&pixel);
1194 image->colormap[i].red=ScaleShortToQuantum(pixel);
1195 p=PushShortPixel(MSBEndian,p,&pixel);
1196 image->colormap[i].green=ScaleShortToQuantum(pixel);
1197 p=PushShortPixel(MSBEndian,p,&pixel);
1198 image->colormap[i].blue=ScaleShortToQuantum(pixel);
1199 }
1200 break;
1201 }
1202 case 32:
1203 {
cristy4cb162a2010-05-30 03:04:47 +00001204 unsigned int
cristy3ed852e2009-09-05 21:47:34 +00001205 pixel;
1206
cristybb503372010-05-27 20:51:26 +00001207 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00001208 {
1209 p=PushLongPixel(MSBEndian,p,&pixel);
1210 image->colormap[i].red=ScaleLongToQuantum(pixel);
1211 p=PushLongPixel(MSBEndian,p,&pixel);
1212 image->colormap[i].green=ScaleLongToQuantum(pixel);
1213 p=PushLongPixel(MSBEndian,p,&pixel);
1214 image->colormap[i].blue=ScaleLongToQuantum(pixel);
1215 }
1216 break;
1217 }
1218 }
1219 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1220 }
1221 }
1222 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
1223 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1224 break;
1225 /*
1226 Allocate image pixels.
1227 */
1228 quantum_info=AcquireQuantumInfo(image_info,image);
1229 if (quantum_info == (QuantumInfo *) NULL)
1230 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1231 if (quantum_format != UndefinedQuantumFormat)
1232 {
1233 status=SetQuantumFormat(image,quantum_info,quantum_format);
1234 if (status == MagickFalse)
1235 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1236 }
1237 packet_size=(size_t) (quantum_info->depth/8);
1238 if (image->storage_class == DirectClass)
1239 packet_size=(size_t) (3*quantum_info->depth/8);
cristy325cfdc2012-04-28 01:00:09 +00001240 if (IsGrayColorspace(image->colorspace) != MagickFalse)
cristy0a30e182011-09-01 01:43:15 +00001241 packet_size=quantum_info->depth/8;
cristy3ed852e2009-09-05 21:47:34 +00001242 if (image->matte != MagickFalse)
1243 packet_size+=quantum_info->depth/8;
1244 if (image->colorspace == CMYKColorspace)
1245 packet_size+=quantum_info->depth/8;
1246 if (image->compression == RLECompression)
1247 packet_size++;
1248 length=image->columns;
cristy26377172010-12-20 19:01:58 +00001249 length=MagickMax(MagickMax(BZipMaxExtent(packet_size*image->columns),
1250 LZMAMaxExtent(packet_size*image->columns)),ZipMaxExtent(packet_size*
1251 image->columns));
cristy3ed852e2009-09-05 21:47:34 +00001252 compress_pixels=(unsigned char *) AcquireQuantumMemory(length,
1253 sizeof(*compress_pixels));
1254 if (compress_pixels == (unsigned char *) NULL)
1255 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1256 /*
1257 Read image pixels.
1258 */
1259 quantum_type=RGBQuantum;
1260 if (image->matte != MagickFalse)
1261 quantum_type=RGBAQuantum;
1262 if (image->colorspace == CMYKColorspace)
1263 {
1264 quantum_type=CMYKQuantum;
1265 if (image->matte != MagickFalse)
1266 quantum_type=CMYKAQuantum;
1267 }
cristy325cfdc2012-04-28 01:00:09 +00001268 if (IsGrayColorspace(image->colorspace) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001269 {
1270 quantum_type=GrayQuantum;
1271 if (image->matte != MagickFalse)
1272 quantum_type=GrayAlphaQuantum;
1273 }
cristybdbf4b62012-05-13 22:22:59 +00001274 if (image->storage_class == PseudoClass)
1275 {
1276 quantum_type=IndexQuantum;
1277 if (image->matte != MagickFalse)
1278 quantum_type=IndexAlphaQuantum;
1279 }
cristy330af6c2010-12-21 14:36:06 +00001280 status=MagickTrue;
1281 switch (image->compression)
1282 {
1283#if defined(MAGICKCORE_BZLIB_DELEGATE)
1284 case BZipCompression:
1285 {
cristy3a99dcf2011-12-17 01:29:40 +00001286 int
1287 code;
1288
cristy330af6c2010-12-21 14:36:06 +00001289 (void) ResetMagickMemory(&bzip_info,0,sizeof(bzip_info));
1290 bzip_info.bzalloc=AcquireBZIPMemory;
1291 bzip_info.bzfree=RelinquishBZIPMemory;
1292 bzip_info.opaque=(void *) NULL;
1293 code=BZ2_bzDecompressInit(&bzip_info,(int) image_info->verbose,
1294 MagickFalse);
1295 if (code != BZ_OK)
1296 status=MagickFalse;
cristy330af6c2010-12-21 14:36:06 +00001297 break;
1298 }
1299#endif
1300#if defined(MAGICKCORE_LZMA_DELEGATE)
1301 case LZMACompression:
1302 {
cristy3a99dcf2011-12-17 01:29:40 +00001303 int
1304 code;
1305
cristy9d72f1a2010-12-21 20:46:59 +00001306 (void) ResetMagickMemory(&allocator,0,sizeof(allocator));
1307 allocator.alloc=AcquireLZMAMemory;
1308 allocator.free=RelinquishLZMAMemory;
cristy330af6c2010-12-21 14:36:06 +00001309 lzma_info=initialize_lzma;
cristy9d72f1a2010-12-21 20:46:59 +00001310 lzma_info.allocator=(&allocator);
cristy330af6c2010-12-21 14:36:06 +00001311 code=lzma_auto_decoder(&lzma_info,-1,0);
1312 if (code != LZMA_OK)
1313 status=MagickFalse;
cristy330af6c2010-12-21 14:36:06 +00001314 break;
1315 }
1316#endif
1317#if defined(MAGICKCORE_ZLIB_DELEGATE)
1318 case LZWCompression:
1319 case ZipCompression:
1320 {
cristy3a99dcf2011-12-17 01:29:40 +00001321 int
1322 code;
1323
cristy330af6c2010-12-21 14:36:06 +00001324 (void) ResetMagickMemory(&zip_info,0,sizeof(zip_info));
1325 zip_info.zalloc=AcquireZIPMemory;
1326 zip_info.zfree=RelinquishZIPMemory;
1327 zip_info.opaque=(voidpf) NULL;
1328 code=inflateInit(&zip_info);
1329 if (code != Z_OK)
1330 status=MagickFalse;
cristy330af6c2010-12-21 14:36:06 +00001331 break;
1332 }
1333#endif
1334 case RLECompression:
1335 {
cristy4c08aed2011-07-01 19:47:50 +00001336 GetPixelInfo(image,&pixel);
cristy330af6c2010-12-21 14:36:06 +00001337 break;
1338 }
1339 default:
1340 break;
1341 }
cristy3ed852e2009-09-05 21:47:34 +00001342 pixels=GetQuantumPixels(quantum_info);
cristy3ed852e2009-09-05 21:47:34 +00001343 length=0;
cristybb503372010-05-27 20:51:26 +00001344 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001345 {
cristybb503372010-05-27 20:51:26 +00001346 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001347 x;
1348
cristy4c08aed2011-07-01 19:47:50 +00001349 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00001350 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00001351
cristy330af6c2010-12-21 14:36:06 +00001352 if (status == MagickFalse)
1353 break;
cristy3ed852e2009-09-05 21:47:34 +00001354 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +00001355 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001356 break;
cristy3ed852e2009-09-05 21:47:34 +00001357 switch (image->compression)
1358 {
cristy3ed852e2009-09-05 21:47:34 +00001359#if defined(MAGICKCORE_BZLIB_DELEGATE)
1360 case BZipCompression:
1361 {
cristy3ed852e2009-09-05 21:47:34 +00001362 bzip_info.next_out=(char *) pixels;
1363 bzip_info.avail_out=(unsigned int) (packet_size*image->columns);
1364 do
1365 {
1366 if (bzip_info.avail_in == 0)
1367 {
1368 bzip_info.next_in=(char *) compress_pixels;
1369 length=(size_t) BZipMaxExtent(packet_size*image->columns);
cristy261ce822012-02-19 22:08:28 +00001370 if (version != 0.0)
cristy3ed852e2009-09-05 21:47:34 +00001371 length=(size_t) ReadBlobMSBLong(image);
1372 bzip_info.avail_in=(unsigned int) ReadBlob(image,length,
1373 (unsigned char *) bzip_info.next_in);
1374 }
1375 if (BZ2_bzDecompress(&bzip_info) == BZ_STREAM_END)
1376 break;
1377 } while (bzip_info.avail_out != 0);
cristy26377172010-12-20 19:01:58 +00001378 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1379 quantum_type,pixels,exception);
1380 break;
1381 }
1382#endif
1383#if defined(MAGICKCORE_LZMA_DELEGATE)
1384 case LZMACompression:
1385 {
cristy26377172010-12-20 19:01:58 +00001386 lzma_info.next_out=pixels;
cristy330af6c2010-12-21 14:36:06 +00001387 lzma_info.avail_out=packet_size*image->columns;
cristy26377172010-12-20 19:01:58 +00001388 do
1389 {
cristy3a99dcf2011-12-17 01:29:40 +00001390 int
1391 code;
1392
cristy26377172010-12-20 19:01:58 +00001393 if (lzma_info.avail_in == 0)
1394 {
1395 lzma_info.next_in=compress_pixels;
1396 length=(size_t) ReadBlobMSBLong(image);
1397 lzma_info.avail_in=(unsigned int) ReadBlob(image,length,
1398 (unsigned char *) lzma_info.next_in);
1399 }
1400 code=lzma_code(&lzma_info,LZMA_RUN);
cristy330af6c2010-12-21 14:36:06 +00001401 if (code < 0)
1402 {
1403 status=MagickFalse;
1404 break;
1405 }
1406 if (code == LZMA_STREAM_END)
cristy26377172010-12-20 19:01:58 +00001407 break;
1408 } while (lzma_info.avail_out != 0);
cristy26377172010-12-20 19:01:58 +00001409 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1410 quantum_type,pixels,exception);
1411 break;
1412 }
1413#endif
1414#if defined(MAGICKCORE_ZLIB_DELEGATE)
1415 case LZWCompression:
1416 case ZipCompression:
1417 {
cristy26377172010-12-20 19:01:58 +00001418 zip_info.next_out=pixels;
1419 zip_info.avail_out=(uInt) (packet_size*image->columns);
1420 do
1421 {
1422 if (zip_info.avail_in == 0)
1423 {
1424 zip_info.next_in=compress_pixels;
1425 length=(size_t) ZipMaxExtent(packet_size*image->columns);
cristy261ce822012-02-19 22:08:28 +00001426 if (version != 0.0)
cristy26377172010-12-20 19:01:58 +00001427 length=(size_t) ReadBlobMSBLong(image);
1428 zip_info.avail_in=(unsigned int) ReadBlob(image,length,
1429 zip_info.next_in);
1430 }
1431 if (inflate(&zip_info,Z_SYNC_FLUSH) == Z_STREAM_END)
1432 break;
1433 } while (zip_info.avail_out != 0);
cristy3ed852e2009-09-05 21:47:34 +00001434 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1435 quantum_type,pixels,exception);
1436 break;
1437 }
1438#endif
1439 case RLECompression:
1440 {
cristybb503372010-05-27 20:51:26 +00001441 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001442 {
1443 if (length == 0)
1444 {
1445 count=ReadBlob(image,packet_size,pixels);
cristyc82a27b2011-10-21 01:07:16 +00001446 PushRunlengthPacket(image,pixels,&length,&pixel,exception);
cristy3ed852e2009-09-05 21:47:34 +00001447 }
1448 length--;
cristy4c08aed2011-07-01 19:47:50 +00001449 if (image->storage_class == PseudoClass)
cristy94b11832011-09-08 19:46:03 +00001450 SetPixelIndex(image,ClampToQuantum(pixel.index),q);
cristy4c08aed2011-07-01 19:47:50 +00001451 else
1452 {
cristy94b11832011-09-08 19:46:03 +00001453 SetPixelRed(image,ClampToQuantum(pixel.red),q);
1454 SetPixelGreen(image,ClampToQuantum(pixel.green),q);
1455 SetPixelBlue(image,ClampToQuantum(pixel.blue),q);
cristy4c08aed2011-07-01 19:47:50 +00001456 if (image->colorspace == CMYKColorspace)
cristy94b11832011-09-08 19:46:03 +00001457 SetPixelBlack(image,ClampToQuantum(pixel.black),q);
cristy4c08aed2011-07-01 19:47:50 +00001458 }
1459 if (image->matte != MagickFalse)
cristy94b11832011-09-08 19:46:03 +00001460 SetPixelAlpha(image,ClampToQuantum(pixel.alpha),q);
cristyed231572011-07-14 02:18:59 +00001461 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001462 }
1463 break;
1464 }
1465 default:
1466 {
1467 count=ReadBlob(image,packet_size*image->columns,pixels);
1468 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1469 quantum_type,pixels,exception);
1470 break;
1471 }
1472 }
1473 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1474 break;
1475 }
1476 SetQuantumImageType(image,quantum_type);
cristy330af6c2010-12-21 14:36:06 +00001477 switch (image->compression)
1478 {
1479#if defined(MAGICKCORE_BZLIB_DELEGATE)
1480 case BZipCompression:
1481 {
cristy3a99dcf2011-12-17 01:29:40 +00001482 int
1483 code;
1484
cristy261ce822012-02-19 22:08:28 +00001485 if (version == 0.0)
cristy330af6c2010-12-21 14:36:06 +00001486 {
1487 MagickOffsetType
1488 offset;
1489
1490 offset=SeekBlob(image,-((MagickOffsetType)
1491 bzip_info.avail_in),SEEK_CUR);
1492 if (offset < 0)
1493 ThrowReaderException(CorruptImageError,
1494 "ImproperImageHeader");
1495 }
1496 code=BZ2_bzDecompressEnd(&bzip_info);
1497 if (code != BZ_OK)
1498 status=MagickFalse;
1499 break;
1500 }
1501#endif
1502#if defined(MAGICKCORE_LZMA_DELEGATE)
1503 case LZMACompression:
1504 {
cristy3a99dcf2011-12-17 01:29:40 +00001505 int
1506 code;
1507
cristy3b788a02010-12-27 15:59:54 +00001508 code=lzma_code(&lzma_info,LZMA_FINISH);
1509 if ((code != LZMA_STREAM_END) && (code != LZMA_OK))
cristyb977da52010-12-22 15:55:53 +00001510 status=MagickFalse;
cristy330af6c2010-12-21 14:36:06 +00001511 lzma_end(&lzma_info);
1512 break;
1513 }
1514#endif
1515#if defined(MAGICKCORE_ZLIB_DELEGATE)
1516 case LZWCompression:
1517 case ZipCompression:
1518 {
cristy3a99dcf2011-12-17 01:29:40 +00001519 int
1520 code;
1521
cristy261ce822012-02-19 22:08:28 +00001522 if (version == 0.0)
cristy330af6c2010-12-21 14:36:06 +00001523 {
1524 MagickOffsetType
1525 offset;
1526
1527 offset=SeekBlob(image,-((MagickOffsetType) zip_info.avail_in),
1528 SEEK_CUR);
1529 if (offset < 0)
1530 ThrowReaderException(CorruptImageError,
1531 "ImproperImageHeader");
1532 }
1533 code=inflateEnd(&zip_info);
1534 if (code != LZMA_OK)
1535 status=MagickFalse;
1536 break;
1537 }
1538#endif
1539 default:
1540 break;
1541 }
cristy3ed852e2009-09-05 21:47:34 +00001542 quantum_info=DestroyQuantumInfo(quantum_info);
1543 compress_pixels=(unsigned char *) RelinquishMagickMemory(compress_pixels);
cristybb503372010-05-27 20:51:26 +00001544 if (((y != (ssize_t) image->rows)) || (status == MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00001545 {
1546 image=DestroyImageList(image);
1547 return((Image *) NULL);
1548 }
1549 if (EOFBlob(image) != MagickFalse)
1550 {
1551 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
1552 image->filename);
1553 break;
1554 }
1555 /*
1556 Proceed to next image.
1557 */
1558 if (image_info->number_scenes != 0)
1559 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1560 break;
1561 do
1562 {
1563 c=ReadBlobByte(image);
1564 } while ((isgraph(c) == MagickFalse) && (c != EOF));
1565 if (c != EOF)
1566 {
1567 /*
1568 Allocate next image structure.
1569 */
cristy9950d572011-10-01 18:22:35 +00001570 AcquireNextImage(image_info,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00001571 if (GetNextImageInList(image) == (Image *) NULL)
1572 {
1573 image=DestroyImageList(image);
1574 return((Image *) NULL);
1575 }
1576 image=SyncNextImageInList(image);
1577 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
1578 GetBlobSize(image));
1579 if (status == MagickFalse)
1580 break;
1581 }
1582 } while (c != EOF);
1583 (void) CloseBlob(image);
1584 return(GetFirstImageInList(image));
1585}
1586
1587/*
1588%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1589% %
1590% %
1591% %
1592% R e g i s t e r M I F F I m a g e %
1593% %
1594% %
1595% %
1596%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1597%
1598% RegisterMIFFImage() adds properties for the MIFF image format to the list of
1599% supported formats. The properties include the image format tag, a method to
1600% read and/or write the format, whether the format supports the saving of more
1601% than one frame to the same file or blob, whether the format supports native
1602% in-memory I/O, and a brief description of the format.
1603%
1604% The format of the RegisterMIFFImage method is:
1605%
cristybb503372010-05-27 20:51:26 +00001606% size_t RegisterMIFFImage(void)
cristy3ed852e2009-09-05 21:47:34 +00001607%
1608*/
cristybb503372010-05-27 20:51:26 +00001609ModuleExport size_t RegisterMIFFImage(void)
cristy3ed852e2009-09-05 21:47:34 +00001610{
1611 char
1612 version[MaxTextExtent];
1613
1614 MagickInfo
1615 *entry;
1616
1617 *version='\0';
1618#if defined(MagickImageCoderSignatureText)
1619 (void) CopyMagickString(version,MagickLibVersionText,MaxTextExtent);
1620#if defined(ZLIB_VERSION)
1621 (void) ConcatenateMagickString(version," with Zlib ",MaxTextExtent);
1622 (void) ConcatenateMagickString(version,ZLIB_VERSION,MaxTextExtent);
1623#endif
1624#if defined(MAGICKCORE_BZLIB_DELEGATE)
1625 (void) ConcatenateMagickString(version," and BZlib",MaxTextExtent);
1626#endif
1627#endif
1628 entry=SetMagickInfo("MIFF");
1629 entry->decoder=(DecodeImageHandler *) ReadMIFFImage;
1630 entry->encoder=(EncodeImageHandler *) WriteMIFFImage;
1631 entry->magick=(IsImageFormatHandler *) IsMIFF;
cristyffaf9782011-04-13 19:50:51 +00001632 entry->seekable_stream=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +00001633 entry->description=ConstantString("Magick Image File Format");
1634 if (*version != '\0')
1635 entry->version=ConstantString(version);
1636 entry->module=ConstantString("MIFF");
1637 (void) RegisterMagickInfo(entry);
1638 return(MagickImageCoderSignature);
1639}
1640
1641/*
1642%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1643% %
1644% %
1645% %
1646% U n r e g i s t e r M I F F I m a g e %
1647% %
1648% %
1649% %
1650%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1651%
1652% UnregisterMIFFImage() removes format registrations made by the MIFF module
1653% from the list of supported formats.
1654%
1655% The format of the UnregisterMIFFImage method is:
1656%
1657% UnregisterMIFFImage(void)
1658%
1659*/
1660ModuleExport void UnregisterMIFFImage(void)
1661{
1662 (void) UnregisterMagickInfo("MIFF");
1663}
1664
1665/*
1666%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1667% %
1668% %
1669% %
1670% W r i t e M I F F I m a g e %
1671% %
1672% %
1673% %
1674%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1675%
1676% WriteMIFFImage() writes a MIFF image to a file.
1677%
1678% The format of the WriteMIFFImage method is:
1679%
1680% MagickBooleanType WriteMIFFImage(const ImageInfo *image_info,
cristy1e178e72011-08-28 19:44:34 +00001681% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001682%
1683% Compression code contributed by Kyle Shorter.
1684%
1685% A description of each parameter follows:
1686%
1687% o image_info: the image info.
1688%
1689% o image: the image.
1690%
cristy1e178e72011-08-28 19:44:34 +00001691% o exception: return any errors or warnings in this structure.
1692%
cristy3ed852e2009-09-05 21:47:34 +00001693*/
1694
1695static unsigned char *PopRunlengthPacket(Image *image,unsigned char *pixels,
cristyc82a27b2011-10-21 01:07:16 +00001696 size_t length,PixelInfo *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001697{
1698 if (image->storage_class != DirectClass)
1699 {
1700 switch (image->depth)
1701 {
1702 case 32:
1703 {
cristy4c08aed2011-07-01 19:47:50 +00001704 *pixels++=(unsigned char) ((size_t) pixel->index >> 24);
1705 *pixels++=(unsigned char) ((size_t) pixel->index >> 16);
cristy3ed852e2009-09-05 21:47:34 +00001706 }
1707 case 16:
cristy4c08aed2011-07-01 19:47:50 +00001708 *pixels++=(unsigned char) ((size_t) pixel->index >> 8);
cristy3ed852e2009-09-05 21:47:34 +00001709 case 8:
1710 {
cristy4c08aed2011-07-01 19:47:50 +00001711 *pixels++=(unsigned char) pixel->index;
cristy3ed852e2009-09-05 21:47:34 +00001712 break;
1713 }
1714 default:
cristyc82a27b2011-10-21 01:07:16 +00001715 (void) ThrowMagickException(exception,GetMagickModule(),
cristy3ed852e2009-09-05 21:47:34 +00001716 CorruptImageError,"ImageDepthNotSupported","`%s'",image->filename);
1717 }
1718 switch (image->depth)
1719 {
1720 case 32:
1721 {
cristy4cb162a2010-05-30 03:04:47 +00001722 unsigned int
cristy3ed852e2009-09-05 21:47:34 +00001723 value;
1724
1725 if (image->matte != MagickFalse)
1726 {
cristy94b11832011-09-08 19:46:03 +00001727 value=ScaleQuantumToLong(ClampToQuantum(pixel->alpha));
cristy3ed852e2009-09-05 21:47:34 +00001728 pixels=PopLongPixel(MSBEndian,value,pixels);
1729 }
1730 break;
1731 }
1732 case 16:
1733 {
1734 unsigned short
1735 value;
1736
1737 if (image->matte != MagickFalse)
1738 {
cristy94b11832011-09-08 19:46:03 +00001739 value=ScaleQuantumToShort(ClampToQuantum(pixel->alpha));
cristy3ed852e2009-09-05 21:47:34 +00001740 pixels=PopShortPixel(MSBEndian,value,pixels);
1741 }
1742 break;
1743 }
1744 case 8:
1745 {
1746 unsigned char
1747 value;
1748
1749 if (image->matte != MagickFalse)
1750 {
cristy94b11832011-09-08 19:46:03 +00001751 value=(unsigned char) ScaleQuantumToChar(ClampToQuantum(
1752 pixel->alpha));
cristy3ed852e2009-09-05 21:47:34 +00001753 pixels=PopCharPixel(value,pixels);
1754 }
1755 break;
1756 }
1757 default:
cristyc82a27b2011-10-21 01:07:16 +00001758 (void) ThrowMagickException(exception,GetMagickModule(),
cristy3ed852e2009-09-05 21:47:34 +00001759 CorruptImageError,"ImageDepthNotSupported","`%s'",image->filename);
1760 }
1761 *pixels++=(unsigned char) length;
1762 return(pixels);
1763 }
1764 switch (image->depth)
1765 {
1766 case 32:
1767 {
cristy4cb162a2010-05-30 03:04:47 +00001768 unsigned int
cristy3ed852e2009-09-05 21:47:34 +00001769 value;
1770
cristy94b11832011-09-08 19:46:03 +00001771 value=ScaleQuantumToLong(ClampToQuantum(pixel->red));
cristy3ed852e2009-09-05 21:47:34 +00001772 pixels=PopLongPixel(MSBEndian,value,pixels);
cristy325cfdc2012-04-28 01:00:09 +00001773 if (IsGrayColorspace(image->colorspace) == MagickFalse)
1774 {
1775 value=ScaleQuantumToLong(ClampToQuantum(pixel->green));
1776 pixels=PopLongPixel(MSBEndian,value,pixels);
1777 value=ScaleQuantumToLong(ClampToQuantum(pixel->blue));
1778 pixels=PopLongPixel(MSBEndian,value,pixels);
1779 }
cristy3ed852e2009-09-05 21:47:34 +00001780 if (image->colorspace == CMYKColorspace)
1781 {
cristy94b11832011-09-08 19:46:03 +00001782 value=ScaleQuantumToLong(ClampToQuantum(pixel->black));
cristy4c08aed2011-07-01 19:47:50 +00001783 pixels=PopLongPixel(MSBEndian,value,pixels);
1784 }
1785 if (image->matte != MagickFalse)
1786 {
cristy94b11832011-09-08 19:46:03 +00001787 value=ScaleQuantumToLong(ClampToQuantum(pixel->alpha));
cristy3ed852e2009-09-05 21:47:34 +00001788 pixels=PopLongPixel(MSBEndian,value,pixels);
1789 }
1790 break;
1791 }
1792 case 16:
1793 {
1794 unsigned short
1795 value;
1796
cristy94b11832011-09-08 19:46:03 +00001797 value=ScaleQuantumToShort(ClampToQuantum(pixel->red));
cristy3ed852e2009-09-05 21:47:34 +00001798 pixels=PopShortPixel(MSBEndian,value,pixels);
cristy325cfdc2012-04-28 01:00:09 +00001799 if (IsGrayColorspace(image->colorspace) == MagickFalse)
1800 {
1801 value=ScaleQuantumToShort(ClampToQuantum(pixel->green));
1802 pixels=PopShortPixel(MSBEndian,value,pixels);
1803 value=ScaleQuantumToShort(ClampToQuantum(pixel->blue));
1804 pixels=PopShortPixel(MSBEndian,value,pixels);
1805 }
cristy3ed852e2009-09-05 21:47:34 +00001806 if (image->colorspace == CMYKColorspace)
1807 {
cristy94b11832011-09-08 19:46:03 +00001808 value=ScaleQuantumToShort(ClampToQuantum(pixel->black));
cristy4c08aed2011-07-01 19:47:50 +00001809 pixels=PopShortPixel(MSBEndian,value,pixels);
1810 }
1811 if (image->matte != MagickFalse)
1812 {
cristy94b11832011-09-08 19:46:03 +00001813 value=ScaleQuantumToShort(ClampToQuantum(pixel->alpha));
cristy3ed852e2009-09-05 21:47:34 +00001814 pixels=PopShortPixel(MSBEndian,value,pixels);
1815 }
1816 break;
1817 }
1818 case 8:
1819 {
1820 unsigned char
1821 value;
1822
cristy94b11832011-09-08 19:46:03 +00001823 value=(unsigned char) ScaleQuantumToChar(ClampToQuantum(pixel->red));
cristy3ed852e2009-09-05 21:47:34 +00001824 pixels=PopCharPixel(value,pixels);
cristy325cfdc2012-04-28 01:00:09 +00001825 if (IsGrayColorspace(image->colorspace) == MagickFalse)
1826 {
1827 value=(unsigned char) ScaleQuantumToChar(ClampToQuantum(
1828 pixel->green));
1829 pixels=PopCharPixel(value,pixels);
1830 value=(unsigned char) ScaleQuantumToChar(ClampToQuantum(pixel->blue));
1831 pixels=PopCharPixel(value,pixels);
1832 }
cristy3ed852e2009-09-05 21:47:34 +00001833 if (image->colorspace == CMYKColorspace)
1834 {
cristy94b11832011-09-08 19:46:03 +00001835 value=(unsigned char) ScaleQuantumToChar(ClampToQuantum(
1836 pixel->black));
cristy4c08aed2011-07-01 19:47:50 +00001837 pixels=PopCharPixel(value,pixels);
1838 }
1839 if (image->matte != MagickFalse)
1840 {
cristy94b11832011-09-08 19:46:03 +00001841 value=(unsigned char) ScaleQuantumToChar(ClampToQuantum(
1842 pixel->alpha));
cristy3ed852e2009-09-05 21:47:34 +00001843 pixels=PopCharPixel(value,pixels);
1844 }
1845 break;
1846 }
1847 default:
cristyc82a27b2011-10-21 01:07:16 +00001848 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
1849 "ImageDepthNotSupported","`%s'",image->filename);
cristy3ed852e2009-09-05 21:47:34 +00001850 }
1851 *pixels++=(unsigned char) length;
1852 return(pixels);
1853}
1854
1855static MagickBooleanType WriteMIFFImage(const ImageInfo *image_info,
cristy1e178e72011-08-28 19:44:34 +00001856 Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001857{
1858#if defined(MAGICKCORE_BZLIB_DELEGATE)
1859 bz_stream
1860 bzip_info;
1861#endif
1862
1863 char
1864 buffer[MaxTextExtent];
1865
1866 CompressionType
1867 compression;
1868
1869 const char
1870 *property,
1871 *value;
1872
cristy26377172010-12-20 19:01:58 +00001873#if defined(MAGICKCORE_LZMA_DELEGATE)
cristy4b46dba2010-12-20 19:18:20 +00001874 lzma_allocator
1875 allocator;
1876
cristy26377172010-12-20 19:01:58 +00001877 lzma_stream
cristy330af6c2010-12-21 14:36:06 +00001878 initialize_lzma = LZMA_STREAM_INIT,
1879 lzma_info;
cristy26377172010-12-20 19:01:58 +00001880#endif
cristy3ed852e2009-09-05 21:47:34 +00001881
1882 MagickBooleanType
1883 status;
1884
1885 MagickOffsetType
1886 scene;
1887
cristy4c08aed2011-07-01 19:47:50 +00001888 PixelInfo
1889 pixel,
1890 target;
cristy3ed852e2009-09-05 21:47:34 +00001891
1892 QuantumInfo
1893 *quantum_info;
1894
1895 QuantumType
1896 quantum_type;
1897
cristybb503372010-05-27 20:51:26 +00001898 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001899 i;
1900
1901 size_t
1902 length,
1903 packet_size;
1904
cristy26377172010-12-20 19:01:58 +00001905 ssize_t
1906 y;
1907
cristy3ed852e2009-09-05 21:47:34 +00001908 unsigned char
1909 *compress_pixels,
1910 *pixels,
1911 *q;
1912
1913#if defined(MAGICKCORE_ZLIB_DELEGATE)
1914 z_stream
1915 zip_info;
1916#endif
1917
1918 /*
1919 Open output image file.
1920 */
1921 assert(image_info != (const ImageInfo *) NULL);
1922 assert(image_info->signature == MagickSignature);
1923 assert(image != (Image *) NULL);
1924 assert(image->signature == MagickSignature);
1925 if (image->debug != MagickFalse)
1926 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy3a37efd2011-08-28 20:31:03 +00001927 assert(exception != (ExceptionInfo *) NULL);
1928 assert(exception->signature == MagickSignature);
cristy1e178e72011-08-28 19:44:34 +00001929 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00001930 if (status == MagickFalse)
1931 return(status);
cristy3ed852e2009-09-05 21:47:34 +00001932 scene=0;
1933 do
1934 {
1935 /*
1936 Allocate image pixels.
1937 */
1938 image->depth=image->depth <= 8 ? 8UL : image->depth <= 16 ? 16UL :
1939 image->depth <= 32 ? 32UL : 64UL;
1940 quantum_info=AcquireQuantumInfo(image_info,image);
1941 if (quantum_info == (QuantumInfo *) NULL)
1942 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1943 if ((image->storage_class != PseudoClass) && (image->depth >= 32) &&
1944 (quantum_info->format == UndefinedQuantumFormat) &&
cristy1e178e72011-08-28 19:44:34 +00001945 (IsHighDynamicRangeImage(image,exception) != MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00001946 {
1947 status=SetQuantumFormat(image,quantum_info,FloatingPointQuantumFormat);
1948 if (status == MagickFalse)
1949 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1950 }
1951 if ((image->storage_class == PseudoClass) &&
cristybb503372010-05-27 20:51:26 +00001952 (image->colors > (size_t) (GetQuantumRange(image->depth)+1)))
cristy1e178e72011-08-28 19:44:34 +00001953 (void) SetImageStorageClass(image,DirectClass,exception);
cristy669e5c72011-09-12 12:01:33 +00001954 if (IsImageGray(image,exception) != MagickFalse)
cristy325cfdc2012-04-28 01:00:09 +00001955 (void) SetImageColorspace(image,GRAYColorspace,exception);
cristy3ed852e2009-09-05 21:47:34 +00001956 compression=image->compression;
1957 if (image_info->compression != UndefinedCompression)
1958 compression=image_info->compression;
1959 switch (compression)
1960 {
1961#if !defined(MAGICKCORE_ZLIB_DELEGATE)
cristy26377172010-12-20 19:01:58 +00001962 case LZMACompression: compression=NoCompression; break;
1963#endif
1964#if !defined(MAGICKCORE_ZLIB_DELEGATE)
cristy3ed852e2009-09-05 21:47:34 +00001965 case LZWCompression:
1966 case ZipCompression: compression=NoCompression; break;
1967#endif
1968#if !defined(MAGICKCORE_BZLIB_DELEGATE)
1969 case BZipCompression: compression=NoCompression; break;
1970#endif
1971 case RLECompression:
1972 {
1973 if (quantum_info->format == FloatingPointQuantumFormat)
1974 compression=NoCompression;
cristy4c08aed2011-07-01 19:47:50 +00001975 GetPixelInfo(image,&target);
cristy3ed852e2009-09-05 21:47:34 +00001976 break;
1977 }
1978 default:
1979 break;
1980 }
1981 packet_size=(size_t) (quantum_info->depth/8);
1982 if (image->storage_class == DirectClass)
1983 packet_size=(size_t) (3*quantum_info->depth/8);
cristy325cfdc2012-04-28 01:00:09 +00001984 if (IsGrayColorspace(image->colorspace) != MagickFalse)
cristy0a30e182011-09-01 01:43:15 +00001985 packet_size=(size_t) (quantum_info->depth/8);
cristy3ed852e2009-09-05 21:47:34 +00001986 if (image->matte != MagickFalse)
1987 packet_size+=quantum_info->depth/8;
1988 if (image->colorspace == CMYKColorspace)
1989 packet_size+=quantum_info->depth/8;
1990 if (compression == RLECompression)
1991 packet_size++;
1992 length=image->columns;
1993 length=MagickMax(BZipMaxExtent(packet_size*image->columns),ZipMaxExtent(
1994 packet_size*image->columns));
1995 if ((compression == BZipCompression) || (compression == ZipCompression))
1996 if (length != (size_t) ((unsigned int) length))
1997 compression=NoCompression;
1998 compress_pixels=(unsigned char *) AcquireQuantumMemory(length,
1999 sizeof(*compress_pixels));
2000 if (compress_pixels == (unsigned char *) NULL)
2001 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2002 /*
2003 Write MIFF header.
2004 */
2005 (void) WriteBlobString(image,"id=ImageMagick version=1.0\n");
cristyb51dff52011-05-19 16:55:47 +00002006 (void) FormatLocaleString(buffer,MaxTextExtent,
cristy042ee782011-04-22 18:48:30 +00002007 "class=%s colors=%.20g matte=%s\n",CommandOptionToMnemonic(
cristye8c25f92010-06-03 00:53:06 +00002008 MagickClassOptions,image->storage_class),(double) image->colors,
cristy042ee782011-04-22 18:48:30 +00002009 CommandOptionToMnemonic(MagickBooleanOptions,(ssize_t) image->matte));
cristy3ed852e2009-09-05 21:47:34 +00002010 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00002011 (void) FormatLocaleString(buffer,MaxTextExtent,"columns=%.20g rows=%.20g "
cristye8c25f92010-06-03 00:53:06 +00002012 "depth=%.20g\n",(double) image->columns,(double) image->rows,(double)
2013 image->depth);
cristy3ed852e2009-09-05 21:47:34 +00002014 (void) WriteBlobString(image,buffer);
cristy5f1c1ff2010-12-23 21:38:06 +00002015 if (image->type != UndefinedType)
cristy3ed852e2009-09-05 21:47:34 +00002016 {
cristyb51dff52011-05-19 16:55:47 +00002017 (void) FormatLocaleString(buffer,MaxTextExtent,"type=%s\n",
cristy042ee782011-04-22 18:48:30 +00002018 CommandOptionToMnemonic(MagickTypeOptions,image->type));
cristy3ed852e2009-09-05 21:47:34 +00002019 (void) WriteBlobString(image,buffer);
2020 }
2021 if (image->colorspace != UndefinedColorspace)
2022 {
cristyb51dff52011-05-19 16:55:47 +00002023 (void) FormatLocaleString(buffer,MaxTextExtent,"colorspace=%s\n",
cristy042ee782011-04-22 18:48:30 +00002024 CommandOptionToMnemonic(MagickColorspaceOptions,image->colorspace));
cristy3ed852e2009-09-05 21:47:34 +00002025 (void) WriteBlobString(image,buffer);
2026 }
2027 if (compression != UndefinedCompression)
2028 {
cristyb51dff52011-05-19 16:55:47 +00002029 (void) FormatLocaleString(buffer,MaxTextExtent,"compression=%s "
cristy042ee782011-04-22 18:48:30 +00002030 "quality=%.20g\n",CommandOptionToMnemonic(MagickCompressOptions,
cristye8c25f92010-06-03 00:53:06 +00002031 compression),(double) image->quality);
cristy3ed852e2009-09-05 21:47:34 +00002032 (void) WriteBlobString(image,buffer);
2033 }
2034 if (image->units != UndefinedResolution)
2035 {
cristyb51dff52011-05-19 16:55:47 +00002036 (void) FormatLocaleString(buffer,MaxTextExtent,"units=%s\n",
cristy042ee782011-04-22 18:48:30 +00002037 CommandOptionToMnemonic(MagickResolutionOptions,image->units));
cristy3ed852e2009-09-05 21:47:34 +00002038 (void) WriteBlobString(image,buffer);
2039 }
cristy2a11bef2011-10-28 18:33:11 +00002040 if ((image->resolution.x != 0) || (image->resolution.y != 0))
cristy3ed852e2009-09-05 21:47:34 +00002041 {
cristyb51dff52011-05-19 16:55:47 +00002042 (void) FormatLocaleString(buffer,MaxTextExtent,
cristy2a11bef2011-10-28 18:33:11 +00002043 "resolution=%gx%g\n",image->resolution.x,image->resolution.y);
cristy3ed852e2009-09-05 21:47:34 +00002044 (void) WriteBlobString(image,buffer);
2045 }
2046 if ((image->page.width != 0) || (image->page.height != 0))
2047 {
cristyb51dff52011-05-19 16:55:47 +00002048 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00002049 "page=%.20gx%.20g%+.20g%+.20g\n",(double) image->page.width,(double)
2050 image->page.height,(double) image->page.x,(double) image->page.y);
cristy3ed852e2009-09-05 21:47:34 +00002051 (void) WriteBlobString(image,buffer);
2052 }
2053 else
2054 if ((image->page.x != 0) || (image->page.y != 0))
2055 {
cristyb51dff52011-05-19 16:55:47 +00002056 (void) FormatLocaleString(buffer,MaxTextExtent,"page=%+ld%+ld\n",
cristyf2faecf2010-05-28 19:19:36 +00002057 (long) image->page.x,(long) image->page.y);
cristy3ed852e2009-09-05 21:47:34 +00002058 (void) WriteBlobString(image,buffer);
2059 }
2060 if ((image->tile_offset.x != 0) || (image->tile_offset.y != 0))
2061 {
cristyb51dff52011-05-19 16:55:47 +00002062 (void) FormatLocaleString(buffer,MaxTextExtent,"tile-offset=%+ld%+ld\n",
cristyf2faecf2010-05-28 19:19:36 +00002063 (long) image->tile_offset.x,(long) image->tile_offset.y);
cristy3ed852e2009-09-05 21:47:34 +00002064 (void) WriteBlobString(image,buffer);
2065 }
2066 if ((GetNextImageInList(image) != (Image *) NULL) ||
2067 (GetPreviousImageInList(image) != (Image *) NULL))
2068 {
2069 if (image->scene == 0)
cristyb51dff52011-05-19 16:55:47 +00002070 (void) FormatLocaleString(buffer,MaxTextExtent,"iterations=%.20g "
cristye8c25f92010-06-03 00:53:06 +00002071 "delay=%.20g ticks-per-second=%.20g\n",(double) image->iterations,
2072 (double) image->delay,(double) image->ticks_per_second);
cristy3ed852e2009-09-05 21:47:34 +00002073 else
cristyb51dff52011-05-19 16:55:47 +00002074 (void) FormatLocaleString(buffer,MaxTextExtent,"scene=%.20g "
cristye8c25f92010-06-03 00:53:06 +00002075 "iterations=%.20g delay=%.20g ticks-per-second=%.20g\n",(double)
2076 image->scene,(double) image->iterations,(double) image->delay,
2077 (double) image->ticks_per_second);
cristy3ed852e2009-09-05 21:47:34 +00002078 (void) WriteBlobString(image,buffer);
2079 }
2080 else
2081 {
2082 if (image->scene != 0)
2083 {
cristyb51dff52011-05-19 16:55:47 +00002084 (void) FormatLocaleString(buffer,MaxTextExtent,"scene=%.20g\n",
cristye8c25f92010-06-03 00:53:06 +00002085 (double) image->scene);
cristy3ed852e2009-09-05 21:47:34 +00002086 (void) WriteBlobString(image,buffer);
2087 }
2088 if (image->iterations != 0)
2089 {
cristyb51dff52011-05-19 16:55:47 +00002090 (void) FormatLocaleString(buffer,MaxTextExtent,"iterations=%.20g\n",
cristye8c25f92010-06-03 00:53:06 +00002091 (double) image->iterations);
cristy3ed852e2009-09-05 21:47:34 +00002092 (void) WriteBlobString(image,buffer);
2093 }
2094 if (image->delay != 0)
2095 {
cristyb51dff52011-05-19 16:55:47 +00002096 (void) FormatLocaleString(buffer,MaxTextExtent,"delay=%.20g\n",
cristye8c25f92010-06-03 00:53:06 +00002097 (double) image->delay);
cristy3ed852e2009-09-05 21:47:34 +00002098 (void) WriteBlobString(image,buffer);
2099 }
2100 if (image->ticks_per_second != UndefinedTicksPerSecond)
2101 {
cristyb51dff52011-05-19 16:55:47 +00002102 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00002103 "ticks-per-second=%.20g\n",(double) image->ticks_per_second);
cristy3ed852e2009-09-05 21:47:34 +00002104 (void) WriteBlobString(image,buffer);
2105 }
2106 }
2107 if (image->gravity != UndefinedGravity)
2108 {
cristyb51dff52011-05-19 16:55:47 +00002109 (void) FormatLocaleString(buffer,MaxTextExtent,"gravity=%s\n",
cristy042ee782011-04-22 18:48:30 +00002110 CommandOptionToMnemonic(MagickGravityOptions,image->gravity));
cristy3ed852e2009-09-05 21:47:34 +00002111 (void) WriteBlobString(image,buffer);
2112 }
2113 if (image->dispose != UndefinedDispose)
2114 {
cristyb51dff52011-05-19 16:55:47 +00002115 (void) FormatLocaleString(buffer,MaxTextExtent,"dispose=%s\n",
cristy042ee782011-04-22 18:48:30 +00002116 CommandOptionToMnemonic(MagickDisposeOptions,image->dispose));
cristy3ed852e2009-09-05 21:47:34 +00002117 (void) WriteBlobString(image,buffer);
2118 }
2119 if (image->rendering_intent != UndefinedIntent)
2120 {
cristy0a30e182011-09-01 01:43:15 +00002121 (void) FormatLocaleString(buffer,MaxTextExtent,"rendering-intent=%s\n",
2122 CommandOptionToMnemonic(MagickIntentOptions,image->rendering_intent));
cristy3ed852e2009-09-05 21:47:34 +00002123 (void) WriteBlobString(image,buffer);
2124 }
2125 if (image->gamma != 0.0)
2126 {
cristyb51dff52011-05-19 16:55:47 +00002127 (void) FormatLocaleString(buffer,MaxTextExtent,"gamma=%g\n",
cristy3ed852e2009-09-05 21:47:34 +00002128 image->gamma);
2129 (void) WriteBlobString(image,buffer);
2130 }
2131 if (image->chromaticity.white_point.x != 0.0)
2132 {
2133 /*
2134 Note chomaticity points.
2135 */
cristyb51dff52011-05-19 16:55:47 +00002136 (void) FormatLocaleString(buffer,MaxTextExtent,"red-primary=%g,"
cristye7f51092010-01-17 00:39:37 +00002137 "%g green-primary=%g,%g blue-primary=%g,%g\n",
cristy3ed852e2009-09-05 21:47:34 +00002138 image->chromaticity.red_primary.x,image->chromaticity.red_primary.y,
2139 image->chromaticity.green_primary.x,
2140 image->chromaticity.green_primary.y,
2141 image->chromaticity.blue_primary.x,
2142 image->chromaticity.blue_primary.y);
2143 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00002144 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye7f51092010-01-17 00:39:37 +00002145 "white-point=%g,%g\n",image->chromaticity.white_point.x,
cristy8cd5b312010-01-07 01:10:24 +00002146 image->chromaticity.white_point.y);
cristy3ed852e2009-09-05 21:47:34 +00002147 (void) WriteBlobString(image,buffer);
2148 }
2149 if (image->orientation != UndefinedOrientation)
2150 {
cristyb51dff52011-05-19 16:55:47 +00002151 (void) FormatLocaleString(buffer,MaxTextExtent,"orientation=%s\n",
cristy042ee782011-04-22 18:48:30 +00002152 CommandOptionToMnemonic(MagickOrientationOptions,image->orientation));
cristy3ed852e2009-09-05 21:47:34 +00002153 (void) WriteBlobString(image,buffer);
2154 }
2155 if (image->profiles != (void *) NULL)
2156 {
2157 const char
2158 *name;
2159
2160 const StringInfo
2161 *profile;
2162
2163 /*
2164 Write image profiles.
2165 */
2166 ResetImageProfileIterator(image);
2167 name=GetNextImageProfile(image);
2168 while (name != (const char *) NULL)
2169 {
2170 profile=GetImageProfile(image,name);
2171 if (profile != (StringInfo *) NULL)
2172 {
cristyb51dff52011-05-19 16:55:47 +00002173 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00002174 "profile:%s=%.20g\n",name,(double)
2175 GetStringInfoLength(profile));
cristy3ed852e2009-09-05 21:47:34 +00002176 (void) WriteBlobString(image,buffer);
2177 }
2178 name=GetNextImageProfile(image);
2179 }
2180 }
2181 if (image->montage != (char *) NULL)
2182 {
cristyb51dff52011-05-19 16:55:47 +00002183 (void) FormatLocaleString(buffer,MaxTextExtent,"montage=%s\n",
cristy3ed852e2009-09-05 21:47:34 +00002184 image->montage);
2185 (void) WriteBlobString(image,buffer);
2186 }
2187 if (quantum_info->format == FloatingPointQuantumFormat)
cristyd15e6592011-10-15 00:13:06 +00002188 (void) SetImageProperty(image,"quantum:format","floating-point",
2189 exception);
cristy3ed852e2009-09-05 21:47:34 +00002190 ResetImagePropertyIterator(image);
2191 property=GetNextImageProperty(image);
2192 while (property != (const char *) NULL)
2193 {
cristyb51dff52011-05-19 16:55:47 +00002194 (void) FormatLocaleString(buffer,MaxTextExtent,"%s=",property);
cristy3ed852e2009-09-05 21:47:34 +00002195 (void) WriteBlobString(image,buffer);
cristyd15e6592011-10-15 00:13:06 +00002196 value=GetImageProperty(image,property,exception);
cristy3ed852e2009-09-05 21:47:34 +00002197 if (value != (const char *) NULL)
2198 {
cristyd76ed5d2012-05-20 16:15:57 +00002199 size_t
2200 length;
2201
cristy0e75d752012-05-20 16:10:32 +00002202 length=strlen(value);
2203 for (i=0; i < (ssize_t) length; i++)
cristy3ed852e2009-09-05 21:47:34 +00002204 if (isspace((int) ((unsigned char) value[i])) != 0)
2205 break;
cristy0e75d752012-05-20 16:10:32 +00002206 if (i == (ssize_t) length)
2207 (void) WriteBlob(image,length,(const unsigned char *) value);
cristyb880ee82012-04-07 15:08:14 +00002208 else
2209 {
2210 (void) WriteBlobByte(image,'{');
cristy3d136bd2012-05-04 12:16:20 +00002211 if (strchr(value,'}') == (char *) NULL)
cristy0e75d752012-05-20 16:10:32 +00002212 (void) WriteBlob(image,length,(const unsigned char *) value);
cristy3d136bd2012-05-04 12:16:20 +00002213 else
cristy0e75d752012-05-20 16:10:32 +00002214 for (i=0; i < (ssize_t) length; i++)
cristy3d136bd2012-05-04 12:16:20 +00002215 {
2216 if (value[i] == (int) '}')
2217 (void) WriteBlobByte(image,'\\');
2218 (void) WriteBlobByte(image,value[i]);
2219 }
cristyb880ee82012-04-07 15:08:14 +00002220 (void) WriteBlobByte(image,'}');
2221 }
cristy3ed852e2009-09-05 21:47:34 +00002222 }
2223 (void) WriteBlobByte(image,'\n');
2224 property=GetNextImageProperty(image);
2225 }
2226 (void) WriteBlobString(image,"\f\n:\032");
2227 if (image->montage != (char *) NULL)
2228 {
2229 /*
2230 Write montage tile directory.
2231 */
2232 if (image->directory != (char *) NULL)
2233 (void) WriteBlob(image,strlen(image->directory),(unsigned char *)
2234 image->directory);
2235 (void) WriteBlobByte(image,'\0');
2236 }
2237 if (image->profiles != (void *) NULL)
2238 {
2239 const char
2240 *name;
2241
2242 const StringInfo
2243 *profile;
2244
2245 /*
2246 Generic profile.
2247 */
2248 ResetImageProfileIterator(image);
2249 name=GetNextImageProfile(image);
2250 while (name != (const char *) NULL)
2251 {
2252 profile=GetImageProfile(image,name);
2253 (void) WriteBlob(image,GetStringInfoLength(profile),
2254 GetStringInfoDatum(profile));
2255 name=GetNextImageProfile(image);
2256 }
2257 }
2258 if (image->storage_class == PseudoClass)
2259 {
2260 size_t
2261 packet_size;
2262
2263 unsigned char
2264 *colormap,
2265 *q;
2266
2267 /*
2268 Allocate colormap.
2269 */
2270 packet_size=(size_t) (3*quantum_info->depth/8);
2271 colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
2272 packet_size*sizeof(*colormap));
2273 if (colormap == (unsigned char *) NULL)
2274 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2275 /*
2276 Write colormap to file.
2277 */
2278 q=colormap;
cristybb503372010-05-27 20:51:26 +00002279 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00002280 {
2281 switch (quantum_info->depth)
2282 {
2283 default:
2284 ThrowWriterException(CorruptImageError,"ImageDepthNotSupported");
2285 case 32:
2286 {
cristy4cb162a2010-05-30 03:04:47 +00002287 register unsigned int
cristy3ed852e2009-09-05 21:47:34 +00002288 pixel;
2289
2290 pixel=ScaleQuantumToLong(image->colormap[i].red);
2291 q=PopLongPixel(MSBEndian,pixel,q);
2292 pixel=ScaleQuantumToLong(image->colormap[i].green);
2293 q=PopLongPixel(MSBEndian,pixel,q);
2294 pixel=ScaleQuantumToLong(image->colormap[i].blue);
2295 q=PopLongPixel(MSBEndian,pixel,q);
2296 break;
2297 }
2298 case 16:
2299 {
2300 register unsigned short
2301 pixel;
2302
2303 pixel=ScaleQuantumToShort(image->colormap[i].red);
2304 q=PopShortPixel(MSBEndian,pixel,q);
2305 pixel=ScaleQuantumToShort(image->colormap[i].green);
2306 q=PopShortPixel(MSBEndian,pixel,q);
2307 pixel=ScaleQuantumToShort(image->colormap[i].blue);
2308 q=PopShortPixel(MSBEndian,pixel,q);
2309 break;
2310 }
2311 case 8:
2312 {
2313 register unsigned char
2314 pixel;
2315
2316 pixel=(unsigned char) ScaleQuantumToChar(image->colormap[i].red);
2317 q=PopCharPixel(pixel,q);
2318 pixel=(unsigned char) ScaleQuantumToChar(
2319 image->colormap[i].green);
2320 q=PopCharPixel(pixel,q);
2321 pixel=(unsigned char) ScaleQuantumToChar(image->colormap[i].blue);
2322 q=PopCharPixel(pixel,q);
2323 break;
2324 }
2325 }
2326 }
2327 (void) WriteBlob(image,packet_size*image->colors,colormap);
2328 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
2329 }
2330 /*
2331 Write image pixels to file.
2332 */
cristy330af6c2010-12-21 14:36:06 +00002333 status=MagickTrue;
2334 switch (compression)
2335 {
2336#if defined(MAGICKCORE_BZLIB_DELEGATE)
2337 case BZipCompression:
2338 {
cristy3a99dcf2011-12-17 01:29:40 +00002339 int
2340 code;
2341
cristy330af6c2010-12-21 14:36:06 +00002342 (void) ResetMagickMemory(&bzip_info,0,sizeof(bzip_info));
2343 bzip_info.bzalloc=AcquireBZIPMemory;
2344 bzip_info.bzfree=RelinquishBZIPMemory;
2345 code=BZ2_bzCompressInit(&bzip_info,(int) (image->quality ==
2346 UndefinedCompressionQuality ? 7 : MagickMin(image->quality/10,
2347 9)),(int) image_info->verbose,0);
2348 if (code != BZ_OK)
2349 status=MagickFalse;
2350 break;
2351 }
2352#endif
2353#if defined(MAGICKCORE_LZMA_DELEGATE)
2354 case LZMACompression:
2355 {
cristy3a99dcf2011-12-17 01:29:40 +00002356 int
2357 code;
2358
cristy330af6c2010-12-21 14:36:06 +00002359 (void) ResetMagickMemory(&allocator,0,sizeof(allocator));
2360 allocator.alloc=AcquireLZMAMemory;
2361 allocator.free=RelinquishLZMAMemory;
cristy9d72f1a2010-12-21 20:46:59 +00002362 lzma_info=initialize_lzma;
cristy330af6c2010-12-21 14:36:06 +00002363 lzma_info.allocator=&allocator;
cristy9d72f1a2010-12-21 20:46:59 +00002364 code=lzma_easy_encoder(&lzma_info,image->quality/10,LZMA_CHECK_SHA256);
2365 if (code != LZMA_OK)
2366 status=MagickTrue;
cristy330af6c2010-12-21 14:36:06 +00002367 break;
2368 }
2369#endif
2370#if defined(MAGICKCORE_ZLIB_DELEGATE)
2371 case LZWCompression:
2372 case ZipCompression:
2373 {
cristy3a99dcf2011-12-17 01:29:40 +00002374 int
2375 code;
2376
cristy330af6c2010-12-21 14:36:06 +00002377 (void) ResetMagickMemory(&zip_info,0,sizeof(zip_info));
2378 zip_info.zalloc=AcquireZIPMemory;
2379 zip_info.zfree=RelinquishZIPMemory;
2380 code=deflateInit(&zip_info,(int) (image->quality ==
2381 UndefinedCompressionQuality ? 7 : MagickMin(image->quality/10,9)));
2382 if (code != Z_OK)
2383 status=MagickFalse;
2384 break;
2385 }
2386#endif
2387 default:
2388 break;
2389 }
cristy1e178e72011-08-28 19:44:34 +00002390 quantum_type=GetQuantumType(image,exception);
cristy3ed852e2009-09-05 21:47:34 +00002391 pixels=GetQuantumPixels(quantum_info);
cristybb503372010-05-27 20:51:26 +00002392 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002393 {
cristy4c08aed2011-07-01 19:47:50 +00002394 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00002395 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00002396
cristybb503372010-05-27 20:51:26 +00002397 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002398 x;
2399
cristy330af6c2010-12-21 14:36:06 +00002400 if (status == MagickFalse)
2401 break;
cristy1e178e72011-08-28 19:44:34 +00002402 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00002403 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002404 break;
cristy3ed852e2009-09-05 21:47:34 +00002405 q=pixels;
2406 switch (compression)
2407 {
cristy3ed852e2009-09-05 21:47:34 +00002408#if defined(MAGICKCORE_BZLIB_DELEGATE)
2409 case BZipCompression:
2410 {
cristy3ed852e2009-09-05 21:47:34 +00002411 bzip_info.next_in=(char *) pixels;
2412 bzip_info.avail_in=(unsigned int) (packet_size*image->columns);
cristy4c08aed2011-07-01 19:47:50 +00002413 (void) ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
cristy1e178e72011-08-28 19:44:34 +00002414 quantum_type,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00002415 do
2416 {
cristy3a99dcf2011-12-17 01:29:40 +00002417 int
2418 code;
2419
cristy3ed852e2009-09-05 21:47:34 +00002420 bzip_info.next_out=(char *) compress_pixels;
2421 bzip_info.avail_out=(unsigned int) BZipMaxExtent(packet_size*
2422 image->columns);
2423 code=BZ2_bzCompress(&bzip_info,BZ_FLUSH);
cristy26377172010-12-20 19:01:58 +00002424 if (code != BZ_OK)
2425 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00002426 length=(size_t) (bzip_info.next_out-(char *) compress_pixels);
2427 if (length != 0)
2428 {
2429 (void) WriteBlobMSBLong(image,(unsigned int) length);
2430 (void) WriteBlob(image,length,compress_pixels);
2431 }
2432 } while (bzip_info.avail_in != 0);
cristy26377172010-12-20 19:01:58 +00002433 break;
2434 }
2435#endif
2436#if defined(MAGICKCORE_LZMA_DELEGATE)
2437 case LZMACompression:
2438 {
cristy26377172010-12-20 19:01:58 +00002439 lzma_info.next_in=pixels;
cristy330af6c2010-12-21 14:36:06 +00002440 lzma_info.avail_in=packet_size*image->columns;
cristy4c08aed2011-07-01 19:47:50 +00002441 (void) ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
cristy1e178e72011-08-28 19:44:34 +00002442 quantum_type,pixels,exception);
cristy26377172010-12-20 19:01:58 +00002443 do
2444 {
cristy3a99dcf2011-12-17 01:29:40 +00002445 int
2446 code;
2447
cristy26377172010-12-20 19:01:58 +00002448 lzma_info.next_out=compress_pixels;
2449 lzma_info.avail_out=packet_size*image->columns;
2450 code=lzma_code(&lzma_info,LZMA_RUN);
2451 if (code != LZMA_OK)
2452 status=MagickFalse;
2453 length=(size_t) (lzma_info.next_out-compress_pixels);
2454 if (length != 0)
2455 {
2456 (void) WriteBlobMSBLong(image,(unsigned int) length);
2457 (void) WriteBlob(image,length,compress_pixels);
2458 }
2459 } while (lzma_info.avail_in != 0);
cristy26377172010-12-20 19:01:58 +00002460 break;
2461 }
2462#endif
2463#if defined(MAGICKCORE_ZLIB_DELEGATE)
2464 case LZWCompression:
2465 case ZipCompression:
2466 {
cristy26377172010-12-20 19:01:58 +00002467 zip_info.next_in=pixels;
2468 zip_info.avail_in=(uInt) (packet_size*image->columns);
cristy4c08aed2011-07-01 19:47:50 +00002469 (void) ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
cristy1e178e72011-08-28 19:44:34 +00002470 quantum_type,pixels,exception);
cristy26377172010-12-20 19:01:58 +00002471 do
2472 {
cristy3a99dcf2011-12-17 01:29:40 +00002473 int
2474 code;
2475
cristy26377172010-12-20 19:01:58 +00002476 zip_info.next_out=compress_pixels;
2477 zip_info.avail_out=(uInt) ZipMaxExtent(packet_size*image->columns);
2478 code=deflate(&zip_info,Z_SYNC_FLUSH);
2479 if (code != Z_OK)
2480 status=MagickFalse;
2481 length=(size_t) (zip_info.next_out-compress_pixels);
2482 if (length != 0)
2483 {
2484 (void) WriteBlobMSBLong(image,(unsigned int) length);
2485 (void) WriteBlob(image,length,compress_pixels);
2486 }
2487 } while (zip_info.avail_in != 0);
cristy3ed852e2009-09-05 21:47:34 +00002488 break;
2489 }
2490#endif
2491 case RLECompression:
2492 {
cristy4c08aed2011-07-01 19:47:50 +00002493 length=0;
cristy803640d2011-11-17 02:11:32 +00002494 GetPixelInfoPixel(image,p,&pixel);
cristyed231572011-07-14 02:18:59 +00002495 p+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00002496 for (x=1; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002497 {
cristy803640d2011-11-17 02:11:32 +00002498 GetPixelInfoPixel(image,p,&target);
cristy4c08aed2011-07-01 19:47:50 +00002499 if ((length < 255) &&
2500 (IsPixelInfoEquivalent(&pixel,&target) != MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00002501 length++;
2502 else
2503 {
cristyc82a27b2011-10-21 01:07:16 +00002504 q=PopRunlengthPacket(image,q,length,&pixel,exception);
cristy3ed852e2009-09-05 21:47:34 +00002505 length=0;
2506 }
cristy803640d2011-11-17 02:11:32 +00002507 GetPixelInfoPixel(image,p,&pixel);
cristyed231572011-07-14 02:18:59 +00002508 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00002509 }
cristyc82a27b2011-10-21 01:07:16 +00002510 q=PopRunlengthPacket(image,q,length,&pixel,exception);
cristy3ed852e2009-09-05 21:47:34 +00002511 (void) WriteBlob(image,(size_t) (q-pixels),pixels);
2512 break;
2513 }
2514 default:
2515 {
cristy4c08aed2011-07-01 19:47:50 +00002516 (void) ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
cristy1e178e72011-08-28 19:44:34 +00002517 quantum_type,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00002518 (void) WriteBlob(image,packet_size*image->columns,pixels);
2519 break;
2520 }
2521 }
cristycee97112010-05-28 00:44:52 +00002522 if (image->previous == (Image *) NULL)
2523 {
2524 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2525 image->rows);
2526 if (status == MagickFalse)
2527 break;
2528 }
cristy3ed852e2009-09-05 21:47:34 +00002529 }
cristy330af6c2010-12-21 14:36:06 +00002530 switch (compression)
2531 {
2532#if defined(MAGICKCORE_BZLIB_DELEGATE)
2533 case BZipCompression:
2534 {
cristy3a99dcf2011-12-17 01:29:40 +00002535 int
2536 code;
2537
cristy330af6c2010-12-21 14:36:06 +00002538 for ( ; ; )
2539 {
2540 if (status == MagickFalse)
2541 break;
2542 bzip_info.next_out=(char *) compress_pixels;
2543 bzip_info.avail_out=(unsigned int) BZipMaxExtent(packet_size*
2544 image->columns);
2545 code=BZ2_bzCompress(&bzip_info,BZ_FINISH);
cristy330af6c2010-12-21 14:36:06 +00002546 length=(size_t) (bzip_info.next_out-(char *) compress_pixels);
2547 if (length != 0)
2548 {
2549 (void) WriteBlobMSBLong(image,(unsigned int) length);
2550 (void) WriteBlob(image,length,compress_pixels);
2551 }
2552 if (code == BZ_STREAM_END)
2553 break;
2554 }
2555 code=BZ2_bzCompressEnd(&bzip_info);
2556 if (code != BZ_OK)
2557 status=MagickFalse;
2558 break;
2559 }
2560#endif
2561#if defined(MAGICKCORE_LZMA_DELEGATE)
2562 case LZMACompression:
2563 {
cristy3a99dcf2011-12-17 01:29:40 +00002564 int
2565 code;
2566
cristy330af6c2010-12-21 14:36:06 +00002567 for ( ; ; )
2568 {
2569 if (status == MagickFalse)
2570 break;
2571 lzma_info.next_out=compress_pixels;
2572 lzma_info.avail_out=packet_size*image->columns;
2573 code=lzma_code(&lzma_info,LZMA_FINISH);
cristy330af6c2010-12-21 14:36:06 +00002574 length=(size_t) (lzma_info.next_out-compress_pixels);
2575 if (length > 6)
2576 {
2577 (void) WriteBlobMSBLong(image,(unsigned int) length);
2578 (void) WriteBlob(image,length,compress_pixels);
2579 }
2580 if (code == LZMA_STREAM_END)
2581 break;
2582 }
2583 lzma_end(&lzma_info);
2584 break;
2585 }
2586#endif
2587#if defined(MAGICKCORE_ZLIB_DELEGATE)
2588 case LZWCompression:
2589 case ZipCompression:
2590 {
cristy3a99dcf2011-12-17 01:29:40 +00002591 int
2592 code;
2593
cristy330af6c2010-12-21 14:36:06 +00002594 for ( ; ; )
2595 {
2596 if (status == MagickFalse)
2597 break;
2598 zip_info.next_out=compress_pixels;
cristyc3ca81b2011-10-17 18:05:54 +00002599 zip_info.avail_out=(uInt) ZipMaxExtent(packet_size*image->columns);
cristy330af6c2010-12-21 14:36:06 +00002600 code=deflate(&zip_info,Z_FINISH);
cristy330af6c2010-12-21 14:36:06 +00002601 length=(size_t) (zip_info.next_out-compress_pixels);
2602 if (length > 6)
2603 {
2604 (void) WriteBlobMSBLong(image,(unsigned int) length);
2605 (void) WriteBlob(image,length,compress_pixels);
2606 }
2607 if (code == Z_STREAM_END)
2608 break;
2609 }
2610 code=deflateEnd(&zip_info);
2611 if (code != Z_OK)
2612 status=MagickFalse;
2613 break;
2614 }
2615#endif
2616 default:
2617 break;
2618 }
cristy3ed852e2009-09-05 21:47:34 +00002619 quantum_info=DestroyQuantumInfo(quantum_info);
2620 compress_pixels=(unsigned char *) RelinquishMagickMemory(compress_pixels);
2621 if (GetNextImageInList(image) == (Image *) NULL)
2622 break;
2623 image=SyncNextImageInList(image);
2624 status=SetImageProgress(image,SaveImagesTag,scene++,
2625 GetImageListLength(image));
2626 if (status == MagickFalse)
2627 break;
2628 } while (image_info->adjoin != MagickFalse);
2629 (void) CloseBlob(image);
2630 return(status);
2631}