]> 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-2014 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    http://www.imagemagick.org/script/license.php                            %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38 \f
39 /*
40   Include declarations.
41 */
42 #include "MagickCore/studio.h"
43 #include "MagickCore/attribute.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/color.h"
48 #include "MagickCore/color-private.h"
49 #include "MagickCore/colormap.h"
50 #include "MagickCore/colormap-private.h"
51 #include "MagickCore/colorspace.h"
52 #include "MagickCore/colorspace-private.h"
53 #include "MagickCore/constitute.h"
54 #include "MagickCore/exception.h"
55 #include "MagickCore/exception-private.h"
56 #include "MagickCore/hashmap.h"
57 #include "MagickCore/geometry.h"
58 #include "MagickCore/image.h"
59 #include "MagickCore/image-private.h"
60 #include "MagickCore/list.h"
61 #include "MagickCore/magick.h"
62 #include "MagickCore/memory_.h"
63 #include "MagickCore/module.h"
64 #include "MagickCore/monitor.h"
65 #include "MagickCore/monitor-private.h"
66 #include "MagickCore/option.h"
67 #include "MagickCore/pixel.h"
68 #include "MagickCore/pixel-accessor.h"
69 #include "MagickCore/profile.h"
70 #include "MagickCore/property.h"
71 #include "MagickCore/quantum-private.h"
72 #include "MagickCore/static.h"
73 #include "MagickCore/statistic.h"
74 #include "MagickCore/string_.h"
75 #include "MagickCore/string-private.h"
76 #if defined(MAGICKCORE_BZLIB_DELEGATE)
77 #include "bzlib.h"
78 #endif
79 #if defined(MAGICKCORE_LZMA_DELEGATE)
80 #include "lzma.h"
81 #endif
82 #if defined(MAGICKCORE_ZLIB_DELEGATE)
83 #include "zlib.h"
84 #endif
85 \f
86 /*
87   Define declarations.
88 */
89 #if !defined(LZMA_OK)
90 #define LZMA_OK  0
91 #endif
92 \f
93 /*
94   Forward declarations.
95 */
96 static MagickBooleanType
97   WriteMIFFImage(const ImageInfo *,Image *,ExceptionInfo *);
98 \f
99 /*
100 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
101 %                                                                             %
102 %                                                                             %
103 %                                                                             %
104 %   I s M I F F                                                               %
105 %                                                                             %
106 %                                                                             %
107 %                                                                             %
108 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
109 %
110 %  IsMIFF() returns MagickTrue if the image format type, identified by the
111 %  magick string, is MIFF.
112 %
113 %  The format of the IsMIFF method is:
114 %
115 %      MagickBooleanType IsMIFF(const unsigned char *magick,const size_t length)
116 %
117 %  A description of each parameter follows:
118 %
119 %    o magick: compare image format pattern against these bytes.
120 %
121 %    o length: Specifies the length of the magick string.
122 %
123 */
124 static MagickBooleanType IsMIFF(const unsigned char *magick,const size_t length)
125 {
126   if (length < 14)
127     return(MagickFalse);
128   if (LocaleNCompare((const char *) magick,"id=ImageMagick",14) == 0)
129     return(MagickTrue);
130   return(MagickFalse);
131 }
132 \f
133 /*
134 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
135 %                                                                             %
136 %                                                                             %
137 %                                                                             %
138 %   R e a d M I F F I m a g e                                                 %
139 %                                                                             %
140 %                                                                             %
141 %                                                                             %
142 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
143 %
144 %  ReadMIFFImage() reads a MIFF image file and returns it.  It allocates the
145 %  memory necessary for the new Image structure and returns a pointer to the
146 %  new image.
147 %
148 %  The format of the ReadMIFFImage method is:
149 %
150 %      Image *ReadMIFFImage(const ImageInfo *image_info,
151 %        ExceptionInfo *exception)
152 %
153 %  Decompression code contributed by Kyle Shorter.
154 %
155 %  A description of each parameter follows:
156 %
157 %    o image_info: the image info.
158 %
159 %    o exception: return any errors or warnings in this structure.
160 %
161 */
162
163 #if defined(MAGICKCORE_BZLIB_DELEGATE)
164 static void *AcquireBZIPMemory(void *context,int items,int size)
165 {
166   (void) context;
167   return((void *) AcquireQuantumMemory((size_t) items,(size_t) size));
168 }
169 #endif
170
171 #if defined(MAGICKCORE_LZMA_DELEGATE)
172 static void *AcquireLZMAMemory(void *context,size_t items,size_t size)
173 {
174   (void) context;
175   return((void *) AcquireQuantumMemory((size_t) items,(size_t) size));
176 }
177 #endif
178
179 #if defined(MAGICKCORE_ZLIB_DELEGATE)
180 static voidpf AcquireZIPMemory(voidpf context,unsigned int items,
181   unsigned int size)
182 {
183   (void) context;
184   return((voidpf) AcquireQuantumMemory(items,size));
185 }
186 #endif
187
188 static inline size_t MagickMax(const size_t x,const size_t y)
189 {
190   if (x > y)
191     return(x);
192   return(y);
193 }
194
195 static inline size_t MagickMin(const size_t x,const size_t y)
196 {
197   if (x < y)
198     return(x);
199   return(y);
200 }
201
202 static void PushRunlengthPacket(Image *image,const unsigned char *pixels,
203   size_t *length,PixelInfo *pixel,ExceptionInfo *exception)
204 {
205   const unsigned char
206     *p;
207
208   p=pixels;
209   if (image->storage_class == PseudoClass)
210     {
211       pixel->index=0;
212       switch (image->depth)
213       {
214         case 32:
215         {
216           pixel->index=ConstrainColormapIndex(image,
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     if ((image->storage_class == PseudoClass) &&
1955         (image->colors > (size_t) (GetQuantumRange(image->depth)+1)))
1956       (void) SetImageStorageClass(image,DirectClass,exception);
1957     image->depth=image->depth <= 8 ? 8UL : image->depth <= 16 ? 16UL :
1958       image->depth <= 32 ? 32UL : 64UL;
1959     if (IsImageGray(image,exception) == MagickFalse)
1960       {
1961         /*
1962           sRGB masquerading as a grayscale image?
1963         */
1964         if (IsGrayColorspace(image->colorspace) != MagickFalse)
1965           (void) SetImageColorspace(image,sRGBColorspace,exception);
1966       }
1967     else
1968       if (IsGrayColorspace(image->colorspace) == MagickFalse)
1969         (void) SetImageColorspace(image,GRAYColorspace,exception);
1970     quantum_info=AcquireQuantumInfo(image_info,image);
1971     if (quantum_info == (QuantumInfo *) NULL)
1972       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1973     if ((image->storage_class != PseudoClass) && (image->depth >= 32) &&
1974         (quantum_info->format == UndefinedQuantumFormat) &&
1975         (IsHighDynamicRangeImage(image,exception) != MagickFalse))
1976       {
1977         status=SetQuantumFormat(image,quantum_info,FloatingPointQuantumFormat);
1978         if (status == MagickFalse)
1979           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1980       }
1981     compression=UndefinedCompression;
1982     if (image_info->compression != UndefinedCompression)
1983       compression=image_info->compression;
1984     switch (compression)
1985     {
1986 #if !defined(MAGICKCORE_LZMA_DELEGATE)
1987       case LZMACompression: compression=NoCompression; break;
1988 #endif
1989 #if !defined(MAGICKCORE_ZLIB_DELEGATE)
1990       case LZWCompression:
1991       case ZipCompression: compression=NoCompression; break;
1992 #endif
1993 #if !defined(MAGICKCORE_BZLIB_DELEGATE)
1994       case BZipCompression: compression=NoCompression; break;
1995 #endif
1996       case RLECompression:
1997       {
1998         if (quantum_info->format == FloatingPointQuantumFormat)
1999           compression=NoCompression;
2000         GetPixelInfo(image,&target);
2001         break;
2002       }
2003       default:
2004         break;
2005     }
2006     packet_size=(size_t) (quantum_info->depth/8);
2007     if (image->storage_class == DirectClass)
2008       packet_size=(size_t) (3*quantum_info->depth/8);
2009     if (IsGrayColorspace(image->colorspace) != MagickFalse)
2010       packet_size=(size_t) (quantum_info->depth/8);
2011     if (image->alpha_trait == BlendPixelTrait)
2012       packet_size+=quantum_info->depth/8;
2013     if (image->colorspace == CMYKColorspace)
2014       packet_size+=quantum_info->depth/8;
2015     if (compression == RLECompression)
2016       packet_size++;
2017     length=image->columns;
2018     length=MagickMax(BZipMaxExtent(packet_size*image->columns),ZipMaxExtent(
2019       packet_size*image->columns));
2020     if ((compression == BZipCompression) || (compression == ZipCompression))
2021       if (length != (size_t) ((unsigned int) length))
2022         compression=NoCompression;
2023     compress_pixels=(unsigned char *) AcquireQuantumMemory(length,
2024       sizeof(*compress_pixels));
2025     if (compress_pixels == (unsigned char *) NULL)
2026       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2027     /*
2028       Write MIFF header.
2029     */
2030     (void) WriteBlobString(image,"id=ImageMagick  version=1.0\n");
2031     (void) FormatLocaleString(buffer,MaxTextExtent,
2032       "class=%s  colors=%.20g  alpha-trait=%s\n",CommandOptionToMnemonic(
2033       MagickClassOptions,image->storage_class),(double) image->colors,
2034       CommandOptionToMnemonic(MagickPixelTraitOptions,(ssize_t)
2035       image->alpha_trait));
2036     (void) WriteBlobString(image,buffer);
2037     (void) FormatLocaleString(buffer,MaxTextExtent,"columns=%.20g  rows=%.20g  "
2038       "depth=%.20g\n",(double) image->columns,(double) image->rows,(double)
2039       image->depth);
2040     (void) WriteBlobString(image,buffer);
2041     if (image->type != UndefinedType)
2042       {
2043         (void) FormatLocaleString(buffer,MaxTextExtent,"type=%s\n",
2044           CommandOptionToMnemonic(MagickTypeOptions,image->type));
2045         (void) WriteBlobString(image,buffer);
2046       }
2047     if (image->colorspace != UndefinedColorspace)
2048       {
2049         (void) FormatLocaleString(buffer,MaxTextExtent,"colorspace=%s\n",
2050           CommandOptionToMnemonic(MagickColorspaceOptions,image->colorspace));
2051         (void) WriteBlobString(image,buffer);
2052       }
2053     if (image->intensity != UndefinedPixelIntensityMethod)
2054       {
2055         (void) FormatLocaleString(buffer,MaxTextExtent,"pixel-intensity=%s\n",
2056           CommandOptionToMnemonic(MagickPixelIntensityOptions,
2057           image->intensity));
2058         (void) WriteBlobString(image,buffer);
2059       }
2060     if (image->endian != UndefinedEndian)
2061       {
2062         (void) FormatLocaleString(buffer,MaxTextExtent,"endian=%s\n",
2063           CommandOptionToMnemonic(MagickEndianOptions,image->endian));
2064         (void) WriteBlobString(image,buffer);
2065       }
2066     if (compression != UndefinedCompression)
2067       {
2068         (void) FormatLocaleString(buffer,MaxTextExtent,"compression=%s  "
2069           "quality=%.20g\n",CommandOptionToMnemonic(MagickCompressOptions,
2070           compression),(double) image->quality);
2071         (void) WriteBlobString(image,buffer);
2072       }
2073     if (image->units != UndefinedResolution)
2074       {
2075         (void) FormatLocaleString(buffer,MaxTextExtent,"units=%s\n",
2076           CommandOptionToMnemonic(MagickResolutionOptions,image->units));
2077         (void) WriteBlobString(image,buffer);
2078       }
2079     if ((image->resolution.x != 0) || (image->resolution.y != 0))
2080       {
2081         (void) FormatLocaleString(buffer,MaxTextExtent,
2082           "resolution=%gx%g\n",image->resolution.x,image->resolution.y);
2083         (void) WriteBlobString(image,buffer);
2084       }
2085     if ((image->page.width != 0) || (image->page.height != 0))
2086       {
2087         (void) FormatLocaleString(buffer,MaxTextExtent,
2088           "page=%.20gx%.20g%+.20g%+.20g\n",(double) image->page.width,(double)
2089           image->page.height,(double) image->page.x,(double) image->page.y);
2090         (void) WriteBlobString(image,buffer);
2091       }
2092     else
2093       if ((image->page.x != 0) || (image->page.y != 0))
2094         {
2095           (void) FormatLocaleString(buffer,MaxTextExtent,"page=%+ld%+ld\n",
2096             (long) image->page.x,(long) image->page.y);
2097           (void) WriteBlobString(image,buffer);
2098         }
2099     if ((image->tile_offset.x != 0) || (image->tile_offset.y != 0))
2100       {
2101         (void) FormatLocaleString(buffer,MaxTextExtent,"tile-offset=%+ld%+ld\n",
2102           (long) image->tile_offset.x,(long) image->tile_offset.y);
2103         (void) WriteBlobString(image,buffer);
2104       }
2105     if ((GetNextImageInList(image) != (Image *) NULL) ||
2106         (GetPreviousImageInList(image) != (Image *) NULL))
2107       {
2108         if (image->scene == 0)
2109           (void) FormatLocaleString(buffer,MaxTextExtent,"iterations=%.20g  "
2110             "delay=%.20g  ticks-per-second=%.20g\n",(double) image->iterations,
2111             (double) image->delay,(double) image->ticks_per_second);
2112         else
2113           (void) FormatLocaleString(buffer,MaxTextExtent,"scene=%.20g  "
2114             "iterations=%.20g  delay=%.20g  ticks-per-second=%.20g\n",(double)
2115             image->scene,(double) image->iterations,(double) image->delay,
2116             (double) image->ticks_per_second);
2117         (void) WriteBlobString(image,buffer);
2118       }
2119     else
2120       {
2121         if (image->scene != 0)
2122           {
2123             (void) FormatLocaleString(buffer,MaxTextExtent,"scene=%.20g\n",
2124               (double) image->scene);
2125             (void) WriteBlobString(image,buffer);
2126           }
2127         if (image->iterations != 0)
2128           {
2129             (void) FormatLocaleString(buffer,MaxTextExtent,"iterations=%.20g\n",
2130               (double) image->iterations);
2131             (void) WriteBlobString(image,buffer);
2132           }
2133         if (image->delay != 0)
2134           {
2135             (void) FormatLocaleString(buffer,MaxTextExtent,"delay=%.20g\n",
2136               (double) image->delay);
2137             (void) WriteBlobString(image,buffer);
2138           }
2139         if (image->ticks_per_second != UndefinedTicksPerSecond)
2140           {
2141             (void) FormatLocaleString(buffer,MaxTextExtent,
2142               "ticks-per-second=%.20g\n",(double) image->ticks_per_second);
2143             (void) WriteBlobString(image,buffer);
2144           }
2145       }
2146     if (image->gravity != UndefinedGravity)
2147       {
2148         (void) FormatLocaleString(buffer,MaxTextExtent,"gravity=%s\n",
2149           CommandOptionToMnemonic(MagickGravityOptions,image->gravity));
2150         (void) WriteBlobString(image,buffer);
2151       }
2152     if (image->dispose != UndefinedDispose)
2153       {
2154         (void) FormatLocaleString(buffer,MaxTextExtent,"dispose=%s\n",
2155           CommandOptionToMnemonic(MagickDisposeOptions,image->dispose));
2156         (void) WriteBlobString(image,buffer);
2157       }
2158     if (image->rendering_intent != UndefinedIntent)
2159       {
2160         (void) FormatLocaleString(buffer,MaxTextExtent,"rendering-intent=%s\n",
2161           CommandOptionToMnemonic(MagickIntentOptions,image->rendering_intent));
2162         (void) WriteBlobString(image,buffer);
2163       }
2164     if (image->gamma != 0.0)
2165       {
2166         (void) FormatLocaleString(buffer,MaxTextExtent,"gamma=%g\n",
2167           image->gamma);
2168         (void) WriteBlobString(image,buffer);
2169       }
2170     if (image->chromaticity.white_point.x != 0.0)
2171       {
2172         /*
2173           Note chomaticity points.
2174         */
2175         (void) FormatLocaleString(buffer,MaxTextExtent,"red-primary=%g,"
2176           "%g  green-primary=%g,%g  blue-primary=%g,%g\n",
2177           image->chromaticity.red_primary.x,image->chromaticity.red_primary.y,
2178           image->chromaticity.green_primary.x,
2179           image->chromaticity.green_primary.y,
2180           image->chromaticity.blue_primary.x,
2181           image->chromaticity.blue_primary.y);
2182         (void) WriteBlobString(image,buffer);
2183         (void) FormatLocaleString(buffer,MaxTextExtent,
2184           "white-point=%g,%g\n",image->chromaticity.white_point.x,
2185           image->chromaticity.white_point.y);
2186         (void) WriteBlobString(image,buffer);
2187       }
2188     if (image->orientation != UndefinedOrientation)
2189       {
2190         (void) FormatLocaleString(buffer,MaxTextExtent,"orientation=%s\n",
2191           CommandOptionToMnemonic(MagickOrientationOptions,image->orientation));
2192         (void) WriteBlobString(image,buffer);
2193       }
2194     if (image->profiles != (void *) NULL)
2195       {
2196         const char
2197           *name;
2198
2199         const StringInfo
2200           *profile;
2201
2202         /*
2203           Write image profiles.
2204         */
2205         ResetImageProfileIterator(image);
2206         name=GetNextImageProfile(image);
2207         while (name != (const char *) NULL)
2208         {
2209           profile=GetImageProfile(image,name);
2210           if (profile != (StringInfo *) NULL)
2211             {
2212               (void) FormatLocaleString(buffer,MaxTextExtent,
2213                 "profile:%s=%.20g\n",name,(double)
2214                 GetStringInfoLength(profile));
2215               (void) WriteBlobString(image,buffer);
2216             }
2217           name=GetNextImageProfile(image);
2218         }
2219       }
2220     if (image->montage != (char *) NULL)
2221       {
2222         (void) FormatLocaleString(buffer,MaxTextExtent,"montage=%s\n",
2223           image->montage);
2224         (void) WriteBlobString(image,buffer);
2225       }
2226     if (quantum_info->format == FloatingPointQuantumFormat)
2227       (void) SetImageProperty(image,"quantum:format","floating-point",
2228         exception);
2229     ResetImagePropertyIterator(image);
2230     property=GetNextImageProperty(image);
2231     while (property != (const char *) NULL)
2232     {
2233       (void) FormatLocaleString(buffer,MaxTextExtent,"%s=",property);
2234       (void) WriteBlobString(image,buffer);
2235       value=GetImageProperty(image,property,exception);
2236       if (value != (const char *) NULL)
2237         {
2238           size_t
2239             length;
2240
2241           length=strlen(value);
2242           for (i=0; i < (ssize_t) length; i++)
2243             if (isspace((int) ((unsigned char) value[i])) != 0)
2244               break;
2245           if ((i == (ssize_t) length) && (i != 0))
2246             (void) WriteBlob(image,length,(const unsigned char *) value);
2247           else
2248             {
2249               (void) WriteBlobByte(image,'{');
2250               if (strchr(value,'}') == (char *) NULL)
2251                 (void) WriteBlob(image,length,(const unsigned char *) value);
2252               else
2253                 for (i=0; i < (ssize_t) length; i++)
2254                 {
2255                   if (value[i] == (int) '}')
2256                     (void) WriteBlobByte(image,'\\');
2257                   (void) WriteBlobByte(image,value[i]);
2258                 }
2259               (void) WriteBlobByte(image,'}');
2260             }
2261         }
2262       (void) WriteBlobByte(image,'\n');
2263       property=GetNextImageProperty(image);
2264     }
2265     (void) WriteBlobString(image,"\f\n:\032");
2266     if (image->montage != (char *) NULL)
2267       {
2268         /*
2269           Write montage tile directory.
2270         */
2271         if (image->directory != (char *) NULL)
2272           (void) WriteBlob(image,strlen(image->directory),(unsigned char *)
2273             image->directory);
2274         (void) WriteBlobByte(image,'\0');
2275       }
2276     if (image->profiles != (void *) NULL)
2277       {
2278         const char
2279           *name;
2280
2281         const StringInfo
2282           *profile;
2283
2284         /*
2285           Generic profile.
2286         */
2287         ResetImageProfileIterator(image);
2288         name=GetNextImageProfile(image);
2289         while (name != (const char *) NULL)
2290         {
2291           profile=GetImageProfile(image,name);
2292           (void) WriteBlob(image,GetStringInfoLength(profile),
2293             GetStringInfoDatum(profile));
2294           name=GetNextImageProfile(image);
2295         }
2296       }
2297     if (image->storage_class == PseudoClass)
2298       {
2299         size_t
2300           packet_size;
2301
2302         unsigned char
2303           *colormap,
2304           *q;
2305
2306         /*
2307           Allocate colormap.
2308         */
2309         packet_size=(size_t) (3*quantum_info->depth/8);
2310         colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
2311           packet_size*sizeof(*colormap));
2312         if (colormap == (unsigned char *) NULL)
2313           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2314         /*
2315           Write colormap to file.
2316         */
2317         q=colormap;
2318         for (i=0; i < (ssize_t) image->colors; i++)
2319         {
2320           switch (quantum_info->depth)
2321           {
2322             default:
2323               ThrowWriterException(CorruptImageError,"ImageDepthNotSupported");
2324             case 32:
2325             {
2326               register unsigned int
2327                 pixel;
2328
2329               pixel=ScaleQuantumToLong(image->colormap[i].red);
2330               q=PopLongPixel(MSBEndian,pixel,q);
2331               pixel=ScaleQuantumToLong(image->colormap[i].green);
2332               q=PopLongPixel(MSBEndian,pixel,q);
2333               pixel=ScaleQuantumToLong(image->colormap[i].blue);
2334               q=PopLongPixel(MSBEndian,pixel,q);
2335               break;
2336             }
2337             case 16:
2338             {
2339               register unsigned short
2340                 pixel;
2341
2342               pixel=ScaleQuantumToShort(image->colormap[i].red);
2343               q=PopShortPixel(MSBEndian,pixel,q);
2344               pixel=ScaleQuantumToShort(image->colormap[i].green);
2345               q=PopShortPixel(MSBEndian,pixel,q);
2346               pixel=ScaleQuantumToShort(image->colormap[i].blue);
2347               q=PopShortPixel(MSBEndian,pixel,q);
2348               break;
2349             }
2350             case 8:
2351             {
2352               register unsigned char
2353                 pixel;
2354
2355               pixel=(unsigned char) ScaleQuantumToChar(image->colormap[i].red);
2356               q=PopCharPixel(pixel,q);
2357               pixel=(unsigned char) ScaleQuantumToChar(
2358                 image->colormap[i].green);
2359               q=PopCharPixel(pixel,q);
2360               pixel=(unsigned char) ScaleQuantumToChar(image->colormap[i].blue);
2361               q=PopCharPixel(pixel,q);
2362               break;
2363             }
2364           }
2365         }
2366         (void) WriteBlob(image,packet_size*image->colors,colormap);
2367         colormap=(unsigned char *) RelinquishMagickMemory(colormap);
2368       }
2369     /*
2370       Write image pixels to file.
2371     */
2372     status=MagickTrue;
2373     switch (compression)
2374     {
2375 #if defined(MAGICKCORE_BZLIB_DELEGATE)
2376       case BZipCompression:
2377       {
2378         int
2379           code;
2380
2381         (void) ResetMagickMemory(&bzip_info,0,sizeof(bzip_info));
2382         bzip_info.bzalloc=AcquireBZIPMemory;
2383         bzip_info.bzfree=RelinquishBZIPMemory;
2384         code=BZ2_bzCompressInit(&bzip_info,(int) (image->quality ==
2385           UndefinedCompressionQuality ? 7 : MagickMin(image->quality/10,
2386           9)),(int) image_info->verbose,0);
2387         if (code != BZ_OK)
2388           status=MagickFalse;
2389         break;
2390       }
2391 #endif
2392 #if defined(MAGICKCORE_LZMA_DELEGATE)
2393       case LZMACompression:
2394       {
2395         int
2396           code;
2397
2398         (void) ResetMagickMemory(&allocator,0,sizeof(allocator));
2399         allocator.alloc=AcquireLZMAMemory;
2400         allocator.free=RelinquishLZMAMemory;
2401         lzma_info=initialize_lzma;
2402         lzma_info.allocator=&allocator;
2403         code=lzma_easy_encoder(&lzma_info,image->quality/10,LZMA_CHECK_SHA256);
2404         if (code != LZMA_OK)
2405           status=MagickTrue;
2406         break;
2407       }
2408 #endif
2409 #if defined(MAGICKCORE_ZLIB_DELEGATE)
2410       case LZWCompression:
2411       case ZipCompression:
2412       {
2413         int
2414           code;
2415
2416         (void) ResetMagickMemory(&zip_info,0,sizeof(zip_info));
2417         zip_info.zalloc=AcquireZIPMemory;
2418         zip_info.zfree=RelinquishZIPMemory;
2419         code=deflateInit(&zip_info,(int) (image->quality ==
2420           UndefinedCompressionQuality ? 7 : MagickMin(image->quality/10,9)));
2421         if (code != Z_OK)
2422           status=MagickFalse;
2423         break;
2424       }
2425 #endif
2426       default:
2427         break;
2428     }
2429     quantum_type=GetQuantumType(image,exception);
2430     pixels=GetQuantumPixels(quantum_info);
2431     for (y=0; y < (ssize_t) image->rows; y++)
2432     {
2433       register const Quantum
2434         *restrict p;
2435
2436       register ssize_t
2437         x;
2438
2439       if (status == MagickFalse)
2440         break;
2441       p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2442       if (p == (const Quantum *) NULL)
2443         break;
2444       q=pixels;
2445       switch (compression)
2446       {
2447 #if defined(MAGICKCORE_BZLIB_DELEGATE)
2448         case BZipCompression:
2449         {
2450           bzip_info.next_in=(char *) pixels;
2451           bzip_info.avail_in=(unsigned int) (packet_size*image->columns);
2452           (void) ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2453             quantum_type,pixels,exception);
2454           do
2455           {
2456             int
2457               code;
2458
2459             bzip_info.next_out=(char *) compress_pixels;
2460             bzip_info.avail_out=(unsigned int) BZipMaxExtent(packet_size*
2461               image->columns);
2462             code=BZ2_bzCompress(&bzip_info,BZ_FLUSH);
2463             if (code != BZ_OK)
2464               status=MagickFalse;
2465             length=(size_t) (bzip_info.next_out-(char *) compress_pixels);
2466             if (length != 0)
2467               {
2468                 (void) WriteBlobMSBLong(image,(unsigned int) length);
2469                 (void) WriteBlob(image,length,compress_pixels);
2470               }
2471           } while (bzip_info.avail_in != 0);
2472           break;
2473         }
2474 #endif
2475 #if defined(MAGICKCORE_LZMA_DELEGATE)
2476         case LZMACompression:
2477         {
2478           lzma_info.next_in=pixels;
2479           lzma_info.avail_in=packet_size*image->columns;
2480           (void) ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2481             quantum_type,pixels,exception);
2482           do
2483           {
2484             int
2485               code;
2486
2487             lzma_info.next_out=compress_pixels;
2488             lzma_info.avail_out=packet_size*image->columns;
2489             code=lzma_code(&lzma_info,LZMA_RUN);
2490             if (code != LZMA_OK)
2491               status=MagickFalse;
2492             length=(size_t) (lzma_info.next_out-compress_pixels);
2493             if (length != 0)
2494               {
2495                 (void) WriteBlobMSBLong(image,(unsigned int) length);
2496                 (void) WriteBlob(image,length,compress_pixels);
2497               }
2498           } while (lzma_info.avail_in != 0);
2499           break;
2500         }
2501 #endif
2502 #if defined(MAGICKCORE_ZLIB_DELEGATE)
2503         case LZWCompression:
2504         case ZipCompression:
2505         {
2506           zip_info.next_in=pixels;
2507           zip_info.avail_in=(uInt) (packet_size*image->columns);
2508           (void) ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2509             quantum_type,pixels,exception);
2510           do
2511           {
2512             int
2513               code;
2514
2515             zip_info.next_out=compress_pixels;
2516             zip_info.avail_out=(uInt) ZipMaxExtent(packet_size*image->columns);
2517             code=deflate(&zip_info,Z_SYNC_FLUSH);
2518             if (code != Z_OK)
2519               status=MagickFalse;
2520             length=(size_t) (zip_info.next_out-compress_pixels);
2521             if (length != 0)
2522               {
2523                 (void) WriteBlobMSBLong(image,(unsigned int) length);
2524                 (void) WriteBlob(image,length,compress_pixels);
2525               }
2526           } while (zip_info.avail_in != 0);
2527           break;
2528         }
2529 #endif
2530         case RLECompression:
2531         {
2532           length=0;
2533           GetPixelInfoPixel(image,p,&pixel);
2534           p+=GetPixelChannels(image);
2535           for (x=1; x < (ssize_t) image->columns; x++)
2536           {
2537             GetPixelInfoPixel(image,p,&target);
2538             if ((length < 255) &&
2539                 (IsPixelInfoEquivalent(&pixel,&target) != MagickFalse))
2540               length++;
2541             else
2542               {
2543                 q=PopRunlengthPacket(image,q,length,&pixel,exception);
2544                 length=0;
2545               }
2546             GetPixelInfoPixel(image,p,&pixel);
2547             p+=GetPixelChannels(image);
2548           }
2549           q=PopRunlengthPacket(image,q,length,&pixel,exception);
2550           (void) WriteBlob(image,(size_t) (q-pixels),pixels);
2551           break;
2552         }
2553         default:
2554         {
2555           (void) ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2556             quantum_type,pixels,exception);
2557           (void) WriteBlob(image,packet_size*image->columns,pixels);
2558           break;
2559         }
2560       }
2561       if (image->previous == (Image *) NULL)
2562         {
2563           status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2564             image->rows);
2565           if (status == MagickFalse)
2566             break;
2567         }
2568     }
2569     switch (compression)
2570     {
2571 #if defined(MAGICKCORE_BZLIB_DELEGATE)
2572       case BZipCompression:
2573       {
2574         int
2575           code;
2576
2577         for ( ; ; )
2578         {
2579           if (status == MagickFalse)
2580             break;
2581           bzip_info.next_out=(char *) compress_pixels;
2582           bzip_info.avail_out=(unsigned int) BZipMaxExtent(packet_size*
2583             image->columns);
2584           code=BZ2_bzCompress(&bzip_info,BZ_FINISH);
2585           length=(size_t) (bzip_info.next_out-(char *) compress_pixels);
2586           if (length != 0)
2587             {
2588               (void) WriteBlobMSBLong(image,(unsigned int) length);
2589               (void) WriteBlob(image,length,compress_pixels);
2590             }
2591           if (code == BZ_STREAM_END)
2592             break;
2593         }
2594         code=BZ2_bzCompressEnd(&bzip_info);
2595         if (code != BZ_OK)
2596           status=MagickFalse;
2597         break;
2598       }
2599 #endif
2600 #if defined(MAGICKCORE_LZMA_DELEGATE)
2601       case LZMACompression:
2602       {
2603         int
2604           code;
2605
2606         for ( ; ; )
2607         {
2608           if (status == MagickFalse)
2609             break;
2610           lzma_info.next_out=compress_pixels;
2611           lzma_info.avail_out=packet_size*image->columns;
2612           code=lzma_code(&lzma_info,LZMA_FINISH);
2613           length=(size_t) (lzma_info.next_out-compress_pixels);
2614           if (length > 6)
2615             {
2616               (void) WriteBlobMSBLong(image,(unsigned int) length);
2617               (void) WriteBlob(image,length,compress_pixels);
2618             }
2619           if (code == LZMA_STREAM_END)
2620             break;
2621         }
2622         lzma_end(&lzma_info);
2623         break;
2624       }
2625 #endif
2626 #if defined(MAGICKCORE_ZLIB_DELEGATE)
2627       case LZWCompression:
2628       case ZipCompression:
2629       {
2630         int
2631           code;
2632
2633         for ( ; ; )
2634         {
2635           if (status == MagickFalse)
2636             break;
2637           zip_info.next_out=compress_pixels;
2638           zip_info.avail_out=(uInt) ZipMaxExtent(packet_size*image->columns);
2639           code=deflate(&zip_info,Z_FINISH);
2640           length=(size_t) (zip_info.next_out-compress_pixels);
2641           if (length > 6)
2642             {
2643               (void) WriteBlobMSBLong(image,(unsigned int) length);
2644               (void) WriteBlob(image,length,compress_pixels);
2645             }
2646           if (code == Z_STREAM_END)
2647             break;
2648         }
2649         code=deflateEnd(&zip_info);
2650         if (code != Z_OK)
2651           status=MagickFalse;
2652         break;
2653       }
2654 #endif
2655       default:
2656         break;
2657     }
2658     quantum_info=DestroyQuantumInfo(quantum_info);
2659     compress_pixels=(unsigned char *) RelinquishMagickMemory(compress_pixels);
2660     if (GetNextImageInList(image) == (Image *) NULL)
2661       break;
2662     image=SyncNextImageInList(image);
2663     status=SetImageProgress(image,SaveImagesTag,scene++,
2664       GetImageListLength(image));
2665     if (status == MagickFalse)
2666       break;
2667   } while (image_info->adjoin != MagickFalse);
2668   (void) CloseBlob(image);
2669   return(status);
2670 }