]> granicus.if.org Git - imagemagick/blob - coders/miff.c
(no commit message)
[imagemagick] / coders / miff.c
1 /*
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 %                                   Cristy                                    %
17 %                                 July 1992                                   %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    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 \f
39 /*
40   Include declarations.
41 */
42 #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"
52 #include "MagickCore/colorspace-private.h"
53 #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"
76 #if defined(MAGICKCORE_BZLIB_DELEGATE)
77 #include "bzlib.h"
78 #endif
79 #if defined(MAGICKCORE_LZMA_DELEGATE)
80 #include "lzma.h"
81 #endif
82 #if defined(MAGICKCORE_ZLIB_DELEGATE)
83 #include "zlib.h"
84 #endif
85 \f
86 /*
87   Define declarations.
88 */
89 #if !defined(LZMA_OK)
90 #define LZMA_OK  0
91 #endif
92 \f
93 /*
94   Forward declarations.
95 */
96 static MagickBooleanType
97   WriteMIFFImage(const ImageInfo *,Image *,ExceptionInfo *);
98 \f
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 */
124 static 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 \f
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)
164 static 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
171 #if defined(MAGICKCORE_LZMA_DELEGATE)
172 static 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
179 #if defined(MAGICKCORE_ZLIB_DELEGATE)
180 static 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
188 static 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
195 static 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
202 static void PushRunlengthPacket(Image *image,const unsigned char *pixels,
203   size_t *length,PixelInfo *pixel,ExceptionInfo *exception)
204 {
205   const unsigned char
206     *p;
207
208   p=pixels;
209   if (image->storage_class == PseudoClass)
210     {
211       pixel->index=0;
212       switch (image->depth)
213       {
214         case 32:
215         {
216           pixel->index=ConstrainColormapIndex(image,((size_t) *p << 24) |
217             ((size_t) *(p+1) << 16) | ((size_t) *(p+2) << 8) | (size_t) *(p+3),
218             exception);
219           p+=4;
220           break;
221         }
222         case 16:
223         {
224           pixel->index=ConstrainColormapIndex(image,(*p << 8) | *(p+1),
225             exception);
226           p+=2;
227           break;
228         }
229         case 8:
230         {
231           pixel->index=ConstrainColormapIndex(image,*p,exception);
232           p++;
233           break;
234         }
235         default:
236           (void) ThrowMagickException(exception,GetMagickModule(),
237             CorruptImageError,"ImageDepthNotSupported","`%s'",image->filename);
238       }
239       switch (image->depth)
240       {
241         case 8:
242         {
243           unsigned char
244             quantum;
245
246           if (image->alpha_trait == BlendPixelTrait)
247             {
248               p=PushCharPixel(p,&quantum);
249               pixel->alpha=ScaleCharToQuantum(quantum);
250             }
251           break;
252         }
253         case 16:
254         {
255           unsigned short
256             quantum;
257
258           if (image->alpha_trait == BlendPixelTrait)
259             {
260               p=PushShortPixel(MSBEndian,p,&quantum);
261               pixel->alpha=(Quantum) (quantum >> (image->depth-
262                 MAGICKCORE_QUANTUM_DEPTH));
263             }
264           break;
265         }
266         case 32:
267         {
268           unsigned int
269             quantum;
270
271           if (image->alpha_trait == BlendPixelTrait)
272             {
273               p=PushLongPixel(MSBEndian,p,&quantum);
274               pixel->alpha=(Quantum) (quantum >> (image->depth-
275                 MAGICKCORE_QUANTUM_DEPTH));
276             }
277           break;
278         }
279         default:
280           (void) ThrowMagickException(exception,GetMagickModule(),
281             CorruptImageError,"ImageDepthNotSupported","`%s'",image->filename);
282       }
283       *length=(size_t) (*p++)+1;
284       return;
285     }
286   switch (image->depth)
287   {
288     case 8:
289     {
290       unsigned char
291         quantum;
292
293       p=PushCharPixel(p,&quantum);
294       pixel->red=ScaleCharToQuantum(quantum);
295       pixel->green=pixel->red;
296       pixel->blue=pixel->red;
297       if (IsGrayColorspace(image->colorspace) == MagickFalse)
298         {
299           p=PushCharPixel(p,&quantum);
300           pixel->green=ScaleCharToQuantum(quantum);
301           p=PushCharPixel(p,&quantum);
302           pixel->blue=ScaleCharToQuantum(quantum);
303         }
304       if (image->colorspace == CMYKColorspace)
305         {
306           p=PushCharPixel(p,&quantum);
307           pixel->black=ScaleCharToQuantum(quantum);
308         }
309       if (image->alpha_trait == BlendPixelTrait)
310         {
311           p=PushCharPixel(p,&quantum);
312           pixel->alpha=ScaleCharToQuantum(quantum);
313         }
314       break;
315     }
316     case 16:
317     {
318       unsigned short
319         quantum;
320
321       p=PushShortPixel(MSBEndian,p,&quantum);
322       pixel->red=quantum >> (image->depth-MAGICKCORE_QUANTUM_DEPTH);
323       pixel->green=pixel->red;
324       pixel->blue=pixel->red;
325       if (IsGrayColorspace(image->colorspace) == MagickFalse)
326         {
327           p=PushShortPixel(MSBEndian,p,&quantum);
328           pixel->green=quantum >> (image->depth-MAGICKCORE_QUANTUM_DEPTH);
329           p=PushShortPixel(MSBEndian,p,&quantum);
330           pixel->blue=quantum >> (image->depth-MAGICKCORE_QUANTUM_DEPTH);
331         }
332       if (image->colorspace == CMYKColorspace)
333         {
334           p=PushShortPixel(MSBEndian,p,&quantum);
335           pixel->black=quantum >> (image->depth-MAGICKCORE_QUANTUM_DEPTH);
336         }
337       if (image->alpha_trait == BlendPixelTrait)
338         {
339           p=PushShortPixel(MSBEndian,p,&quantum);
340           pixel->alpha=quantum >> (image->depth-MAGICKCORE_QUANTUM_DEPTH);
341         }
342       break;
343     }
344     case 32:
345     {
346       unsigned int
347         quantum;
348
349       p=PushLongPixel(MSBEndian,p,&quantum);
350       pixel->red=quantum >> (image->depth-MAGICKCORE_QUANTUM_DEPTH);
351       pixel->green=pixel->red;
352       pixel->blue=pixel->red;
353       if (IsGrayColorspace(image->colorspace) == MagickFalse)
354         {
355           p=PushLongPixel(MSBEndian,p,&quantum);
356           pixel->green=quantum >> (image->depth-MAGICKCORE_QUANTUM_DEPTH);
357           p=PushLongPixel(MSBEndian,p,&quantum);
358           pixel->blue=quantum >> (image->depth-MAGICKCORE_QUANTUM_DEPTH);
359         }
360       if (image->colorspace == CMYKColorspace)
361         {
362           p=PushLongPixel(MSBEndian,p,&quantum);
363           pixel->black=quantum >> (image->depth-MAGICKCORE_QUANTUM_DEPTH);
364         }
365       if (image->alpha_trait == BlendPixelTrait)
366         {
367           p=PushLongPixel(MSBEndian,p,&quantum);
368           pixel->alpha=quantum >> (image->depth-MAGICKCORE_QUANTUM_DEPTH);
369         }
370       break;
371     }
372     default:
373       (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
374         "ImageDepthNotSupported","`%s'",image->filename);
375   }
376   *length=(size_t) (*p++)+1;
377 }
378
379 #if defined(MAGICKCORE_BZLIB_DELEGATE)
380 static void RelinquishBZIPMemory(void *context,void *memory)
381 {
382   (void) context;
383   memory=RelinquishMagickMemory(memory);
384 }
385 #endif
386
387 #if defined(MAGICKCORE_LZMA_DELEGATE)
388 static void RelinquishLZMAMemory(void *context,void *memory)
389 {
390   (void) context;
391   memory=RelinquishMagickMemory(memory);
392 }
393 #endif
394
395 #if defined(MAGICKCORE_ZLIB_DELEGATE)
396 static void RelinquishZIPMemory(voidpf context,voidpf memory)
397 {
398   (void) context;
399   memory=RelinquishMagickMemory(memory);
400 }
401 #endif
402
403 static Image *ReadMIFFImage(const ImageInfo *image_info,
404   ExceptionInfo *exception)
405 {
406 #define BZipMaxExtent(x)  ((x)+((x)/100)+600)
407 #define LZMAMaxExtent(x)  ((x)+((x)/3)+128)
408 #define ZipMaxExtent(x)  ((x)+(((x)+7) >> 3)+(((x)+63) >> 6)+11)
409
410 #if defined(MAGICKCORE_BZLIB_DELEGATE)
411   bz_stream
412     bzip_info;
413 #endif
414
415   char
416     id[MaxTextExtent],
417     keyword[MaxTextExtent],
418     *options;
419
420   const unsigned char
421     *p;
422
423   double
424     version;
425
426   GeometryInfo
427     geometry_info;
428
429   Image
430     *image;
431
432   int
433     c;
434
435   LinkedListInfo
436     *profiles;
437
438 #if defined(MAGICKCORE_LZMA_DELEGATE)
439   lzma_stream
440     initialize_lzma = LZMA_STREAM_INIT,
441     lzma_info;
442
443   lzma_allocator
444     allocator;
445 #endif
446
447   MagickBooleanType
448     status;
449
450   PixelInfo
451     pixel;
452
453   MagickStatusType
454     flags;
455
456   QuantumFormatType
457     quantum_format;
458
459   QuantumInfo
460     *quantum_info;
461
462   QuantumType
463     quantum_type;
464
465   register ssize_t
466     i;
467
468   size_t
469     length,
470     packet_size;
471
472   ssize_t
473     count;
474
475   unsigned char
476     *compress_pixels,
477     *pixels;
478
479   size_t
480     colors;
481
482   ssize_t
483     y;
484
485 #if defined(MAGICKCORE_ZLIB_DELEGATE)
486   z_stream
487     zip_info;
488 #endif
489
490   /*
491     Open image file.
492   */
493   assert(image_info != (const ImageInfo *) NULL);
494   assert(image_info->signature == MagickSignature);
495   if (image_info->debug != MagickFalse)
496     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
497       image_info->filename);
498   assert(exception != (ExceptionInfo *) NULL);
499   assert(exception->signature == MagickSignature);
500   image=AcquireImage(image_info,exception);
501   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
502   if (status == MagickFalse)
503     {
504       image=DestroyImageList(image);
505       return((Image *) NULL);
506     }
507   /*
508     Decode image header;  header terminates one character beyond a ':'.
509   */
510   c=ReadBlobByte(image);
511   if (c == EOF)
512     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
513   *id='\0';
514   (void) ResetMagickMemory(keyword,0,sizeof(keyword));
515   version=0.0;
516   (void) version;
517   do
518   {
519     /*
520       Decode image header;  header terminates one character beyond a ':'.
521     */
522     length=MaxTextExtent;
523     options=AcquireString((char *) NULL);
524     quantum_format=UndefinedQuantumFormat;
525     profiles=(LinkedListInfo *) NULL;
526     colors=0;
527     image->depth=8UL;
528     image->compression=NoCompression;
529     while ((isgraph(c) != MagickFalse) && (c != (int) ':'))
530     {
531       register char
532         *p;
533
534       if (c == (int) '{')
535         {
536           char
537             *comment;
538
539           /*
540             Read comment-- any text between { }.
541           */
542           length=MaxTextExtent;
543           comment=AcquireString((char *) NULL);
544           for (p=comment; comment != (char *) NULL; p++)
545           {
546             c=ReadBlobByte(image);
547             if (c == (int) '\\')
548               c=ReadBlobByte(image);
549             else
550               if ((c == EOF) || (c == (int) '}'))
551                 break;
552             if ((size_t) (p-comment+1) >= length)
553               {
554                 *p='\0';
555                 length<<=1;
556                 comment=(char *) ResizeQuantumMemory(comment,length+
557                   MaxTextExtent,sizeof(*comment));
558                 if (comment == (char *) NULL)
559                   break;
560                 p=comment+strlen(comment);
561               }
562             *p=(char) c;
563           }
564           if (comment == (char *) NULL)
565             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
566           *p='\0';
567           (void) SetImageProperty(image,"comment",comment,exception);
568           comment=DestroyString(comment);
569           c=ReadBlobByte(image);
570         }
571       else
572         if (isalnum(c) != MagickFalse)
573           {
574             /*
575               Get the keyword.
576             */
577             p=keyword;
578             do
579             {
580               if (c == (int) '=')
581                 break;
582               if ((size_t) (p-keyword) < (MaxTextExtent-1))
583                 *p++=(char) c;
584               c=ReadBlobByte(image);
585             } while (c != EOF);
586             *p='\0';
587             p=options;
588             while ((isspace((int) ((unsigned char) c)) != 0) && (c != EOF))
589               c=ReadBlobByte(image);
590             if (c == (int) '=')
591               {
592                 /*
593                   Get the keyword value.
594                 */
595                 c=ReadBlobByte(image);
596                 while ((c != (int) '}') && (c != EOF))
597                 {
598                   if ((size_t) (p-options+1) >= length)
599                     {
600                       *p='\0';
601                       length<<=1;
602                       options=(char *) ResizeQuantumMemory(options,length+
603                         MaxTextExtent,sizeof(*options));
604                       if (options == (char *) NULL)
605                         break;
606                       p=options+strlen(options);
607                     }
608                   if (options == (char *) NULL)
609                     ThrowReaderException(ResourceLimitError,
610                       "MemoryAllocationFailed");
611                   *p++=(char) c;
612                   c=ReadBlobByte(image);
613                   if (c == '\\')
614                     {
615                       c=ReadBlobByte(image);
616                       if (c == (int) '}')
617                         {
618                           *p++=(char) c;
619                           c=ReadBlobByte(image);
620                         }
621                     }
622                   if (*options != '{')
623                     if (isspace((int) ((unsigned char) c)) != 0)
624                       break;
625                 } }
626             *p='\0';
627             if (*options == '{')
628               (void) CopyMagickString(options,options+1,strlen(options));
629             /*
630               Assign a value to the specified keyword.
631             */
632             switch (*keyword)
633             {
634               case 'a':
635               case 'A':
636               {
637                 if (LocaleCompare(keyword,"alpha-trait") == 0)
638                   {
639                     ssize_t
640                       alpha_trait;
641
642                     alpha_trait=ParseCommandOption(MagickPixelTraitOptions,
643                       MagickFalse,options);
644                     if (alpha_trait < 0)
645                       break;
646                     image->alpha_trait=(PixelTrait) alpha_trait;
647                     break;
648                   }
649                 (void) SetImageProperty(image,keyword,options,exception);
650                 break;
651               }
652               case 'b':
653               case 'B':
654               {
655                 if (LocaleCompare(keyword,"background-color") == 0)
656                   {
657                     (void) QueryColorCompliance(options,AllCompliance,
658                       &image->background_color,exception);
659                     break;
660                   }
661                 if (LocaleCompare(keyword,"blue-primary") == 0)
662                   {
663                     flags=ParseGeometry(options,&geometry_info);
664                     image->chromaticity.blue_primary.x=geometry_info.rho;
665                     image->chromaticity.blue_primary.y=geometry_info.sigma;
666                     if ((flags & SigmaValue) == 0)
667                       image->chromaticity.blue_primary.y=
668                         image->chromaticity.blue_primary.x;
669                     break;
670                   }
671                 if (LocaleCompare(keyword,"border-color") == 0)
672                   {
673                     (void) QueryColorCompliance(options,AllCompliance,
674                       &image->border_color,exception);
675                     break;
676                   }
677                 (void) SetImageProperty(image,keyword,options,exception);
678                 break;
679               }
680               case 'c':
681               case 'C':
682               {
683                 if (LocaleCompare(keyword,"class") == 0)
684                   {
685                     ssize_t
686                       storage_class;
687
688                     storage_class=ParseCommandOption(MagickClassOptions,
689                       MagickFalse,options);
690                     if (storage_class < 0)
691                       break;
692                     image->storage_class=(ClassType) storage_class;
693                     break;
694                   }
695                 if (LocaleCompare(keyword,"colors") == 0)
696                   {
697                     colors=StringToUnsignedLong(options);
698                     break;
699                   }
700                 if (LocaleCompare(keyword,"colorspace") == 0)
701                   {
702                     ssize_t
703                       colorspace;
704
705                     colorspace=ParseCommandOption(MagickColorspaceOptions,
706                       MagickFalse,options);
707                     if (colorspace < 0)
708                       break;
709                     image->colorspace=(ColorspaceType) colorspace;
710                     break;
711                   }
712                 if (LocaleCompare(keyword,"compression") == 0)
713                   {
714                     ssize_t
715                       compression;
716
717                     compression=ParseCommandOption(MagickCompressOptions,
718                       MagickFalse,options);
719                     if (compression < 0)
720                       break;
721                     image->compression=(CompressionType) compression;
722                     break;
723                   }
724                 if (LocaleCompare(keyword,"columns") == 0)
725                   {
726                     image->columns=StringToUnsignedLong(options);
727                     break;
728                   }
729                 (void) SetImageProperty(image,keyword,options,exception);
730                 break;
731               }
732               case 'd':
733               case 'D':
734               {
735                 if (LocaleCompare(keyword,"delay") == 0)
736                   {
737                     image->delay=StringToUnsignedLong(options);
738                     break;
739                   }
740                 if (LocaleCompare(keyword,"depth") == 0)
741                   {
742                     image->depth=StringToUnsignedLong(options);
743                     break;
744                   }
745                 if (LocaleCompare(keyword,"dispose") == 0)
746                   {
747                     ssize_t
748                       dispose;
749
750                     dispose=ParseCommandOption(MagickDisposeOptions,MagickFalse,
751                       options);
752                     if (dispose < 0)
753                       break;
754                     image->dispose=(DisposeType) dispose;
755                     break;
756                   }
757                 (void) SetImageProperty(image,keyword,options,exception);
758                 break;
759               }
760               case 'e':
761               case 'E':
762               {
763                 if (LocaleCompare(keyword,"endian") == 0)
764                   {
765                     ssize_t
766                       endian;
767
768                     endian=ParseCommandOption(MagickEndianOptions,MagickFalse,
769                       options);
770                     if (endian < 0)
771                       break;
772                     image->endian=(EndianType) endian;
773                     break;
774                   }
775                 (void) SetImageProperty(image,keyword,options,exception);
776                 break;
777               }
778               case 'g':
779               case 'G':
780               {
781                 if (LocaleCompare(keyword,"gamma") == 0)
782                   {
783                     image->gamma=StringToDouble(options,(char **) NULL);
784                     break;
785                   }
786                 if (LocaleCompare(keyword,"gravity") == 0)
787                   {
788                     ssize_t
789                       gravity;
790
791                     gravity=ParseCommandOption(MagickGravityOptions,MagickFalse,
792                       options);
793                     if (gravity < 0)
794                       break;
795                     image->gravity=(GravityType) gravity;
796                     break;
797                   }
798                 if (LocaleCompare(keyword,"green-primary") == 0)
799                   {
800                     flags=ParseGeometry(options,&geometry_info);
801                     image->chromaticity.green_primary.x=geometry_info.rho;
802                     image->chromaticity.green_primary.y=geometry_info.sigma;
803                     if ((flags & SigmaValue) == 0)
804                       image->chromaticity.green_primary.y=
805                         image->chromaticity.green_primary.x;
806                     break;
807                   }
808                 (void) SetImageProperty(image,keyword,options,exception);
809                 break;
810               }
811               case 'i':
812               case 'I':
813               {
814                 if (LocaleCompare(keyword,"id") == 0)
815                   {
816                     (void) CopyMagickString(id,options,MaxTextExtent);
817                     break;
818                   }
819                 if (LocaleCompare(keyword,"iterations") == 0)
820                   {
821                     image->iterations=StringToUnsignedLong(options);
822                     break;
823                   }
824                 (void) SetImageProperty(image,keyword,options,exception);
825                 break;
826               }
827               case 'm':
828               case 'M':
829               {
830                 if (LocaleCompare(keyword,"matte") == 0)
831                   {
832                     ssize_t
833                       matte;
834
835                     matte=ParseCommandOption(MagickBooleanOptions,MagickFalse,
836                       options);
837                     if (matte < 0)
838                       break;
839                     image->alpha_trait=matte == 0 ? UndefinedPixelTrait :
840                       BlendPixelTrait;
841                     break;
842                   }
843                 if (LocaleCompare(keyword,"matte-color") == 0)
844                   {
845                     (void) QueryColorCompliance(options,AllCompliance,
846                       &image->matte_color,exception);
847                     break;
848                   }
849                 if (LocaleCompare(keyword,"montage") == 0)
850                   {
851                     (void) CloneString(&image->montage,options);
852                     break;
853                   }
854                 (void) SetImageProperty(image,keyword,options,exception);
855                 break;
856               }
857               case 'o':
858               case 'O':
859               {
860                 if (LocaleCompare(keyword,"orientation") == 0)
861                   {
862                     ssize_t
863                       orientation;
864
865                     orientation=ParseCommandOption(MagickOrientationOptions,
866                       MagickFalse,options);
867                     if (orientation < 0)
868                       break;
869                     image->orientation=(OrientationType) orientation;
870                     break;
871                   }
872                 (void) SetImageProperty(image,keyword,options,exception);
873                 break;
874               }
875               case 'p':
876               case 'P':
877               {
878                 if (LocaleCompare(keyword,"page") == 0)
879                   {
880                     char
881                       *geometry;
882
883                     geometry=GetPageGeometry(options);
884                     (void) ParseAbsoluteGeometry(geometry,&image->page);
885                     geometry=DestroyString(geometry);
886                     break;
887                   }
888                 if (LocaleCompare(keyword,"pixel-intensity") == 0)
889                   {
890                     ssize_t
891                       intensity;
892
893                     intensity=ParseCommandOption(MagickPixelIntensityOptions,
894                       MagickFalse,options);
895                     if (intensity < 0)
896                       break;
897                     image->intensity=(PixelIntensityMethod) intensity;
898                     break;
899                   }
900                 if ((LocaleNCompare(keyword,"profile:",8) == 0) ||
901                     (LocaleNCompare(keyword,"profile-",8) == 0))
902                   {
903                     StringInfo
904                       *profile;
905
906                     if (profiles == (LinkedListInfo *) NULL)
907                       profiles=NewLinkedList(0);
908                     (void) AppendValueToLinkedList(profiles,
909                       AcquireString(keyword+8));
910                     profile=BlobToStringInfo((const void *) NULL,(size_t)
911                       StringToLong(options));
912                     if (profile == (StringInfo *) NULL)
913                       ThrowReaderException(ResourceLimitError,
914                         "MemoryAllocationFailed");
915                     (void) SetImageProfile(image,keyword+8,profile,exception);
916                     profile=DestroyStringInfo(profile);
917                     break;
918                   }
919                 (void) SetImageProperty(image,keyword,options,exception);
920                 break;
921               }
922               case 'q':
923               case 'Q':
924               {
925                 if (LocaleCompare(keyword,"quality") == 0)
926                   {
927                     image->quality=StringToUnsignedLong(options);
928                     break;
929                   }
930                 if ((LocaleCompare(keyword,"quantum-format") == 0) ||
931                     (LocaleCompare(keyword,"quantum:format") == 0))
932                   {
933                     ssize_t
934                       format;
935
936                     format=ParseCommandOption(MagickQuantumFormatOptions,
937                       MagickFalse,options);
938                     if (format < 0)
939                       break;
940                     quantum_format=(QuantumFormatType) format;
941                     break;
942                   }
943                 (void) SetImageProperty(image,keyword,options,exception);
944                 break;
945               }
946               case 'r':
947               case 'R':
948               {
949                 if (LocaleCompare(keyword,"red-primary") == 0)
950                   {
951                     flags=ParseGeometry(options,&geometry_info);
952                     image->chromaticity.red_primary.x=geometry_info.rho;
953                     image->chromaticity.red_primary.y=geometry_info.sigma;
954                     if ((flags & SigmaValue) == 0)
955                       image->chromaticity.red_primary.y=
956                         image->chromaticity.red_primary.x;
957                     break;
958                   }
959                 if (LocaleCompare(keyword,"rendering-intent") == 0)
960                   {
961                     ssize_t
962                       rendering_intent;
963
964                     rendering_intent=ParseCommandOption(MagickIntentOptions,
965                       MagickFalse,options);
966                     if (rendering_intent < 0)
967                       break;
968                     image->rendering_intent=(RenderingIntent) rendering_intent;
969                     break;
970                   }
971                 if (LocaleCompare(keyword,"resolution") == 0)
972                   {
973                     flags=ParseGeometry(options,&geometry_info);
974                     image->resolution.x=geometry_info.rho;
975                     image->resolution.y=geometry_info.sigma;
976                     if ((flags & SigmaValue) == 0)
977                       image->resolution.y=image->resolution.x;
978                     break;
979                   }
980                 if (LocaleCompare(keyword,"rows") == 0)
981                   {
982                     image->rows=StringToUnsignedLong(options);
983                     break;
984                   }
985                 (void) SetImageProperty(image,keyword,options,exception);
986                 break;
987               }
988               case 's':
989               case 'S':
990               {
991                 if (LocaleCompare(keyword,"scene") == 0)
992                   {
993                     image->scene=StringToUnsignedLong(options);
994                     break;
995                   }
996                 (void) SetImageProperty(image,keyword,options,exception);
997                 break;
998               }
999               case 't':
1000               case 'T':
1001               {
1002                 if (LocaleCompare(keyword,"ticks-per-second") == 0)
1003                   {
1004                     image->ticks_per_second=(ssize_t) StringToLong(options);
1005                     break;
1006                   }
1007                 if (LocaleCompare(keyword,"tile-offset") == 0)
1008                   {
1009                     char
1010                       *geometry;
1011
1012                     geometry=GetPageGeometry(options);
1013                     (void) ParseAbsoluteGeometry(geometry,&image->tile_offset);
1014                     geometry=DestroyString(geometry);
1015                     break;
1016                   }
1017                 if (LocaleCompare(keyword,"type") == 0)
1018                   {
1019                     ssize_t
1020                       type;
1021
1022                     type=ParseCommandOption(MagickTypeOptions,MagickFalse,
1023                       options);
1024                     if (type < 0)
1025                       break;
1026                     image->type=(ImageType) type;
1027                     break;
1028                   }
1029                 (void) SetImageProperty(image,keyword,options,exception);
1030                 break;
1031               }
1032               case 'u':
1033               case 'U':
1034               {
1035                 if (LocaleCompare(keyword,"units") == 0)
1036                   {
1037                     ssize_t
1038                       units;
1039
1040                     units=ParseCommandOption(MagickResolutionOptions,
1041                       MagickFalse,options);
1042                     if (units < 0)
1043                       break;
1044                     image->units=(ResolutionType) units;
1045                     break;
1046                   }
1047                 (void) SetImageProperty(image,keyword,options,exception);
1048                 break;
1049               }
1050               case 'v':
1051               case 'V':
1052               {
1053                 if (LocaleCompare(keyword,"version") == 0)
1054                   {
1055                     version=StringToDouble(options,(char **) NULL);
1056                     break;
1057                   }
1058                 (void) SetImageProperty(image,keyword,options,exception);
1059                 break;
1060               }
1061               case 'w':
1062               case 'W':
1063               {
1064                 if (LocaleCompare(keyword,"white-point") == 0)
1065                   {
1066                     flags=ParseGeometry(options,&geometry_info);
1067                     image->chromaticity.white_point.x=geometry_info.rho;
1068                     image->chromaticity.white_point.y=geometry_info.sigma;
1069                     if ((flags & SigmaValue) == 0)
1070                       image->chromaticity.white_point.y=
1071                         image->chromaticity.white_point.x;
1072                     break;
1073                   }
1074                 (void) SetImageProperty(image,keyword,options,exception);
1075                 break;
1076               }
1077               default:
1078               {
1079                 (void) SetImageProperty(image,keyword,options,exception);
1080                 break;
1081               }
1082             }
1083           }
1084         else
1085           c=ReadBlobByte(image);
1086       while (isspace((int) ((unsigned char) c)) != 0)
1087         c=ReadBlobByte(image);
1088     }
1089     options=DestroyString(options);
1090     (void) ReadBlobByte(image);
1091     /*
1092       Verify that required image information is defined.
1093     */
1094     if ((LocaleCompare(id,"ImageMagick") != 0) ||
1095         (image->storage_class == UndefinedClass) ||
1096         (image->columns == 0) || (image->rows == 0))
1097       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1098     if (image->montage != (char *) NULL)
1099       {
1100         register char
1101           *p;
1102
1103         /*
1104           Image directory.
1105         */
1106         length=MaxTextExtent;
1107         image->directory=AcquireString((char *) NULL);
1108         p=image->directory;
1109         do
1110         {
1111           *p='\0';
1112           if ((strlen(image->directory)+MaxTextExtent) >= length)
1113             {
1114               /*
1115                 Allocate more memory for the image directory.
1116               */
1117               length<<=1;
1118               image->directory=(char *) ResizeQuantumMemory(image->directory,
1119                 length+MaxTextExtent,sizeof(*image->directory));
1120               if (image->directory == (char *) NULL)
1121                 ThrowReaderException(CorruptImageError,"UnableToReadImageData");
1122               p=image->directory+strlen(image->directory);
1123             }
1124           c=ReadBlobByte(image);
1125           *p++=(char) c;
1126         } while (c != (int) '\0');
1127       }
1128     if (profiles != (LinkedListInfo *) NULL)
1129       {
1130         const char
1131           *name;
1132
1133         const StringInfo
1134           *profile;
1135
1136         /*
1137           Read image profiles.
1138         */
1139         ResetLinkedListIterator(profiles);
1140         name=(const char *) GetNextValueInLinkedList(profiles);
1141         while (name != (const char *) NULL)
1142         {
1143           profile=GetImageProfile(image,name);
1144           if (profile != (StringInfo *) NULL)
1145             {
1146               register unsigned char
1147                 *p;
1148
1149               p=GetStringInfoDatum(profile);
1150               count=ReadBlob(image,GetStringInfoLength(profile),p);
1151               (void) count;
1152             }
1153           name=(const char *) GetNextValueInLinkedList(profiles);
1154         }
1155         profiles=DestroyLinkedList(profiles,RelinquishMagickMemory);
1156       }
1157     image->depth=GetImageQuantumDepth(image,MagickFalse);
1158     if (image->storage_class == PseudoClass)
1159       {
1160         /*
1161           Create image colormap.
1162         */
1163         status=AcquireImageColormap(image,colors != 0 ? colors : 256,exception);
1164         if (status == MagickFalse)
1165           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1166         if (colors != 0)
1167           {
1168             size_t
1169               packet_size;
1170
1171             unsigned char
1172               *colormap;
1173
1174             /*
1175               Read image colormap from file.
1176             */
1177             packet_size=(size_t) (3UL*image->depth/8UL);
1178             colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
1179               packet_size*sizeof(*colormap));
1180             if (colormap == (unsigned char *) NULL)
1181               ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1182             count=ReadBlob(image,packet_size*image->colors,colormap);
1183             p=colormap;
1184             switch (image->depth)
1185             {
1186               default:
1187                 ThrowReaderException(CorruptImageError,
1188                   "ImageDepthNotSupported");
1189               case 8:
1190               {
1191                 unsigned char
1192                   pixel;
1193
1194                 for (i=0; i < (ssize_t) image->colors; i++)
1195                 {
1196                   p=PushCharPixel(p,&pixel);
1197                   image->colormap[i].red=ScaleCharToQuantum(pixel);
1198                   p=PushCharPixel(p,&pixel);
1199                   image->colormap[i].green=ScaleCharToQuantum(pixel);
1200                   p=PushCharPixel(p,&pixel);
1201                   image->colormap[i].blue=ScaleCharToQuantum(pixel);
1202                 }
1203                 break;
1204               }
1205               case 16:
1206               {
1207                 unsigned short
1208                   pixel;
1209
1210                 for (i=0; i < (ssize_t) image->colors; i++)
1211                 {
1212                   p=PushShortPixel(MSBEndian,p,&pixel);
1213                   image->colormap[i].red=ScaleShortToQuantum(pixel);
1214                   p=PushShortPixel(MSBEndian,p,&pixel);
1215                   image->colormap[i].green=ScaleShortToQuantum(pixel);
1216                   p=PushShortPixel(MSBEndian,p,&pixel);
1217                   image->colormap[i].blue=ScaleShortToQuantum(pixel);
1218                 }
1219                 break;
1220               }
1221               case 32:
1222               {
1223                 unsigned int
1224                   pixel;
1225
1226                 for (i=0; i < (ssize_t) image->colors; i++)
1227                 {
1228                   p=PushLongPixel(MSBEndian,p,&pixel);
1229                   image->colormap[i].red=ScaleLongToQuantum(pixel);
1230                   p=PushLongPixel(MSBEndian,p,&pixel);
1231                   image->colormap[i].green=ScaleLongToQuantum(pixel);
1232                   p=PushLongPixel(MSBEndian,p,&pixel);
1233                   image->colormap[i].blue=ScaleLongToQuantum(pixel);
1234                 }
1235                 break;
1236               }
1237             }
1238             colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1239           }
1240       }
1241     if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
1242       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1243         break;
1244     /*
1245       Allocate image pixels.
1246     */
1247     quantum_info=AcquireQuantumInfo(image_info,image);
1248     if (quantum_info == (QuantumInfo *) NULL)
1249       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1250     if (quantum_format != UndefinedQuantumFormat)
1251       {
1252         status=SetQuantumFormat(image,quantum_info,quantum_format);
1253         if (status == MagickFalse)
1254           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1255       }
1256     packet_size=(size_t) (quantum_info->depth/8);
1257     if (image->storage_class == DirectClass)
1258       packet_size=(size_t) (3*quantum_info->depth/8);
1259     if (IsGrayColorspace(image->colorspace) != MagickFalse)
1260       packet_size=quantum_info->depth/8;
1261     if (image->alpha_trait == BlendPixelTrait)
1262       packet_size+=quantum_info->depth/8;
1263     if (image->colorspace == CMYKColorspace)
1264       packet_size+=quantum_info->depth/8;
1265     if (image->compression == RLECompression)
1266       packet_size++;
1267     length=image->columns;
1268     length=MagickMax(MagickMax(BZipMaxExtent(packet_size*image->columns),
1269       LZMAMaxExtent(packet_size*image->columns)),ZipMaxExtent(packet_size*
1270       image->columns));
1271     compress_pixels=(unsigned char *) AcquireQuantumMemory(length,
1272       sizeof(*compress_pixels));
1273     if (compress_pixels == (unsigned char *) NULL)
1274       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1275     /*
1276       Read image pixels.
1277     */
1278     quantum_type=RGBQuantum;
1279     if (image->alpha_trait == BlendPixelTrait)
1280       quantum_type=RGBAQuantum;
1281     if (image->colorspace == CMYKColorspace)
1282       {
1283         quantum_type=CMYKQuantum;
1284         if (image->alpha_trait == BlendPixelTrait)
1285           quantum_type=CMYKAQuantum;
1286       }
1287     if (IsGrayColorspace(image->colorspace) != MagickFalse)
1288       {
1289         quantum_type=GrayQuantum;
1290         if (image->alpha_trait == BlendPixelTrait)
1291           quantum_type=GrayAlphaQuantum;
1292       }
1293     if (image->storage_class == PseudoClass)
1294       {
1295         quantum_type=IndexQuantum;
1296         if (image->alpha_trait == BlendPixelTrait)
1297           quantum_type=IndexAlphaQuantum;
1298       }
1299     status=MagickTrue;
1300     GetPixelInfo(image,&pixel);
1301 #if defined(MAGICKCORE_BZLIB_DELEGATE)
1302    (void) ResetMagickMemory(&bzip_info,0,sizeof(bzip_info));
1303 #endif
1304 #if defined(MAGICKCORE_LZMA_DELEGATE)
1305     (void) ResetMagickMemory(&allocator,0,sizeof(allocator));
1306 #endif
1307 #if defined(MAGICKCORE_ZLIB_DELEGATE)
1308     (void) ResetMagickMemory(&zip_info,0,sizeof(zip_info));
1309 #endif
1310     switch (image->compression)
1311     {
1312 #if defined(MAGICKCORE_BZLIB_DELEGATE)
1313       case BZipCompression:
1314       {
1315         int
1316           code;
1317
1318         bzip_info.bzalloc=AcquireBZIPMemory;
1319         bzip_info.bzfree=RelinquishBZIPMemory;
1320         bzip_info.opaque=(void *) NULL;
1321         code=BZ2_bzDecompressInit(&bzip_info,(int) image_info->verbose,
1322           MagickFalse);
1323         if (code != BZ_OK)
1324           status=MagickFalse;
1325         break;
1326       }
1327 #endif
1328 #if defined(MAGICKCORE_LZMA_DELEGATE)
1329       case LZMACompression:
1330       {
1331         int
1332           code;
1333
1334         allocator.alloc=AcquireLZMAMemory;
1335         allocator.free=RelinquishLZMAMemory;
1336         lzma_info=initialize_lzma;
1337         lzma_info.allocator=(&allocator);
1338         code=lzma_auto_decoder(&lzma_info,-1,0);
1339         if (code != LZMA_OK)
1340           status=MagickFalse;
1341         break;
1342       }
1343 #endif
1344 #if defined(MAGICKCORE_ZLIB_DELEGATE)
1345       case LZWCompression:
1346       case ZipCompression:
1347       {
1348         int
1349           code;
1350
1351         zip_info.zalloc=AcquireZIPMemory;
1352         zip_info.zfree=RelinquishZIPMemory;
1353         zip_info.opaque=(voidpf) NULL;
1354         code=inflateInit(&zip_info);
1355         if (code != Z_OK)
1356           status=MagickFalse;
1357         break;
1358       }
1359 #endif
1360       case RLECompression:
1361         break;
1362       default:
1363         break;
1364     }
1365     pixels=GetQuantumPixels(quantum_info);
1366     length=0;
1367     for (y=0; y < (ssize_t) image->rows; y++)
1368     {
1369       register ssize_t
1370         x;
1371
1372       register Quantum
1373         *restrict q;
1374
1375       if (status == MagickFalse)
1376         break;
1377       q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1378       if (q == (Quantum *) NULL)
1379         break;
1380       switch (image->compression)
1381       {
1382 #if defined(MAGICKCORE_BZLIB_DELEGATE)
1383         case BZipCompression:
1384         {
1385           bzip_info.next_out=(char *) pixels;
1386           bzip_info.avail_out=(unsigned int) (packet_size*image->columns);
1387           do
1388           {
1389             if (bzip_info.avail_in == 0)
1390               {
1391                 bzip_info.next_in=(char *) compress_pixels;
1392                 length=(size_t) BZipMaxExtent(packet_size*image->columns);
1393                 if (version != 0.0)
1394                   length=(size_t) ReadBlobMSBLong(image);
1395                 bzip_info.avail_in=(unsigned int) ReadBlob(image,length,
1396                   (unsigned char *) bzip_info.next_in);
1397               }
1398             if (BZ2_bzDecompress(&bzip_info) == BZ_STREAM_END)
1399               break;
1400           } while (bzip_info.avail_out != 0);
1401           (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1402             quantum_type,pixels,exception);
1403           break;
1404         }
1405 #endif
1406 #if defined(MAGICKCORE_LZMA_DELEGATE)
1407         case LZMACompression:
1408         {
1409           lzma_info.next_out=pixels;
1410           lzma_info.avail_out=packet_size*image->columns;
1411           do
1412           {
1413             int
1414               code;
1415
1416             if (lzma_info.avail_in == 0)
1417               {
1418                 lzma_info.next_in=compress_pixels;
1419                 length=(size_t) ReadBlobMSBLong(image);
1420                 lzma_info.avail_in=(unsigned int) ReadBlob(image,length,
1421                   (unsigned char *) lzma_info.next_in);
1422               }
1423             code=lzma_code(&lzma_info,LZMA_RUN);
1424             if (code < 0)
1425               {
1426                 status=MagickFalse;
1427                 break;
1428               }
1429             if (code == LZMA_STREAM_END)
1430               break;
1431           } while (lzma_info.avail_out != 0);
1432           (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1433             quantum_type,pixels,exception);
1434           break;
1435         }
1436 #endif
1437 #if defined(MAGICKCORE_ZLIB_DELEGATE)
1438         case LZWCompression:
1439         case ZipCompression:
1440         {
1441           zip_info.next_out=pixels;
1442           zip_info.avail_out=(uInt) (packet_size*image->columns);
1443           do
1444           {
1445             if (zip_info.avail_in == 0)
1446               {
1447                 zip_info.next_in=compress_pixels;
1448                 length=(size_t) ZipMaxExtent(packet_size*image->columns);
1449                 if (version != 0.0)
1450                   length=(size_t) ReadBlobMSBLong(image);
1451                 zip_info.avail_in=(unsigned int) ReadBlob(image,length,
1452                   zip_info.next_in);
1453               }
1454             if (inflate(&zip_info,Z_SYNC_FLUSH) == Z_STREAM_END)
1455               break;
1456           } while (zip_info.avail_out != 0);
1457           (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1458             quantum_type,pixels,exception);
1459           break;
1460         }
1461 #endif
1462         case RLECompression:
1463         {
1464           for (x=0; x < (ssize_t) image->columns; x++)
1465           {
1466             if (length == 0)
1467               {
1468                 count=ReadBlob(image,packet_size,pixels);
1469                 PushRunlengthPacket(image,pixels,&length,&pixel,exception);
1470               }
1471             length--;
1472             if (image->storage_class == PseudoClass)
1473               SetPixelIndex(image,ClampToQuantum(pixel.index),q);
1474             else
1475               {
1476                 SetPixelRed(image,ClampToQuantum(pixel.red),q);
1477                 SetPixelGreen(image,ClampToQuantum(pixel.green),q);
1478                 SetPixelBlue(image,ClampToQuantum(pixel.blue),q);
1479                 if (image->colorspace == CMYKColorspace)
1480                   SetPixelBlack(image,ClampToQuantum(pixel.black),q);
1481               }
1482             if (image->alpha_trait == BlendPixelTrait)
1483               SetPixelAlpha(image,ClampToQuantum(pixel.alpha),q);
1484             q+=GetPixelChannels(image);
1485           }
1486           break;
1487         }
1488         default:
1489         {
1490           count=ReadBlob(image,packet_size*image->columns,pixels);
1491           (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1492             quantum_type,pixels,exception);
1493           break;
1494         }
1495       }
1496       if (SyncAuthenticPixels(image,exception) == MagickFalse)
1497         break;
1498     }
1499     SetQuantumImageType(image,quantum_type);
1500     switch (image->compression)
1501     {
1502 #if defined(MAGICKCORE_BZLIB_DELEGATE)
1503       case BZipCompression:
1504       {
1505         int
1506           code;
1507
1508         if (version == 0.0)
1509           {
1510             MagickOffsetType
1511               offset;
1512
1513             offset=SeekBlob(image,-((MagickOffsetType)
1514               bzip_info.avail_in),SEEK_CUR);
1515             if (offset < 0)
1516               ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1517           }
1518         code=BZ2_bzDecompressEnd(&bzip_info);
1519         if (code != BZ_OK)
1520           status=MagickFalse;
1521         break;
1522       }
1523 #endif
1524 #if defined(MAGICKCORE_LZMA_DELEGATE)
1525       case LZMACompression:
1526       {
1527         int
1528           code;
1529
1530         code=lzma_code(&lzma_info,LZMA_FINISH);
1531         if ((code != LZMA_STREAM_END) && (code != LZMA_OK))
1532           status=MagickFalse;
1533         lzma_end(&lzma_info);
1534         break;
1535       }
1536 #endif
1537 #if defined(MAGICKCORE_ZLIB_DELEGATE)
1538       case LZWCompression:
1539       case ZipCompression:
1540       {
1541         int
1542           code;
1543
1544         if (version == 0.0)
1545           {
1546             MagickOffsetType
1547               offset;
1548
1549             offset=SeekBlob(image,-((MagickOffsetType) zip_info.avail_in),
1550               SEEK_CUR);
1551             if (offset < 0)
1552               ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1553           }
1554         code=inflateEnd(&zip_info);
1555         if (code != LZMA_OK)
1556           status=MagickFalse;
1557         break;
1558       }
1559 #endif
1560       default:
1561         break;
1562     }
1563     quantum_info=DestroyQuantumInfo(quantum_info);
1564     compress_pixels=(unsigned char *) RelinquishMagickMemory(compress_pixels);
1565     if (((y != (ssize_t) image->rows)) || (status == MagickFalse))
1566       {
1567         image=DestroyImageList(image);
1568         return((Image *) NULL);
1569       }
1570     if (EOFBlob(image) != MagickFalse)
1571       {
1572         ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
1573           image->filename);
1574         break;
1575       }
1576     /*
1577       Proceed to next image.
1578     */
1579     if (image_info->number_scenes != 0)
1580       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1581         break;
1582     do
1583     {
1584       c=ReadBlobByte(image);
1585     } while ((isgraph(c) == MagickFalse) && (c != EOF));
1586     if (c != EOF)
1587       {
1588         /*
1589           Allocate next image structure.
1590         */
1591         AcquireNextImage(image_info,image,exception);
1592         if (GetNextImageInList(image) == (Image *) NULL)
1593           {
1594             image=DestroyImageList(image);
1595             return((Image *) NULL);
1596           }
1597         image=SyncNextImageInList(image);
1598         status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
1599           GetBlobSize(image));
1600         if (status == MagickFalse)
1601           break;
1602       }
1603   } while (c != EOF);
1604   (void) CloseBlob(image);
1605   return(GetFirstImageInList(image));
1606 }
1607 \f
1608 /*
1609 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1610 %                                                                             %
1611 %                                                                             %
1612 %                                                                             %
1613 %   R e g i s t e r M I F F I m a g e                                         %
1614 %                                                                             %
1615 %                                                                             %
1616 %                                                                             %
1617 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1618 %
1619 %  RegisterMIFFImage() adds properties for the MIFF image format to the list of
1620 %  supported formats.  The properties include the image format tag, a method to
1621 %  read and/or write the format, whether the format supports the saving of more
1622 %  than one frame to the same file or blob, whether the format supports native
1623 %  in-memory I/O, and a brief description of the format.
1624 %
1625 %  The format of the RegisterMIFFImage method is:
1626 %
1627 %      size_t RegisterMIFFImage(void)
1628 %
1629 */
1630 ModuleExport size_t RegisterMIFFImage(void)
1631 {
1632   char
1633     version[MaxTextExtent];
1634
1635   MagickInfo
1636     *entry;
1637
1638   *version='\0';
1639 #if defined(MagickImageCoderSignatureText)
1640   (void) CopyMagickString(version,MagickLibVersionText,MaxTextExtent);
1641 #if defined(ZLIB_VERSION)
1642   (void) ConcatenateMagickString(version," with Zlib ",MaxTextExtent);
1643   (void) ConcatenateMagickString(version,ZLIB_VERSION,MaxTextExtent);
1644 #endif
1645 #if defined(MAGICKCORE_BZLIB_DELEGATE)
1646   (void) ConcatenateMagickString(version," and BZlib",MaxTextExtent);
1647 #endif
1648 #endif
1649   entry=SetMagickInfo("MIFF");
1650   entry->decoder=(DecodeImageHandler *) ReadMIFFImage;
1651   entry->encoder=(EncodeImageHandler *) WriteMIFFImage;
1652   entry->magick=(IsImageFormatHandler *) IsMIFF;
1653   entry->seekable_stream=MagickTrue;
1654   entry->description=ConstantString("Magick Image File Format");
1655   if (*version != '\0')
1656     entry->version=ConstantString(version);
1657   entry->module=ConstantString("MIFF");
1658   (void) RegisterMagickInfo(entry);
1659   return(MagickImageCoderSignature);
1660 }
1661 \f
1662 /*
1663 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1664 %                                                                             %
1665 %                                                                             %
1666 %                                                                             %
1667 %   U n r e g i s t e r M I F F I m a g e                                     %
1668 %                                                                             %
1669 %                                                                             %
1670 %                                                                             %
1671 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1672 %
1673 %  UnregisterMIFFImage() removes format registrations made by the MIFF module
1674 %  from the list of supported formats.
1675 %
1676 %  The format of the UnregisterMIFFImage method is:
1677 %
1678 %      UnregisterMIFFImage(void)
1679 %
1680 */
1681 ModuleExport void UnregisterMIFFImage(void)
1682 {
1683   (void) UnregisterMagickInfo("MIFF");
1684 }
1685 \f
1686 /*
1687 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1688 %                                                                             %
1689 %                                                                             %
1690 %                                                                             %
1691 %   W r i t e M I F F I m a g e                                               %
1692 %                                                                             %
1693 %                                                                             %
1694 %                                                                             %
1695 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1696 %
1697 %  WriteMIFFImage() writes a MIFF image to a file.
1698 %
1699 %  The format of the WriteMIFFImage method is:
1700 %
1701 %      MagickBooleanType WriteMIFFImage(const ImageInfo *image_info,
1702 %        Image *image,ExceptionInfo *exception)
1703 %
1704 %  Compression code contributed by Kyle Shorter.
1705 %
1706 %  A description of each parameter follows:
1707 %
1708 %    o image_info: the image info.
1709 %
1710 %    o image: the image.
1711 %
1712 %    o exception: return any errors or warnings in this structure.
1713 %
1714 */
1715
1716 static unsigned char *PopRunlengthPacket(Image *image,unsigned char *pixels,
1717   size_t length,PixelInfo *pixel,ExceptionInfo *exception)
1718 {
1719   if (image->storage_class != DirectClass)
1720     {
1721       unsigned int
1722         value;
1723
1724       value=(unsigned int) ClampToQuantum(pixel->index);
1725       switch (image->depth)
1726       {
1727         case 32:
1728         {
1729           *pixels++=(unsigned char) (value >> 24);
1730           *pixels++=(unsigned char) (value >> 16);
1731         }
1732         case 16:
1733           *pixels++=(unsigned char) (value >> 8);
1734         case 8:
1735         {
1736           *pixels++=(unsigned char) value;
1737           break;
1738         }
1739         default:
1740           (void) ThrowMagickException(exception,GetMagickModule(),
1741             CorruptImageError,"ImageDepthNotSupported","`%s'",image->filename);
1742       }
1743       switch (image->depth)
1744       {
1745         case 32:
1746         {
1747           unsigned int
1748             value;
1749
1750           if (image->alpha_trait == BlendPixelTrait)
1751             {
1752               value=ScaleQuantumToLong(ClampToQuantum(pixel->alpha));
1753               pixels=PopLongPixel(MSBEndian,value,pixels);
1754             }
1755           break;
1756         }
1757         case 16:
1758         {
1759           unsigned short
1760             value;
1761
1762           if (image->alpha_trait == BlendPixelTrait)
1763             {
1764               value=ScaleQuantumToShort(ClampToQuantum(pixel->alpha));
1765               pixels=PopShortPixel(MSBEndian,value,pixels);
1766             }
1767           break;
1768         }
1769         case 8:
1770         {
1771           unsigned char
1772             value;
1773
1774           if (image->alpha_trait == BlendPixelTrait)
1775             {
1776               value=(unsigned char) ScaleQuantumToChar(ClampToQuantum(
1777                 pixel->alpha));
1778               pixels=PopCharPixel(value,pixels);
1779             }
1780           break;
1781         }
1782         default:
1783           (void) ThrowMagickException(exception,GetMagickModule(),
1784             CorruptImageError,"ImageDepthNotSupported","`%s'",image->filename);
1785       }
1786       *pixels++=(unsigned char) length;
1787       return(pixels);
1788     }
1789   switch (image->depth)
1790   {
1791     case 32:
1792     {
1793       unsigned int
1794         value;
1795
1796       value=ScaleQuantumToLong(ClampToQuantum(pixel->red));
1797       pixels=PopLongPixel(MSBEndian,value,pixels);
1798       if (IsGrayColorspace(image->colorspace) == MagickFalse)
1799         {
1800           value=ScaleQuantumToLong(ClampToQuantum(pixel->green));
1801           pixels=PopLongPixel(MSBEndian,value,pixels);
1802           value=ScaleQuantumToLong(ClampToQuantum(pixel->blue));
1803           pixels=PopLongPixel(MSBEndian,value,pixels);
1804         }
1805       if (image->colorspace == CMYKColorspace)
1806         {
1807           value=ScaleQuantumToLong(ClampToQuantum(pixel->black));
1808           pixels=PopLongPixel(MSBEndian,value,pixels);
1809         }
1810       if (image->alpha_trait == BlendPixelTrait)
1811         {
1812           value=ScaleQuantumToLong(ClampToQuantum(pixel->alpha));
1813           pixels=PopLongPixel(MSBEndian,value,pixels);
1814         }
1815       break;
1816     }
1817     case 16:
1818     {
1819       unsigned short
1820         value;
1821
1822       value=ScaleQuantumToShort(ClampToQuantum(pixel->red));
1823       pixels=PopShortPixel(MSBEndian,value,pixels);
1824       if (IsGrayColorspace(image->colorspace) == MagickFalse)
1825         {
1826           value=ScaleQuantumToShort(ClampToQuantum(pixel->green));
1827           pixels=PopShortPixel(MSBEndian,value,pixels);
1828           value=ScaleQuantumToShort(ClampToQuantum(pixel->blue));
1829           pixels=PopShortPixel(MSBEndian,value,pixels);
1830         }
1831       if (image->colorspace == CMYKColorspace)
1832         {
1833           value=ScaleQuantumToShort(ClampToQuantum(pixel->black));
1834           pixels=PopShortPixel(MSBEndian,value,pixels);
1835         }
1836       if (image->alpha_trait == BlendPixelTrait)
1837         {
1838           value=ScaleQuantumToShort(ClampToQuantum(pixel->alpha));
1839           pixels=PopShortPixel(MSBEndian,value,pixels);
1840         }
1841       break;
1842     }
1843     case 8:
1844     {
1845       unsigned char
1846         value;
1847
1848       value=(unsigned char) ScaleQuantumToChar(ClampToQuantum(pixel->red));
1849       pixels=PopCharPixel(value,pixels);
1850       if (IsGrayColorspace(image->colorspace) == MagickFalse)
1851         {
1852           value=(unsigned char) ScaleQuantumToChar(ClampToQuantum(
1853             pixel->green));
1854           pixels=PopCharPixel(value,pixels);
1855           value=(unsigned char) ScaleQuantumToChar(ClampToQuantum(pixel->blue));
1856           pixels=PopCharPixel(value,pixels);
1857         }
1858       if (image->colorspace == CMYKColorspace)
1859         {
1860           value=(unsigned char) ScaleQuantumToChar(ClampToQuantum(
1861             pixel->black));
1862           pixels=PopCharPixel(value,pixels);
1863         }
1864       if (image->alpha_trait == BlendPixelTrait)
1865         {
1866           value=(unsigned char) ScaleQuantumToChar(ClampToQuantum(
1867             pixel->alpha));
1868           pixels=PopCharPixel(value,pixels);
1869         }
1870       break;
1871     }
1872     default:
1873       (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
1874         "ImageDepthNotSupported","`%s'",image->filename);
1875   }
1876   *pixels++=(unsigned char) length;
1877   return(pixels);
1878 }
1879
1880 static MagickBooleanType WriteMIFFImage(const ImageInfo *image_info,
1881   Image *image,ExceptionInfo *exception)
1882 {
1883 #if defined(MAGICKCORE_BZLIB_DELEGATE)
1884   bz_stream
1885     bzip_info;
1886 #endif
1887
1888   char
1889     buffer[MaxTextExtent];
1890
1891   CompressionType
1892     compression;
1893
1894   const char
1895     *property,
1896     *value;
1897
1898 #if defined(MAGICKCORE_LZMA_DELEGATE)
1899   lzma_allocator
1900     allocator;
1901
1902   lzma_stream
1903     initialize_lzma = LZMA_STREAM_INIT,
1904     lzma_info;
1905 #endif
1906
1907   MagickBooleanType
1908     status;
1909
1910   MagickOffsetType
1911     scene;
1912
1913   PixelInfo
1914     pixel,
1915     target;
1916
1917   QuantumInfo
1918     *quantum_info;
1919
1920   QuantumType
1921     quantum_type;
1922
1923   register ssize_t
1924     i;
1925
1926   size_t
1927     length,
1928     packet_size;
1929
1930   ssize_t
1931     y;
1932
1933   unsigned char
1934     *compress_pixels,
1935     *pixels,
1936     *q;
1937
1938 #if defined(MAGICKCORE_ZLIB_DELEGATE)
1939   z_stream
1940     zip_info;
1941 #endif
1942
1943   /*
1944     Open output image file.
1945   */
1946   assert(image_info != (const ImageInfo *) NULL);
1947   assert(image_info->signature == MagickSignature);
1948   assert(image != (Image *) NULL);
1949   assert(image->signature == MagickSignature);
1950   if (image->debug != MagickFalse)
1951     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1952   assert(exception != (ExceptionInfo *) NULL);
1953   assert(exception->signature == MagickSignature);
1954   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1955   if (status == MagickFalse)
1956     return(status);
1957   scene=0;
1958   do
1959   {
1960     /*
1961       Allocate image pixels.
1962     */
1963     if ((image->storage_class == PseudoClass) &&
1964         (image->colors > (size_t) (GetQuantumRange(image->depth)+1)))
1965       (void) SetImageStorageClass(image,DirectClass,exception);
1966     image->depth=image->depth <= 8 ? 8UL : image->depth <= 16 ? 16UL :
1967       image->depth <= 32 ? 32UL : 64UL;
1968     if (IsImageGray(image,exception) == MagickFalse)
1969       {
1970         /*
1971           sRGB masquerading as a grayscale image?
1972         */
1973         if (IsGrayColorspace(image->colorspace) != MagickFalse)
1974           (void) SetImageColorspace(image,sRGBColorspace,exception);
1975       }
1976     else
1977       if (IsGrayColorspace(image->colorspace) == MagickFalse)
1978         (void) SetImageColorspace(image,GRAYColorspace,exception);
1979     quantum_info=AcquireQuantumInfo(image_info,image);
1980     if (quantum_info == (QuantumInfo *) NULL)
1981       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1982     if ((image->storage_class != PseudoClass) && (image->depth >= 32) &&
1983         (quantum_info->format == UndefinedQuantumFormat) &&
1984         (IsHighDynamicRangeImage(image,exception) != MagickFalse))
1985       {
1986         status=SetQuantumFormat(image,quantum_info,FloatingPointQuantumFormat);
1987         if (status == MagickFalse)
1988           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1989       }
1990     compression=UndefinedCompression;
1991     if (image_info->compression != UndefinedCompression)
1992       compression=image_info->compression;
1993     switch (compression)
1994     {
1995 #if !defined(MAGICKCORE_LZMA_DELEGATE)
1996       case LZMACompression: compression=NoCompression; break;
1997 #endif
1998 #if !defined(MAGICKCORE_ZLIB_DELEGATE)
1999       case LZWCompression:
2000       case ZipCompression: compression=NoCompression; break;
2001 #endif
2002 #if !defined(MAGICKCORE_BZLIB_DELEGATE)
2003       case BZipCompression: compression=NoCompression; break;
2004 #endif
2005       case RLECompression:
2006       {
2007         if (quantum_info->format == FloatingPointQuantumFormat)
2008           compression=NoCompression;
2009         GetPixelInfo(image,&target);
2010         break;
2011       }
2012       default:
2013         break;
2014     }
2015     packet_size=(size_t) (quantum_info->depth/8);
2016     if (image->storage_class == DirectClass)
2017       packet_size=(size_t) (3*quantum_info->depth/8);
2018     if (IsGrayColorspace(image->colorspace) != MagickFalse)
2019       packet_size=(size_t) (quantum_info->depth/8);
2020     if (image->alpha_trait == BlendPixelTrait)
2021       packet_size+=quantum_info->depth/8;
2022     if (image->colorspace == CMYKColorspace)
2023       packet_size+=quantum_info->depth/8;
2024     if (compression == RLECompression)
2025       packet_size++;
2026     length=image->columns;
2027     length=MagickMax(BZipMaxExtent(packet_size*image->columns),ZipMaxExtent(
2028       packet_size*image->columns));
2029     if ((compression == BZipCompression) || (compression == ZipCompression))
2030       if (length != (size_t) ((unsigned int) length))
2031         compression=NoCompression;
2032     compress_pixels=(unsigned char *) AcquireQuantumMemory(length,
2033       sizeof(*compress_pixels));
2034     if (compress_pixels == (unsigned char *) NULL)
2035       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2036     /*
2037       Write MIFF header.
2038     */
2039     (void) WriteBlobString(image,"id=ImageMagick  version=1.0\n");
2040     (void) FormatLocaleString(buffer,MaxTextExtent,
2041       "class=%s  colors=%.20g  alpha-trait=%s\n",CommandOptionToMnemonic(
2042       MagickClassOptions,image->storage_class),(double) image->colors,
2043       CommandOptionToMnemonic(MagickPixelTraitOptions,(ssize_t)
2044       image->alpha_trait));
2045     (void) WriteBlobString(image,buffer);
2046     (void) FormatLocaleString(buffer,MaxTextExtent,"columns=%.20g  rows=%.20g  "
2047       "depth=%.20g\n",(double) image->columns,(double) image->rows,(double)
2048       image->depth);
2049     (void) WriteBlobString(image,buffer);
2050     if (image->type != UndefinedType)
2051       {
2052         (void) FormatLocaleString(buffer,MaxTextExtent,"type=%s\n",
2053           CommandOptionToMnemonic(MagickTypeOptions,image->type));
2054         (void) WriteBlobString(image,buffer);
2055       }
2056     if (image->colorspace != UndefinedColorspace)
2057       {
2058         (void) FormatLocaleString(buffer,MaxTextExtent,"colorspace=%s\n",
2059           CommandOptionToMnemonic(MagickColorspaceOptions,image->colorspace));
2060         (void) WriteBlobString(image,buffer);
2061       }
2062     if (image->intensity != UndefinedPixelIntensityMethod)
2063       {
2064         (void) FormatLocaleString(buffer,MaxTextExtent,"pixel-intensity=%s\n",
2065           CommandOptionToMnemonic(MagickPixelIntensityOptions,
2066           image->intensity));
2067         (void) WriteBlobString(image,buffer);
2068       }
2069     if (image->endian != UndefinedEndian)
2070       {
2071         (void) FormatLocaleString(buffer,MaxTextExtent,"endian=%s\n",
2072           CommandOptionToMnemonic(MagickEndianOptions,image->endian));
2073         (void) WriteBlobString(image,buffer);
2074       }
2075     if (compression != UndefinedCompression)
2076       {
2077         (void) FormatLocaleString(buffer,MaxTextExtent,"compression=%s  "
2078           "quality=%.20g\n",CommandOptionToMnemonic(MagickCompressOptions,
2079           compression),(double) image->quality);
2080         (void) WriteBlobString(image,buffer);
2081       }
2082     if (image->units != UndefinedResolution)
2083       {
2084         (void) FormatLocaleString(buffer,MaxTextExtent,"units=%s\n",
2085           CommandOptionToMnemonic(MagickResolutionOptions,image->units));
2086         (void) WriteBlobString(image,buffer);
2087       }
2088     if ((image->resolution.x != 0) || (image->resolution.y != 0))
2089       {
2090         (void) FormatLocaleString(buffer,MaxTextExtent,
2091           "resolution=%gx%g\n",image->resolution.x,image->resolution.y);
2092         (void) WriteBlobString(image,buffer);
2093       }
2094     if ((image->page.width != 0) || (image->page.height != 0))
2095       {
2096         (void) FormatLocaleString(buffer,MaxTextExtent,
2097           "page=%.20gx%.20g%+.20g%+.20g\n",(double) image->page.width,(double)
2098           image->page.height,(double) image->page.x,(double) image->page.y);
2099         (void) WriteBlobString(image,buffer);
2100       }
2101     else
2102       if ((image->page.x != 0) || (image->page.y != 0))
2103         {
2104           (void) FormatLocaleString(buffer,MaxTextExtent,"page=%+ld%+ld\n",
2105             (long) image->page.x,(long) image->page.y);
2106           (void) WriteBlobString(image,buffer);
2107         }
2108     if ((image->tile_offset.x != 0) || (image->tile_offset.y != 0))
2109       {
2110         (void) FormatLocaleString(buffer,MaxTextExtent,"tile-offset=%+ld%+ld\n",
2111           (long) image->tile_offset.x,(long) image->tile_offset.y);
2112         (void) WriteBlobString(image,buffer);
2113       }
2114     if ((GetNextImageInList(image) != (Image *) NULL) ||
2115         (GetPreviousImageInList(image) != (Image *) NULL))
2116       {
2117         if (image->scene == 0)
2118           (void) FormatLocaleString(buffer,MaxTextExtent,"iterations=%.20g  "
2119             "delay=%.20g  ticks-per-second=%.20g\n",(double) image->iterations,
2120             (double) image->delay,(double) image->ticks_per_second);
2121         else
2122           (void) FormatLocaleString(buffer,MaxTextExtent,"scene=%.20g  "
2123             "iterations=%.20g  delay=%.20g  ticks-per-second=%.20g\n",(double)
2124             image->scene,(double) image->iterations,(double) image->delay,
2125             (double) image->ticks_per_second);
2126         (void) WriteBlobString(image,buffer);
2127       }
2128     else
2129       {
2130         if (image->scene != 0)
2131           {
2132             (void) FormatLocaleString(buffer,MaxTextExtent,"scene=%.20g\n",
2133               (double) image->scene);
2134             (void) WriteBlobString(image,buffer);
2135           }
2136         if (image->iterations != 0)
2137           {
2138             (void) FormatLocaleString(buffer,MaxTextExtent,"iterations=%.20g\n",
2139               (double) image->iterations);
2140             (void) WriteBlobString(image,buffer);
2141           }
2142         if (image->delay != 0)
2143           {
2144             (void) FormatLocaleString(buffer,MaxTextExtent,"delay=%.20g\n",
2145               (double) image->delay);
2146             (void) WriteBlobString(image,buffer);
2147           }
2148         if (image->ticks_per_second != UndefinedTicksPerSecond)
2149           {
2150             (void) FormatLocaleString(buffer,MaxTextExtent,
2151               "ticks-per-second=%.20g\n",(double) image->ticks_per_second);
2152             (void) WriteBlobString(image,buffer);
2153           }
2154       }
2155     if (image->gravity != UndefinedGravity)
2156       {
2157         (void) FormatLocaleString(buffer,MaxTextExtent,"gravity=%s\n",
2158           CommandOptionToMnemonic(MagickGravityOptions,image->gravity));
2159         (void) WriteBlobString(image,buffer);
2160       }
2161     if (image->dispose != UndefinedDispose)
2162       {
2163         (void) FormatLocaleString(buffer,MaxTextExtent,"dispose=%s\n",
2164           CommandOptionToMnemonic(MagickDisposeOptions,image->dispose));
2165         (void) WriteBlobString(image,buffer);
2166       }
2167     if (image->rendering_intent != UndefinedIntent)
2168       {
2169         (void) FormatLocaleString(buffer,MaxTextExtent,"rendering-intent=%s\n",
2170           CommandOptionToMnemonic(MagickIntentOptions,image->rendering_intent));
2171         (void) WriteBlobString(image,buffer);
2172       }
2173     if (image->gamma != 0.0)
2174       {
2175         (void) FormatLocaleString(buffer,MaxTextExtent,"gamma=%g\n",
2176           image->gamma);
2177         (void) WriteBlobString(image,buffer);
2178       }
2179     if (image->chromaticity.white_point.x != 0.0)
2180       {
2181         /*
2182           Note chomaticity points.
2183         */
2184         (void) FormatLocaleString(buffer,MaxTextExtent,"red-primary=%g,"
2185           "%g  green-primary=%g,%g  blue-primary=%g,%g\n",
2186           image->chromaticity.red_primary.x,image->chromaticity.red_primary.y,
2187           image->chromaticity.green_primary.x,
2188           image->chromaticity.green_primary.y,
2189           image->chromaticity.blue_primary.x,
2190           image->chromaticity.blue_primary.y);
2191         (void) WriteBlobString(image,buffer);
2192         (void) FormatLocaleString(buffer,MaxTextExtent,
2193           "white-point=%g,%g\n",image->chromaticity.white_point.x,
2194           image->chromaticity.white_point.y);
2195         (void) WriteBlobString(image,buffer);
2196       }
2197     if (image->orientation != UndefinedOrientation)
2198       {
2199         (void) FormatLocaleString(buffer,MaxTextExtent,"orientation=%s\n",
2200           CommandOptionToMnemonic(MagickOrientationOptions,image->orientation));
2201         (void) WriteBlobString(image,buffer);
2202       }
2203     if (image->profiles != (void *) NULL)
2204       {
2205         const char
2206           *name;
2207
2208         const StringInfo
2209           *profile;
2210
2211         /*
2212           Write image profiles.
2213         */
2214         ResetImageProfileIterator(image);
2215         name=GetNextImageProfile(image);
2216         while (name != (const char *) NULL)
2217         {
2218           profile=GetImageProfile(image,name);
2219           if (profile != (StringInfo *) NULL)
2220             {
2221               (void) FormatLocaleString(buffer,MaxTextExtent,
2222                 "profile:%s=%.20g\n",name,(double)
2223                 GetStringInfoLength(profile));
2224               (void) WriteBlobString(image,buffer);
2225             }
2226           name=GetNextImageProfile(image);
2227         }
2228       }
2229     if (image->montage != (char *) NULL)
2230       {
2231         (void) FormatLocaleString(buffer,MaxTextExtent,"montage=%s\n",
2232           image->montage);
2233         (void) WriteBlobString(image,buffer);
2234       }
2235     if (quantum_info->format == FloatingPointQuantumFormat)
2236       (void) SetImageProperty(image,"quantum:format","floating-point",
2237         exception);
2238     ResetImagePropertyIterator(image);
2239     property=GetNextImageProperty(image);
2240     while (property != (const char *) NULL)
2241     {
2242       (void) FormatLocaleString(buffer,MaxTextExtent,"%s=",property);
2243       (void) WriteBlobString(image,buffer);
2244       value=GetImageProperty(image,property,exception);
2245       if (value != (const char *) NULL)
2246         {
2247           size_t
2248             length;
2249
2250           length=strlen(value);
2251           for (i=0; i < (ssize_t) length; i++)
2252             if (isspace((int) ((unsigned char) value[i])) != 0)
2253               break;
2254           if ((i == (ssize_t) length) && (i != 0))
2255             (void) WriteBlob(image,length,(const unsigned char *) value);
2256           else
2257             {
2258               (void) WriteBlobByte(image,'{');
2259               if (strchr(value,'}') == (char *) NULL)
2260                 (void) WriteBlob(image,length,(const unsigned char *) value);
2261               else
2262                 for (i=0; i < (ssize_t) length; i++)
2263                 {
2264                   if (value[i] == (int) '}')
2265                     (void) WriteBlobByte(image,'\\');
2266                   (void) WriteBlobByte(image,value[i]);
2267                 }
2268               (void) WriteBlobByte(image,'}');
2269             }
2270         }
2271       (void) WriteBlobByte(image,'\n');
2272       property=GetNextImageProperty(image);
2273     }
2274     (void) WriteBlobString(image,"\f\n:\032");
2275     if (image->montage != (char *) NULL)
2276       {
2277         /*
2278           Write montage tile directory.
2279         */
2280         if (image->directory != (char *) NULL)
2281           (void) WriteBlob(image,strlen(image->directory),(unsigned char *)
2282             image->directory);
2283         (void) WriteBlobByte(image,'\0');
2284       }
2285     if (image->profiles != (void *) NULL)
2286       {
2287         const char
2288           *name;
2289
2290         const StringInfo
2291           *profile;
2292
2293         /*
2294           Generic profile.
2295         */
2296         ResetImageProfileIterator(image);
2297         name=GetNextImageProfile(image);
2298         while (name != (const char *) NULL)
2299         {
2300           profile=GetImageProfile(image,name);
2301           (void) WriteBlob(image,GetStringInfoLength(profile),
2302             GetStringInfoDatum(profile));
2303           name=GetNextImageProfile(image);
2304         }
2305       }
2306     if (image->storage_class == PseudoClass)
2307       {
2308         size_t
2309           packet_size;
2310
2311         unsigned char
2312           *colormap,
2313           *q;
2314
2315         /*
2316           Allocate colormap.
2317         */
2318         packet_size=(size_t) (3*quantum_info->depth/8);
2319         colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
2320           packet_size*sizeof(*colormap));
2321         if (colormap == (unsigned char *) NULL)
2322           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2323         /*
2324           Write colormap to file.
2325         */
2326         q=colormap;
2327         for (i=0; i < (ssize_t) image->colors; i++)
2328         {
2329           switch (quantum_info->depth)
2330           {
2331             default:
2332               ThrowWriterException(CorruptImageError,"ImageDepthNotSupported");
2333             case 32:
2334             {
2335               register unsigned int
2336                 pixel;
2337
2338               pixel=ScaleQuantumToLong(image->colormap[i].red);
2339               q=PopLongPixel(MSBEndian,pixel,q);
2340               pixel=ScaleQuantumToLong(image->colormap[i].green);
2341               q=PopLongPixel(MSBEndian,pixel,q);
2342               pixel=ScaleQuantumToLong(image->colormap[i].blue);
2343               q=PopLongPixel(MSBEndian,pixel,q);
2344               break;
2345             }
2346             case 16:
2347             {
2348               register unsigned short
2349                 pixel;
2350
2351               pixel=ScaleQuantumToShort(image->colormap[i].red);
2352               q=PopShortPixel(MSBEndian,pixel,q);
2353               pixel=ScaleQuantumToShort(image->colormap[i].green);
2354               q=PopShortPixel(MSBEndian,pixel,q);
2355               pixel=ScaleQuantumToShort(image->colormap[i].blue);
2356               q=PopShortPixel(MSBEndian,pixel,q);
2357               break;
2358             }
2359             case 8:
2360             {
2361               register unsigned char
2362                 pixel;
2363
2364               pixel=(unsigned char) ScaleQuantumToChar(image->colormap[i].red);
2365               q=PopCharPixel(pixel,q);
2366               pixel=(unsigned char) ScaleQuantumToChar(
2367                 image->colormap[i].green);
2368               q=PopCharPixel(pixel,q);
2369               pixel=(unsigned char) ScaleQuantumToChar(image->colormap[i].blue);
2370               q=PopCharPixel(pixel,q);
2371               break;
2372             }
2373           }
2374         }
2375         (void) WriteBlob(image,packet_size*image->colors,colormap);
2376         colormap=(unsigned char *) RelinquishMagickMemory(colormap);
2377       }
2378     /*
2379       Write image pixels to file.
2380     */
2381     status=MagickTrue;
2382     switch (compression)
2383     {
2384 #if defined(MAGICKCORE_BZLIB_DELEGATE)
2385       case BZipCompression:
2386       {
2387         int
2388           code;
2389
2390         (void) ResetMagickMemory(&bzip_info,0,sizeof(bzip_info));
2391         bzip_info.bzalloc=AcquireBZIPMemory;
2392         bzip_info.bzfree=RelinquishBZIPMemory;
2393         code=BZ2_bzCompressInit(&bzip_info,(int) (image->quality ==
2394           UndefinedCompressionQuality ? 7 : MagickMin(image->quality/10,
2395           9)),(int) image_info->verbose,0);
2396         if (code != BZ_OK)
2397           status=MagickFalse;
2398         break;
2399       }
2400 #endif
2401 #if defined(MAGICKCORE_LZMA_DELEGATE)
2402       case LZMACompression:
2403       {
2404         int
2405           code;
2406
2407         (void) ResetMagickMemory(&allocator,0,sizeof(allocator));
2408         allocator.alloc=AcquireLZMAMemory;
2409         allocator.free=RelinquishLZMAMemory;
2410         lzma_info=initialize_lzma;
2411         lzma_info.allocator=&allocator;
2412         code=lzma_easy_encoder(&lzma_info,image->quality/10,LZMA_CHECK_SHA256);
2413         if (code != LZMA_OK)
2414           status=MagickTrue;
2415         break;
2416       }
2417 #endif
2418 #if defined(MAGICKCORE_ZLIB_DELEGATE)
2419       case LZWCompression:
2420       case ZipCompression:
2421       {
2422         int
2423           code;
2424
2425         (void) ResetMagickMemory(&zip_info,0,sizeof(zip_info));
2426         zip_info.zalloc=AcquireZIPMemory;
2427         zip_info.zfree=RelinquishZIPMemory;
2428         code=deflateInit(&zip_info,(int) (image->quality ==
2429           UndefinedCompressionQuality ? 7 : MagickMin(image->quality/10,9)));
2430         if (code != Z_OK)
2431           status=MagickFalse;
2432         break;
2433       }
2434 #endif
2435       default:
2436         break;
2437     }
2438     quantum_type=GetQuantumType(image,exception);
2439     pixels=GetQuantumPixels(quantum_info);
2440     for (y=0; y < (ssize_t) image->rows; y++)
2441     {
2442       register const Quantum
2443         *restrict p;
2444
2445       register ssize_t
2446         x;
2447
2448       if (status == MagickFalse)
2449         break;
2450       p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2451       if (p == (const Quantum *) NULL)
2452         break;
2453       q=pixels;
2454       switch (compression)
2455       {
2456 #if defined(MAGICKCORE_BZLIB_DELEGATE)
2457         case BZipCompression:
2458         {
2459           bzip_info.next_in=(char *) pixels;
2460           bzip_info.avail_in=(unsigned int) (packet_size*image->columns);
2461           (void) ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2462             quantum_type,pixels,exception);
2463           do
2464           {
2465             int
2466               code;
2467
2468             bzip_info.next_out=(char *) compress_pixels;
2469             bzip_info.avail_out=(unsigned int) BZipMaxExtent(packet_size*
2470               image->columns);
2471             code=BZ2_bzCompress(&bzip_info,BZ_FLUSH);
2472             if (code != BZ_OK)
2473               status=MagickFalse;
2474             length=(size_t) (bzip_info.next_out-(char *) compress_pixels);
2475             if (length != 0)
2476               {
2477                 (void) WriteBlobMSBLong(image,(unsigned int) length);
2478                 (void) WriteBlob(image,length,compress_pixels);
2479               }
2480           } while (bzip_info.avail_in != 0);
2481           break;
2482         }
2483 #endif
2484 #if defined(MAGICKCORE_LZMA_DELEGATE)
2485         case LZMACompression:
2486         {
2487           lzma_info.next_in=pixels;
2488           lzma_info.avail_in=packet_size*image->columns;
2489           (void) ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2490             quantum_type,pixels,exception);
2491           do
2492           {
2493             int
2494               code;
2495
2496             lzma_info.next_out=compress_pixels;
2497             lzma_info.avail_out=packet_size*image->columns;
2498             code=lzma_code(&lzma_info,LZMA_RUN);
2499             if (code != LZMA_OK)
2500               status=MagickFalse;
2501             length=(size_t) (lzma_info.next_out-compress_pixels);
2502             if (length != 0)
2503               {
2504                 (void) WriteBlobMSBLong(image,(unsigned int) length);
2505                 (void) WriteBlob(image,length,compress_pixels);
2506               }
2507           } while (lzma_info.avail_in != 0);
2508           break;
2509         }
2510 #endif
2511 #if defined(MAGICKCORE_ZLIB_DELEGATE)
2512         case LZWCompression:
2513         case ZipCompression:
2514         {
2515           zip_info.next_in=pixels;
2516           zip_info.avail_in=(uInt) (packet_size*image->columns);
2517           (void) ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2518             quantum_type,pixels,exception);
2519           do
2520           {
2521             int
2522               code;
2523
2524             zip_info.next_out=compress_pixels;
2525             zip_info.avail_out=(uInt) ZipMaxExtent(packet_size*image->columns);
2526             code=deflate(&zip_info,Z_SYNC_FLUSH);
2527             if (code != Z_OK)
2528               status=MagickFalse;
2529             length=(size_t) (zip_info.next_out-compress_pixels);
2530             if (length != 0)
2531               {
2532                 (void) WriteBlobMSBLong(image,(unsigned int) length);
2533                 (void) WriteBlob(image,length,compress_pixels);
2534               }
2535           } while (zip_info.avail_in != 0);
2536           break;
2537         }
2538 #endif
2539         case RLECompression:
2540         {
2541           length=0;
2542           GetPixelInfoPixel(image,p,&pixel);
2543           p+=GetPixelChannels(image);
2544           for (x=1; x < (ssize_t) image->columns; x++)
2545           {
2546             GetPixelInfoPixel(image,p,&target);
2547             if ((length < 255) &&
2548                 (IsPixelInfoEquivalent(&pixel,&target) != MagickFalse))
2549               length++;
2550             else
2551               {
2552                 q=PopRunlengthPacket(image,q,length,&pixel,exception);
2553                 length=0;
2554               }
2555             GetPixelInfoPixel(image,p,&pixel);
2556             p+=GetPixelChannels(image);
2557           }
2558           q=PopRunlengthPacket(image,q,length,&pixel,exception);
2559           (void) WriteBlob(image,(size_t) (q-pixels),pixels);
2560           break;
2561         }
2562         default:
2563         {
2564           (void) ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2565             quantum_type,pixels,exception);
2566           (void) WriteBlob(image,packet_size*image->columns,pixels);
2567           break;
2568         }
2569       }
2570       if (image->previous == (Image *) NULL)
2571         {
2572           status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2573             image->rows);
2574           if (status == MagickFalse)
2575             break;
2576         }
2577     }
2578     switch (compression)
2579     {
2580 #if defined(MAGICKCORE_BZLIB_DELEGATE)
2581       case BZipCompression:
2582       {
2583         int
2584           code;
2585
2586         for ( ; ; )
2587         {
2588           if (status == MagickFalse)
2589             break;
2590           bzip_info.next_out=(char *) compress_pixels;
2591           bzip_info.avail_out=(unsigned int) BZipMaxExtent(packet_size*
2592             image->columns);
2593           code=BZ2_bzCompress(&bzip_info,BZ_FINISH);
2594           length=(size_t) (bzip_info.next_out-(char *) compress_pixels);
2595           if (length != 0)
2596             {
2597               (void) WriteBlobMSBLong(image,(unsigned int) length);
2598               (void) WriteBlob(image,length,compress_pixels);
2599             }
2600           if (code == BZ_STREAM_END)
2601             break;
2602         }
2603         code=BZ2_bzCompressEnd(&bzip_info);
2604         if (code != BZ_OK)
2605           status=MagickFalse;
2606         break;
2607       }
2608 #endif
2609 #if defined(MAGICKCORE_LZMA_DELEGATE)
2610       case LZMACompression:
2611       {
2612         int
2613           code;
2614
2615         for ( ; ; )
2616         {
2617           if (status == MagickFalse)
2618             break;
2619           lzma_info.next_out=compress_pixels;
2620           lzma_info.avail_out=packet_size*image->columns;
2621           code=lzma_code(&lzma_info,LZMA_FINISH);
2622           length=(size_t) (lzma_info.next_out-compress_pixels);
2623           if (length > 6)
2624             {
2625               (void) WriteBlobMSBLong(image,(unsigned int) length);
2626               (void) WriteBlob(image,length,compress_pixels);
2627             }
2628           if (code == LZMA_STREAM_END)
2629             break;
2630         }
2631         lzma_end(&lzma_info);
2632         break;
2633       }
2634 #endif
2635 #if defined(MAGICKCORE_ZLIB_DELEGATE)
2636       case LZWCompression:
2637       case ZipCompression:
2638       {
2639         int
2640           code;
2641
2642         for ( ; ; )
2643         {
2644           if (status == MagickFalse)
2645             break;
2646           zip_info.next_out=compress_pixels;
2647           zip_info.avail_out=(uInt) ZipMaxExtent(packet_size*image->columns);
2648           code=deflate(&zip_info,Z_FINISH);
2649           length=(size_t) (zip_info.next_out-compress_pixels);
2650           if (length > 6)
2651             {
2652               (void) WriteBlobMSBLong(image,(unsigned int) length);
2653               (void) WriteBlob(image,length,compress_pixels);
2654             }
2655           if (code == Z_STREAM_END)
2656             break;
2657         }
2658         code=deflateEnd(&zip_info);
2659         if (code != Z_OK)
2660           status=MagickFalse;
2661         break;
2662       }
2663 #endif
2664       default:
2665         break;
2666     }
2667     quantum_info=DestroyQuantumInfo(quantum_info);
2668     compress_pixels=(unsigned char *) RelinquishMagickMemory(compress_pixels);
2669     if (GetNextImageInList(image) == (Image *) NULL)
2670       break;
2671     image=SyncNextImageInList(image);
2672     status=SetImageProgress(image,SaveImagesTag,scene++,
2673       GetImageListLength(image));
2674     if (status == MagickFalse)
2675       break;
2676   } while (image_info->adjoin != MagickFalse);
2677   (void) CloseBlob(image);
2678   return(status);
2679 }