blob: d852c581abdd60606ee6fcc60ff11801fe140525 [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 == '{')
628 (void) CopyMagickString(options,options+1,MaxTextExtent);
629 /*
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 {
cristybb503372010-05-27 20:51:26 +00002199 for (i=0; i < (ssize_t) strlen(value); i++)
cristy3ed852e2009-09-05 21:47:34 +00002200 if (isspace((int) ((unsigned char) value[i])) != 0)
2201 break;
cristyb880ee82012-04-07 15:08:14 +00002202 if (i == (ssize_t) strlen(value))
2203 (void) WriteBlob(image,strlen(value),(const unsigned char *) value);
2204 else
2205 {
2206 (void) WriteBlobByte(image,'{');
cristy3d136bd2012-05-04 12:16:20 +00002207 if (strchr(value,'}') == (char *) NULL)
2208 (void) WriteBlob(image,strlen(value),(const unsigned char *)
2209 value);
2210 else
2211 for (i=0; i < (ssize_t) strlen(value); i++)
2212 {
2213 if (value[i] == (int) '}')
2214 (void) WriteBlobByte(image,'\\');
2215 (void) WriteBlobByte(image,value[i]);
2216 }
cristyb880ee82012-04-07 15:08:14 +00002217 (void) WriteBlobByte(image,'}');
2218 }
cristy3ed852e2009-09-05 21:47:34 +00002219 }
2220 (void) WriteBlobByte(image,'\n');
2221 property=GetNextImageProperty(image);
2222 }
2223 (void) WriteBlobString(image,"\f\n:\032");
2224 if (image->montage != (char *) NULL)
2225 {
2226 /*
2227 Write montage tile directory.
2228 */
2229 if (image->directory != (char *) NULL)
2230 (void) WriteBlob(image,strlen(image->directory),(unsigned char *)
2231 image->directory);
2232 (void) WriteBlobByte(image,'\0');
2233 }
2234 if (image->profiles != (void *) NULL)
2235 {
2236 const char
2237 *name;
2238
2239 const StringInfo
2240 *profile;
2241
2242 /*
2243 Generic profile.
2244 */
2245 ResetImageProfileIterator(image);
2246 name=GetNextImageProfile(image);
2247 while (name != (const char *) NULL)
2248 {
2249 profile=GetImageProfile(image,name);
2250 (void) WriteBlob(image,GetStringInfoLength(profile),
2251 GetStringInfoDatum(profile));
2252 name=GetNextImageProfile(image);
2253 }
2254 }
2255 if (image->storage_class == PseudoClass)
2256 {
2257 size_t
2258 packet_size;
2259
2260 unsigned char
2261 *colormap,
2262 *q;
2263
2264 /*
2265 Allocate colormap.
2266 */
2267 packet_size=(size_t) (3*quantum_info->depth/8);
2268 colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
2269 packet_size*sizeof(*colormap));
2270 if (colormap == (unsigned char *) NULL)
2271 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2272 /*
2273 Write colormap to file.
2274 */
2275 q=colormap;
cristybb503372010-05-27 20:51:26 +00002276 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00002277 {
2278 switch (quantum_info->depth)
2279 {
2280 default:
2281 ThrowWriterException(CorruptImageError,"ImageDepthNotSupported");
2282 case 32:
2283 {
cristy4cb162a2010-05-30 03:04:47 +00002284 register unsigned int
cristy3ed852e2009-09-05 21:47:34 +00002285 pixel;
2286
2287 pixel=ScaleQuantumToLong(image->colormap[i].red);
2288 q=PopLongPixel(MSBEndian,pixel,q);
2289 pixel=ScaleQuantumToLong(image->colormap[i].green);
2290 q=PopLongPixel(MSBEndian,pixel,q);
2291 pixel=ScaleQuantumToLong(image->colormap[i].blue);
2292 q=PopLongPixel(MSBEndian,pixel,q);
2293 break;
2294 }
2295 case 16:
2296 {
2297 register unsigned short
2298 pixel;
2299
2300 pixel=ScaleQuantumToShort(image->colormap[i].red);
2301 q=PopShortPixel(MSBEndian,pixel,q);
2302 pixel=ScaleQuantumToShort(image->colormap[i].green);
2303 q=PopShortPixel(MSBEndian,pixel,q);
2304 pixel=ScaleQuantumToShort(image->colormap[i].blue);
2305 q=PopShortPixel(MSBEndian,pixel,q);
2306 break;
2307 }
2308 case 8:
2309 {
2310 register unsigned char
2311 pixel;
2312
2313 pixel=(unsigned char) ScaleQuantumToChar(image->colormap[i].red);
2314 q=PopCharPixel(pixel,q);
2315 pixel=(unsigned char) ScaleQuantumToChar(
2316 image->colormap[i].green);
2317 q=PopCharPixel(pixel,q);
2318 pixel=(unsigned char) ScaleQuantumToChar(image->colormap[i].blue);
2319 q=PopCharPixel(pixel,q);
2320 break;
2321 }
2322 }
2323 }
2324 (void) WriteBlob(image,packet_size*image->colors,colormap);
2325 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
2326 }
2327 /*
2328 Write image pixels to file.
2329 */
cristy330af6c2010-12-21 14:36:06 +00002330 status=MagickTrue;
2331 switch (compression)
2332 {
2333#if defined(MAGICKCORE_BZLIB_DELEGATE)
2334 case BZipCompression:
2335 {
cristy3a99dcf2011-12-17 01:29:40 +00002336 int
2337 code;
2338
cristy330af6c2010-12-21 14:36:06 +00002339 (void) ResetMagickMemory(&bzip_info,0,sizeof(bzip_info));
2340 bzip_info.bzalloc=AcquireBZIPMemory;
2341 bzip_info.bzfree=RelinquishBZIPMemory;
2342 code=BZ2_bzCompressInit(&bzip_info,(int) (image->quality ==
2343 UndefinedCompressionQuality ? 7 : MagickMin(image->quality/10,
2344 9)),(int) image_info->verbose,0);
2345 if (code != BZ_OK)
2346 status=MagickFalse;
2347 break;
2348 }
2349#endif
2350#if defined(MAGICKCORE_LZMA_DELEGATE)
2351 case LZMACompression:
2352 {
cristy3a99dcf2011-12-17 01:29:40 +00002353 int
2354 code;
2355
cristy330af6c2010-12-21 14:36:06 +00002356 (void) ResetMagickMemory(&allocator,0,sizeof(allocator));
2357 allocator.alloc=AcquireLZMAMemory;
2358 allocator.free=RelinquishLZMAMemory;
cristy9d72f1a2010-12-21 20:46:59 +00002359 lzma_info=initialize_lzma;
cristy330af6c2010-12-21 14:36:06 +00002360 lzma_info.allocator=&allocator;
cristy9d72f1a2010-12-21 20:46:59 +00002361 code=lzma_easy_encoder(&lzma_info,image->quality/10,LZMA_CHECK_SHA256);
2362 if (code != LZMA_OK)
2363 status=MagickTrue;
cristy330af6c2010-12-21 14:36:06 +00002364 break;
2365 }
2366#endif
2367#if defined(MAGICKCORE_ZLIB_DELEGATE)
2368 case LZWCompression:
2369 case ZipCompression:
2370 {
cristy3a99dcf2011-12-17 01:29:40 +00002371 int
2372 code;
2373
cristy330af6c2010-12-21 14:36:06 +00002374 (void) ResetMagickMemory(&zip_info,0,sizeof(zip_info));
2375 zip_info.zalloc=AcquireZIPMemory;
2376 zip_info.zfree=RelinquishZIPMemory;
2377 code=deflateInit(&zip_info,(int) (image->quality ==
2378 UndefinedCompressionQuality ? 7 : MagickMin(image->quality/10,9)));
2379 if (code != Z_OK)
2380 status=MagickFalse;
2381 break;
2382 }
2383#endif
2384 default:
2385 break;
2386 }
cristy1e178e72011-08-28 19:44:34 +00002387 quantum_type=GetQuantumType(image,exception);
cristy3ed852e2009-09-05 21:47:34 +00002388 pixels=GetQuantumPixels(quantum_info);
cristybb503372010-05-27 20:51:26 +00002389 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002390 {
cristy4c08aed2011-07-01 19:47:50 +00002391 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +00002392 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00002393
cristybb503372010-05-27 20:51:26 +00002394 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002395 x;
2396
cristy330af6c2010-12-21 14:36:06 +00002397 if (status == MagickFalse)
2398 break;
cristy1e178e72011-08-28 19:44:34 +00002399 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00002400 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002401 break;
cristy3ed852e2009-09-05 21:47:34 +00002402 q=pixels;
2403 switch (compression)
2404 {
cristy3ed852e2009-09-05 21:47:34 +00002405#if defined(MAGICKCORE_BZLIB_DELEGATE)
2406 case BZipCompression:
2407 {
cristy3ed852e2009-09-05 21:47:34 +00002408 bzip_info.next_in=(char *) pixels;
2409 bzip_info.avail_in=(unsigned int) (packet_size*image->columns);
cristy4c08aed2011-07-01 19:47:50 +00002410 (void) ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
cristy1e178e72011-08-28 19:44:34 +00002411 quantum_type,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00002412 do
2413 {
cristy3a99dcf2011-12-17 01:29:40 +00002414 int
2415 code;
2416
cristy3ed852e2009-09-05 21:47:34 +00002417 bzip_info.next_out=(char *) compress_pixels;
2418 bzip_info.avail_out=(unsigned int) BZipMaxExtent(packet_size*
2419 image->columns);
2420 code=BZ2_bzCompress(&bzip_info,BZ_FLUSH);
cristy26377172010-12-20 19:01:58 +00002421 if (code != BZ_OK)
2422 status=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00002423 length=(size_t) (bzip_info.next_out-(char *) compress_pixels);
2424 if (length != 0)
2425 {
2426 (void) WriteBlobMSBLong(image,(unsigned int) length);
2427 (void) WriteBlob(image,length,compress_pixels);
2428 }
2429 } while (bzip_info.avail_in != 0);
cristy26377172010-12-20 19:01:58 +00002430 break;
2431 }
2432#endif
2433#if defined(MAGICKCORE_LZMA_DELEGATE)
2434 case LZMACompression:
2435 {
cristy26377172010-12-20 19:01:58 +00002436 lzma_info.next_in=pixels;
cristy330af6c2010-12-21 14:36:06 +00002437 lzma_info.avail_in=packet_size*image->columns;
cristy4c08aed2011-07-01 19:47:50 +00002438 (void) ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
cristy1e178e72011-08-28 19:44:34 +00002439 quantum_type,pixels,exception);
cristy26377172010-12-20 19:01:58 +00002440 do
2441 {
cristy3a99dcf2011-12-17 01:29:40 +00002442 int
2443 code;
2444
cristy26377172010-12-20 19:01:58 +00002445 lzma_info.next_out=compress_pixels;
2446 lzma_info.avail_out=packet_size*image->columns;
2447 code=lzma_code(&lzma_info,LZMA_RUN);
2448 if (code != LZMA_OK)
2449 status=MagickFalse;
2450 length=(size_t) (lzma_info.next_out-compress_pixels);
2451 if (length != 0)
2452 {
2453 (void) WriteBlobMSBLong(image,(unsigned int) length);
2454 (void) WriteBlob(image,length,compress_pixels);
2455 }
2456 } while (lzma_info.avail_in != 0);
cristy26377172010-12-20 19:01:58 +00002457 break;
2458 }
2459#endif
2460#if defined(MAGICKCORE_ZLIB_DELEGATE)
2461 case LZWCompression:
2462 case ZipCompression:
2463 {
cristy26377172010-12-20 19:01:58 +00002464 zip_info.next_in=pixels;
2465 zip_info.avail_in=(uInt) (packet_size*image->columns);
cristy4c08aed2011-07-01 19:47:50 +00002466 (void) ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
cristy1e178e72011-08-28 19:44:34 +00002467 quantum_type,pixels,exception);
cristy26377172010-12-20 19:01:58 +00002468 do
2469 {
cristy3a99dcf2011-12-17 01:29:40 +00002470 int
2471 code;
2472
cristy26377172010-12-20 19:01:58 +00002473 zip_info.next_out=compress_pixels;
2474 zip_info.avail_out=(uInt) ZipMaxExtent(packet_size*image->columns);
2475 code=deflate(&zip_info,Z_SYNC_FLUSH);
2476 if (code != Z_OK)
2477 status=MagickFalse;
2478 length=(size_t) (zip_info.next_out-compress_pixels);
2479 if (length != 0)
2480 {
2481 (void) WriteBlobMSBLong(image,(unsigned int) length);
2482 (void) WriteBlob(image,length,compress_pixels);
2483 }
2484 } while (zip_info.avail_in != 0);
cristy3ed852e2009-09-05 21:47:34 +00002485 break;
2486 }
2487#endif
2488 case RLECompression:
2489 {
cristy4c08aed2011-07-01 19:47:50 +00002490 length=0;
cristy803640d2011-11-17 02:11:32 +00002491 GetPixelInfoPixel(image,p,&pixel);
cristyed231572011-07-14 02:18:59 +00002492 p+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00002493 for (x=1; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002494 {
cristy803640d2011-11-17 02:11:32 +00002495 GetPixelInfoPixel(image,p,&target);
cristy4c08aed2011-07-01 19:47:50 +00002496 if ((length < 255) &&
2497 (IsPixelInfoEquivalent(&pixel,&target) != MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00002498 length++;
2499 else
2500 {
cristyc82a27b2011-10-21 01:07:16 +00002501 q=PopRunlengthPacket(image,q,length,&pixel,exception);
cristy3ed852e2009-09-05 21:47:34 +00002502 length=0;
2503 }
cristy803640d2011-11-17 02:11:32 +00002504 GetPixelInfoPixel(image,p,&pixel);
cristyed231572011-07-14 02:18:59 +00002505 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00002506 }
cristyc82a27b2011-10-21 01:07:16 +00002507 q=PopRunlengthPacket(image,q,length,&pixel,exception);
cristy3ed852e2009-09-05 21:47:34 +00002508 (void) WriteBlob(image,(size_t) (q-pixels),pixels);
2509 break;
2510 }
2511 default:
2512 {
cristy4c08aed2011-07-01 19:47:50 +00002513 (void) ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
cristy1e178e72011-08-28 19:44:34 +00002514 quantum_type,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00002515 (void) WriteBlob(image,packet_size*image->columns,pixels);
2516 break;
2517 }
2518 }
cristycee97112010-05-28 00:44:52 +00002519 if (image->previous == (Image *) NULL)
2520 {
2521 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2522 image->rows);
2523 if (status == MagickFalse)
2524 break;
2525 }
cristy3ed852e2009-09-05 21:47:34 +00002526 }
cristy330af6c2010-12-21 14:36:06 +00002527 switch (compression)
2528 {
2529#if defined(MAGICKCORE_BZLIB_DELEGATE)
2530 case BZipCompression:
2531 {
cristy3a99dcf2011-12-17 01:29:40 +00002532 int
2533 code;
2534
cristy330af6c2010-12-21 14:36:06 +00002535 for ( ; ; )
2536 {
2537 if (status == MagickFalse)
2538 break;
2539 bzip_info.next_out=(char *) compress_pixels;
2540 bzip_info.avail_out=(unsigned int) BZipMaxExtent(packet_size*
2541 image->columns);
2542 code=BZ2_bzCompress(&bzip_info,BZ_FINISH);
cristy330af6c2010-12-21 14:36:06 +00002543 length=(size_t) (bzip_info.next_out-(char *) compress_pixels);
2544 if (length != 0)
2545 {
2546 (void) WriteBlobMSBLong(image,(unsigned int) length);
2547 (void) WriteBlob(image,length,compress_pixels);
2548 }
2549 if (code == BZ_STREAM_END)
2550 break;
2551 }
2552 code=BZ2_bzCompressEnd(&bzip_info);
2553 if (code != BZ_OK)
2554 status=MagickFalse;
2555 break;
2556 }
2557#endif
2558#if defined(MAGICKCORE_LZMA_DELEGATE)
2559 case LZMACompression:
2560 {
cristy3a99dcf2011-12-17 01:29:40 +00002561 int
2562 code;
2563
cristy330af6c2010-12-21 14:36:06 +00002564 for ( ; ; )
2565 {
2566 if (status == MagickFalse)
2567 break;
2568 lzma_info.next_out=compress_pixels;
2569 lzma_info.avail_out=packet_size*image->columns;
2570 code=lzma_code(&lzma_info,LZMA_FINISH);
cristy330af6c2010-12-21 14:36:06 +00002571 length=(size_t) (lzma_info.next_out-compress_pixels);
2572 if (length > 6)
2573 {
2574 (void) WriteBlobMSBLong(image,(unsigned int) length);
2575 (void) WriteBlob(image,length,compress_pixels);
2576 }
2577 if (code == LZMA_STREAM_END)
2578 break;
2579 }
2580 lzma_end(&lzma_info);
2581 break;
2582 }
2583#endif
2584#if defined(MAGICKCORE_ZLIB_DELEGATE)
2585 case LZWCompression:
2586 case ZipCompression:
2587 {
cristy3a99dcf2011-12-17 01:29:40 +00002588 int
2589 code;
2590
cristy330af6c2010-12-21 14:36:06 +00002591 for ( ; ; )
2592 {
2593 if (status == MagickFalse)
2594 break;
2595 zip_info.next_out=compress_pixels;
cristyc3ca81b2011-10-17 18:05:54 +00002596 zip_info.avail_out=(uInt) ZipMaxExtent(packet_size*image->columns);
cristy330af6c2010-12-21 14:36:06 +00002597 code=deflate(&zip_info,Z_FINISH);
cristy330af6c2010-12-21 14:36:06 +00002598 length=(size_t) (zip_info.next_out-compress_pixels);
2599 if (length > 6)
2600 {
2601 (void) WriteBlobMSBLong(image,(unsigned int) length);
2602 (void) WriteBlob(image,length,compress_pixels);
2603 }
2604 if (code == Z_STREAM_END)
2605 break;
2606 }
2607 code=deflateEnd(&zip_info);
2608 if (code != Z_OK)
2609 status=MagickFalse;
2610 break;
2611 }
2612#endif
2613 default:
2614 break;
2615 }
cristy3ed852e2009-09-05 21:47:34 +00002616 quantum_info=DestroyQuantumInfo(quantum_info);
2617 compress_pixels=(unsigned char *) RelinquishMagickMemory(compress_pixels);
2618 if (GetNextImageInList(image) == (Image *) NULL)
2619 break;
2620 image=SyncNextImageInList(image);
2621 status=SetImageProgress(image,SaveImagesTag,scene++,
2622 GetImageListLength(image));
2623 if (status == MagickFalse)
2624 break;
2625 } while (image_info->adjoin != MagickFalse);
2626 (void) CloseBlob(image);
2627 return(status);
2628}