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