]> granicus.if.org Git - imagemagick/blob - coders/miff.c
2ece9f2803d881f256373556bcf09c496c6f920c
[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-2012 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                     (void) SetImageColorspace(image,(ColorspaceType) colorspace,                      exception);
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 ((LocaleNCompare(keyword,"profile:",8) == 0) ||
888                     (LocaleNCompare(keyword,"profile-",8) == 0))
889                   {
890                     StringInfo
891                       *profile;
892
893                     if (profiles == (LinkedListInfo *) NULL)
894                       profiles=NewLinkedList(0);
895                     (void) AppendValueToLinkedList(profiles,
896                       AcquireString(keyword+8));
897                     profile=BlobToStringInfo((const void *) NULL,(size_t)
898                       StringToLong(options));
899                     if (profile == (StringInfo *) NULL)
900                       ThrowReaderException(ResourceLimitError,
901                         "MemoryAllocationFailed");
902                     (void) SetImageProfile(image,keyword+8,profile,exception);
903                     profile=DestroyStringInfo(profile);
904                     break;
905                   }
906                 (void) SetImageProperty(image,keyword,options,exception);
907                 break;
908               }
909               case 'q':
910               case 'Q':
911               {
912                 if (LocaleCompare(keyword,"quality") == 0)
913                   {
914                     image->quality=StringToUnsignedLong(options);
915                     break;
916                   }
917                 if ((LocaleCompare(keyword,"quantum-format") == 0) ||
918                     (LocaleCompare(keyword,"quantum:format") == 0))
919                   {
920                     ssize_t
921                       format;
922
923                     format=ParseCommandOption(MagickQuantumFormatOptions,
924                       MagickFalse,options);
925                     if (format < 0)
926                       break;
927                     quantum_format=(QuantumFormatType) format;
928                     break;
929                   }
930                 (void) SetImageProperty(image,keyword,options,exception);
931                 break;
932               }
933               case 'r':
934               case 'R':
935               {
936                 if (LocaleCompare(keyword,"red-primary") == 0)
937                   {
938                     flags=ParseGeometry(options,&geometry_info);
939                     image->chromaticity.red_primary.x=geometry_info.rho;
940                     image->chromaticity.red_primary.y=geometry_info.sigma;
941                     if ((flags & SigmaValue) == 0)
942                       image->chromaticity.red_primary.y=
943                         image->chromaticity.red_primary.x;
944                     break;
945                   }
946                 if (LocaleCompare(keyword,"rendering-intent") == 0)
947                   {
948                     ssize_t
949                       rendering_intent;
950
951                     rendering_intent=ParseCommandOption(MagickIntentOptions,
952                       MagickFalse,options);
953                     if (rendering_intent < 0)
954                       break;
955                     image->rendering_intent=(RenderingIntent) rendering_intent;
956                     break;
957                   }
958                 if (LocaleCompare(keyword,"resolution") == 0)
959                   {
960                     flags=ParseGeometry(options,&geometry_info);
961                     image->resolution.x=geometry_info.rho;
962                     image->resolution.y=geometry_info.sigma;
963                     if ((flags & SigmaValue) == 0)
964                       image->resolution.y=image->resolution.x;
965                     break;
966                   }
967                 if (LocaleCompare(keyword,"rows") == 0)
968                   {
969                     image->rows=StringToUnsignedLong(options);
970                     break;
971                   }
972                 (void) SetImageProperty(image,keyword,options,exception);
973                 break;
974               }
975               case 's':
976               case 'S':
977               {
978                 if (LocaleCompare(keyword,"scene") == 0)
979                   {
980                     image->scene=StringToUnsignedLong(options);
981                     break;
982                   }
983                 (void) SetImageProperty(image,keyword,options,exception);
984                 break;
985               }
986               case 't':
987               case 'T':
988               {
989                 if (LocaleCompare(keyword,"ticks-per-second") == 0)
990                   {
991                     image->ticks_per_second=(ssize_t) StringToLong(options);
992                     break;
993                   }
994                 if (LocaleCompare(keyword,"tile-offset") == 0)
995                   {
996                     char
997                       *geometry;
998
999                     geometry=GetPageGeometry(options);
1000                     (void) ParseAbsoluteGeometry(geometry,&image->tile_offset);
1001                     geometry=DestroyString(geometry);
1002                     break;
1003                   }
1004                 if (LocaleCompare(keyword,"type") == 0)
1005                   {
1006                     ssize_t
1007                       type;
1008
1009                     type=ParseCommandOption(MagickTypeOptions,MagickFalse,
1010                       options);
1011                     if (type < 0)
1012                       break;
1013                     image->type=(ImageType) type;
1014                     break;
1015                   }
1016                 (void) SetImageProperty(image,keyword,options,exception);
1017                 break;
1018               }
1019               case 'u':
1020               case 'U':
1021               {
1022                 if (LocaleCompare(keyword,"units") == 0)
1023                   {
1024                     ssize_t
1025                       units;
1026
1027                     units=ParseCommandOption(MagickResolutionOptions,
1028                       MagickFalse,options);
1029                     if (units < 0)
1030                       break;
1031                     image->units=(ResolutionType) units;
1032                     break;
1033                   }
1034                 (void) SetImageProperty(image,keyword,options,exception);
1035                 break;
1036               }
1037               case 'v':
1038               case 'V':
1039               {
1040                 if (LocaleCompare(keyword,"version") == 0)
1041                   {
1042                     version=StringToDouble(options,(char **) NULL);
1043                     break;
1044                   }
1045                 (void) SetImageProperty(image,keyword,options,exception);
1046                 break;
1047               }
1048               case 'w':
1049               case 'W':
1050               {
1051                 if (LocaleCompare(keyword,"white-point") == 0)
1052                   {
1053                     flags=ParseGeometry(options,&geometry_info);
1054                     image->chromaticity.white_point.x=geometry_info.rho;
1055                     image->chromaticity.white_point.y=geometry_info.sigma;
1056                     if ((flags & SigmaValue) == 0)
1057                       image->chromaticity.white_point.y=
1058                         image->chromaticity.white_point.x;
1059                     break;
1060                   }
1061                 (void) SetImageProperty(image,keyword,options,exception);
1062                 break;
1063               }
1064               default:
1065               {
1066                 (void) SetImageProperty(image,keyword,options,exception);
1067                 break;
1068               }
1069             }
1070           }
1071         else
1072           c=ReadBlobByte(image);
1073       while (isspace((int) ((unsigned char) c)) != 0)
1074         c=ReadBlobByte(image);
1075     }
1076     options=DestroyString(options);
1077     (void) ReadBlobByte(image);
1078     /*
1079       Verify that required image information is defined.
1080     */
1081     if ((LocaleCompare(id,"ImageMagick") != 0) ||
1082         (image->storage_class == UndefinedClass) ||
1083         (image->columns == 0) || (image->rows == 0))
1084       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1085     if (image->montage != (char *) NULL)
1086       {
1087         register char
1088           *p;
1089
1090         /*
1091           Image directory.
1092         */
1093         length=MaxTextExtent;
1094         image->directory=AcquireString((char *) NULL);
1095         p=image->directory;
1096         do
1097         {
1098           *p='\0';
1099           if ((strlen(image->directory)+MaxTextExtent) >= length)
1100             {
1101               /*
1102                 Allocate more memory for the image directory.
1103               */
1104               length<<=1;
1105               image->directory=(char *) ResizeQuantumMemory(image->directory,
1106                 length+MaxTextExtent,sizeof(*image->directory));
1107               if (image->directory == (char *) NULL)
1108                 ThrowReaderException(CorruptImageError,"UnableToReadImageData");
1109               p=image->directory+strlen(image->directory);
1110             }
1111           c=ReadBlobByte(image);
1112           *p++=(char) c;
1113         } while (c != (int) '\0');
1114       }
1115     if (profiles != (LinkedListInfo *) NULL)
1116       {
1117         const char
1118           *name;
1119
1120         const StringInfo
1121           *profile;
1122
1123         /*
1124           Read image profiles.
1125         */
1126         ResetLinkedListIterator(profiles);
1127         name=(const char *) GetNextValueInLinkedList(profiles);
1128         while (name != (const char *) NULL)
1129         {
1130           profile=GetImageProfile(image,name);
1131           if (profile != (StringInfo *) NULL)
1132             {
1133               register unsigned char
1134                 *p;
1135
1136               p=GetStringInfoDatum(profile);
1137               count=ReadBlob(image,GetStringInfoLength(profile),p);
1138               (void) count;
1139             }
1140           name=(const char *) GetNextValueInLinkedList(profiles);
1141         }
1142         profiles=DestroyLinkedList(profiles,RelinquishMagickMemory);
1143       }
1144     image->depth=GetImageQuantumDepth(image,MagickFalse);
1145     if (image->storage_class == PseudoClass)
1146       {
1147         /*
1148           Create image colormap.
1149         */
1150         status=AcquireImageColormap(image,colors != 0 ? colors : 256,exception);
1151         if (status == MagickFalse)
1152           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1153         if (colors != 0)
1154           {
1155             size_t
1156               packet_size;
1157
1158             unsigned char
1159               *colormap;
1160
1161             /*
1162               Read image colormap from file.
1163             */
1164             packet_size=(size_t) (3UL*image->depth/8UL);
1165             colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
1166               packet_size*sizeof(*colormap));
1167             if (colormap == (unsigned char *) NULL)
1168               ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1169             count=ReadBlob(image,packet_size*image->colors,colormap);
1170             p=colormap;
1171             switch (image->depth)
1172             {
1173               default:
1174                 ThrowReaderException(CorruptImageError,
1175                   "ImageDepthNotSupported");
1176               case 8:
1177               {
1178                 unsigned char
1179                   pixel;
1180
1181                 for (i=0; i < (ssize_t) image->colors; i++)
1182                 {
1183                   p=PushCharPixel(p,&pixel);
1184                   image->colormap[i].red=ScaleCharToQuantum(pixel);
1185                   p=PushCharPixel(p,&pixel);
1186                   image->colormap[i].green=ScaleCharToQuantum(pixel);
1187                   p=PushCharPixel(p,&pixel);
1188                   image->colormap[i].blue=ScaleCharToQuantum(pixel);
1189                 }
1190                 break;
1191               }
1192               case 16:
1193               {
1194                 unsigned short
1195                   pixel;
1196
1197                 for (i=0; i < (ssize_t) image->colors; i++)
1198                 {
1199                   p=PushShortPixel(MSBEndian,p,&pixel);
1200                   image->colormap[i].red=ScaleShortToQuantum(pixel);
1201                   p=PushShortPixel(MSBEndian,p,&pixel);
1202                   image->colormap[i].green=ScaleShortToQuantum(pixel);
1203                   p=PushShortPixel(MSBEndian,p,&pixel);
1204                   image->colormap[i].blue=ScaleShortToQuantum(pixel);
1205                 }
1206                 break;
1207               }
1208               case 32:
1209               {
1210                 unsigned int
1211                   pixel;
1212
1213                 for (i=0; i < (ssize_t) image->colors; i++)
1214                 {
1215                   p=PushLongPixel(MSBEndian,p,&pixel);
1216                   image->colormap[i].red=ScaleLongToQuantum(pixel);
1217                   p=PushLongPixel(MSBEndian,p,&pixel);
1218                   image->colormap[i].green=ScaleLongToQuantum(pixel);
1219                   p=PushLongPixel(MSBEndian,p,&pixel);
1220                   image->colormap[i].blue=ScaleLongToQuantum(pixel);
1221                 }
1222                 break;
1223               }
1224             }
1225             colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1226           }
1227       }
1228     if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
1229       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1230         break;
1231     /*
1232       Allocate image pixels.
1233     */
1234     quantum_info=AcquireQuantumInfo(image_info,image);
1235     if (quantum_info == (QuantumInfo *) NULL)
1236       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1237     if (quantum_format != UndefinedQuantumFormat)
1238       {
1239         status=SetQuantumFormat(image,quantum_info,quantum_format);
1240         if (status == MagickFalse)
1241           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1242       }
1243     packet_size=(size_t) (quantum_info->depth/8);
1244     if (image->storage_class == DirectClass)
1245       packet_size=(size_t) (3*quantum_info->depth/8);
1246     if (IsGrayColorspace(image->colorspace) != MagickFalse)
1247       packet_size=quantum_info->depth/8;
1248     if (image->alpha_trait == BlendPixelTrait)
1249       packet_size+=quantum_info->depth/8;
1250     if (image->colorspace == CMYKColorspace)
1251       packet_size+=quantum_info->depth/8;
1252     if (image->compression == RLECompression)
1253       packet_size++;
1254     length=image->columns;
1255     length=MagickMax(MagickMax(BZipMaxExtent(packet_size*image->columns),
1256       LZMAMaxExtent(packet_size*image->columns)),ZipMaxExtent(packet_size*
1257       image->columns));
1258     compress_pixels=(unsigned char *) AcquireQuantumMemory(length,
1259       sizeof(*compress_pixels));
1260     if (compress_pixels == (unsigned char *) NULL)
1261       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1262     /*
1263       Read image pixels.
1264     */
1265     quantum_type=RGBQuantum;
1266     if (image->alpha_trait == BlendPixelTrait)
1267       quantum_type=RGBAQuantum;
1268     if (image->colorspace == CMYKColorspace)
1269       {
1270         quantum_type=CMYKQuantum;
1271         if (image->alpha_trait == BlendPixelTrait)
1272           quantum_type=CMYKAQuantum;
1273       }
1274     if (IsGrayColorspace(image->colorspace) != MagickFalse)
1275       {
1276         quantum_type=GrayQuantum;
1277         if (image->alpha_trait == BlendPixelTrait)
1278           quantum_type=GrayAlphaQuantum;
1279       }
1280     if (image->storage_class == PseudoClass)
1281       {
1282         quantum_type=IndexQuantum;
1283         if (image->alpha_trait == BlendPixelTrait)
1284           quantum_type=IndexAlphaQuantum;
1285       }
1286     status=MagickTrue;
1287     switch (image->compression)
1288     {
1289 #if defined(MAGICKCORE_BZLIB_DELEGATE)
1290       case BZipCompression:
1291       {
1292         int
1293           code;
1294
1295         (void) ResetMagickMemory(&bzip_info,0,sizeof(bzip_info));
1296         bzip_info.bzalloc=AcquireBZIPMemory;
1297         bzip_info.bzfree=RelinquishBZIPMemory;
1298         bzip_info.opaque=(void *) NULL;
1299         code=BZ2_bzDecompressInit(&bzip_info,(int) image_info->verbose,
1300           MagickFalse);
1301         if (code != BZ_OK)
1302           status=MagickFalse;
1303         break;
1304       }
1305 #endif
1306 #if defined(MAGICKCORE_LZMA_DELEGATE)
1307       case LZMACompression:
1308       {
1309         int
1310           code;
1311
1312         (void) ResetMagickMemory(&allocator,0,sizeof(allocator));
1313         allocator.alloc=AcquireLZMAMemory;
1314         allocator.free=RelinquishLZMAMemory;
1315         lzma_info=initialize_lzma;
1316         lzma_info.allocator=(&allocator);
1317         code=lzma_auto_decoder(&lzma_info,-1,0);
1318         if (code != LZMA_OK)
1319           status=MagickFalse;
1320         break;
1321       }
1322 #endif
1323 #if defined(MAGICKCORE_ZLIB_DELEGATE)
1324       case LZWCompression:
1325       case ZipCompression:
1326       {
1327         int
1328           code;
1329
1330         (void) ResetMagickMemory(&zip_info,0,sizeof(zip_info));
1331         zip_info.zalloc=AcquireZIPMemory;
1332         zip_info.zfree=RelinquishZIPMemory;
1333         zip_info.opaque=(voidpf) NULL;
1334         code=inflateInit(&zip_info);
1335         if (code != Z_OK)
1336           status=MagickFalse;
1337         break;
1338       }
1339 #endif
1340       case RLECompression:
1341       {
1342         GetPixelInfo(image,&pixel);
1343         break;
1344       }
1345       default:
1346         break;
1347     }
1348     pixels=GetQuantumPixels(quantum_info);
1349     length=0;
1350     for (y=0; y < (ssize_t) image->rows; y++)
1351     {
1352       register ssize_t
1353         x;
1354
1355       register Quantum
1356         *restrict q;
1357
1358       if (status == MagickFalse)
1359         break;
1360       q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1361       if (q == (Quantum *) NULL)
1362         break;
1363       switch (image->compression)
1364       {
1365 #if defined(MAGICKCORE_BZLIB_DELEGATE)
1366         case BZipCompression:
1367         {
1368           bzip_info.next_out=(char *) pixels;
1369           bzip_info.avail_out=(unsigned int) (packet_size*image->columns);
1370           do
1371           {
1372             if (bzip_info.avail_in == 0)
1373               {
1374                 bzip_info.next_in=(char *) compress_pixels;
1375                 length=(size_t) BZipMaxExtent(packet_size*image->columns);
1376                 if (version != 0.0)
1377                   length=(size_t) ReadBlobMSBLong(image);
1378                 bzip_info.avail_in=(unsigned int) ReadBlob(image,length,
1379                   (unsigned char *) bzip_info.next_in);
1380               }
1381             if (BZ2_bzDecompress(&bzip_info) == BZ_STREAM_END)
1382               break;
1383           } while (bzip_info.avail_out != 0);
1384           (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1385             quantum_type,pixels,exception);
1386           break;
1387         }
1388 #endif
1389 #if defined(MAGICKCORE_LZMA_DELEGATE)
1390         case LZMACompression:
1391         {
1392           lzma_info.next_out=pixels;
1393           lzma_info.avail_out=packet_size*image->columns;
1394           do
1395           {
1396             int
1397               code;
1398
1399             if (lzma_info.avail_in == 0)
1400               {
1401                 lzma_info.next_in=compress_pixels;
1402                 length=(size_t) ReadBlobMSBLong(image);
1403                 lzma_info.avail_in=(unsigned int) ReadBlob(image,length,
1404                   (unsigned char *) lzma_info.next_in);
1405               }
1406             code=lzma_code(&lzma_info,LZMA_RUN);
1407             if (code < 0)
1408               {
1409                 status=MagickFalse;
1410                 break;
1411               }
1412             if (code == LZMA_STREAM_END)
1413               break;
1414           } while (lzma_info.avail_out != 0);
1415           (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1416             quantum_type,pixels,exception);
1417           break;
1418         }
1419 #endif
1420 #if defined(MAGICKCORE_ZLIB_DELEGATE)
1421         case LZWCompression:
1422         case ZipCompression:
1423         {
1424           zip_info.next_out=pixels;
1425           zip_info.avail_out=(uInt) (packet_size*image->columns);
1426           do
1427           {
1428             if (zip_info.avail_in == 0)
1429               {
1430                 zip_info.next_in=compress_pixels;
1431                 length=(size_t) ZipMaxExtent(packet_size*image->columns);
1432                 if (version != 0.0)
1433                   length=(size_t) ReadBlobMSBLong(image);
1434                 zip_info.avail_in=(unsigned int) ReadBlob(image,length,
1435                   zip_info.next_in);
1436               }
1437             if (inflate(&zip_info,Z_SYNC_FLUSH) == Z_STREAM_END)
1438               break;
1439           } while (zip_info.avail_out != 0);
1440           (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1441             quantum_type,pixels,exception);
1442           break;
1443         }
1444 #endif
1445         case RLECompression:
1446         {
1447           for (x=0; x < (ssize_t) image->columns; x++)
1448           {
1449             if (length == 0)
1450               {
1451                 count=ReadBlob(image,packet_size,pixels);
1452                 PushRunlengthPacket(image,pixels,&length,&pixel,exception);
1453               }
1454             length--;
1455             if (image->storage_class == PseudoClass)
1456               SetPixelIndex(image,ClampToQuantum(pixel.index),q);
1457             else
1458               {
1459                 SetPixelRed(image,ClampToQuantum(pixel.red),q);
1460                 SetPixelGreen(image,ClampToQuantum(pixel.green),q);
1461                 SetPixelBlue(image,ClampToQuantum(pixel.blue),q);
1462                 if (image->colorspace == CMYKColorspace)
1463                   SetPixelBlack(image,ClampToQuantum(pixel.black),q);
1464               }
1465             if (image->alpha_trait == BlendPixelTrait)
1466               SetPixelAlpha(image,ClampToQuantum(pixel.alpha),q);
1467             q+=GetPixelChannels(image);
1468           }
1469           break;
1470         }
1471         default:
1472         {
1473           count=ReadBlob(image,packet_size*image->columns,pixels);
1474           (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1475             quantum_type,pixels,exception);
1476           break;
1477         }
1478       }
1479       if (SyncAuthenticPixels(image,exception) == MagickFalse)
1480         break;
1481     }
1482     SetQuantumImageType(image,quantum_type);
1483     switch (image->compression)
1484     {
1485 #if defined(MAGICKCORE_BZLIB_DELEGATE)
1486       case BZipCompression:
1487       {
1488         int
1489           code;
1490
1491         if (version == 0.0)
1492           {
1493             MagickOffsetType
1494               offset;
1495
1496             offset=SeekBlob(image,-((MagickOffsetType)
1497               bzip_info.avail_in),SEEK_CUR);
1498             if (offset < 0)
1499               ThrowReaderException(CorruptImageError,
1500                 "ImproperImageHeader");
1501           }
1502         code=BZ2_bzDecompressEnd(&bzip_info);
1503         if (code != BZ_OK)
1504           status=MagickFalse;
1505         break;
1506       }
1507 #endif
1508 #if defined(MAGICKCORE_LZMA_DELEGATE)
1509       case LZMACompression:
1510       {
1511         int
1512           code;
1513
1514         code=lzma_code(&lzma_info,LZMA_FINISH);
1515         if ((code != LZMA_STREAM_END) && (code != LZMA_OK))
1516           status=MagickFalse;
1517         lzma_end(&lzma_info);
1518         break;
1519       }
1520 #endif
1521 #if defined(MAGICKCORE_ZLIB_DELEGATE)
1522       case LZWCompression:
1523       case ZipCompression:
1524       {
1525         int
1526           code;
1527
1528         if (version == 0.0)
1529           {
1530             MagickOffsetType
1531               offset;
1532
1533             offset=SeekBlob(image,-((MagickOffsetType) zip_info.avail_in),
1534               SEEK_CUR);
1535             if (offset < 0)
1536               ThrowReaderException(CorruptImageError,
1537                 "ImproperImageHeader");
1538           }
1539         code=inflateEnd(&zip_info);
1540         if (code != LZMA_OK)
1541           status=MagickFalse;
1542         break;
1543       }
1544 #endif
1545       default:
1546         break;
1547     }
1548     quantum_info=DestroyQuantumInfo(quantum_info);
1549     compress_pixels=(unsigned char *) RelinquishMagickMemory(compress_pixels);
1550     if (((y != (ssize_t) image->rows)) || (status == MagickFalse))
1551       {
1552         image=DestroyImageList(image);
1553         return((Image *) NULL);
1554       }
1555     if (EOFBlob(image) != MagickFalse)
1556       {
1557         ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
1558           image->filename);
1559         break;
1560       }
1561     /*
1562       Proceed to next image.
1563     */
1564     if (image_info->number_scenes != 0)
1565       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1566         break;
1567     do
1568     {
1569       c=ReadBlobByte(image);
1570     } while ((isgraph(c) == MagickFalse) && (c != EOF));
1571     if (c != EOF)
1572       {
1573         /*
1574           Allocate next image structure.
1575         */
1576         AcquireNextImage(image_info,image,exception);
1577         if (GetNextImageInList(image) == (Image *) NULL)
1578           {
1579             image=DestroyImageList(image);
1580             return((Image *) NULL);
1581           }
1582         image=SyncNextImageInList(image);
1583         status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
1584           GetBlobSize(image));
1585         if (status == MagickFalse)
1586           break;
1587       }
1588   } while (c != EOF);
1589   (void) CloseBlob(image);
1590   return(GetFirstImageInList(image));
1591 }
1592 \f
1593 /*
1594 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1595 %                                                                             %
1596 %                                                                             %
1597 %                                                                             %
1598 %   R e g i s t e r M I F F I m a g e                                         %
1599 %                                                                             %
1600 %                                                                             %
1601 %                                                                             %
1602 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1603 %
1604 %  RegisterMIFFImage() adds properties for the MIFF image format to the list of
1605 %  supported formats.  The properties include the image format tag, a method to
1606 %  read and/or write the format, whether the format supports the saving of more
1607 %  than one frame to the same file or blob, whether the format supports native
1608 %  in-memory I/O, and a brief description of the format.
1609 %
1610 %  The format of the RegisterMIFFImage method is:
1611 %
1612 %      size_t RegisterMIFFImage(void)
1613 %
1614 */
1615 ModuleExport size_t RegisterMIFFImage(void)
1616 {
1617   char
1618     version[MaxTextExtent];
1619
1620   MagickInfo
1621     *entry;
1622
1623   *version='\0';
1624 #if defined(MagickImageCoderSignatureText)
1625   (void) CopyMagickString(version,MagickLibVersionText,MaxTextExtent);
1626 #if defined(ZLIB_VERSION)
1627   (void) ConcatenateMagickString(version," with Zlib ",MaxTextExtent);
1628   (void) ConcatenateMagickString(version,ZLIB_VERSION,MaxTextExtent);
1629 #endif
1630 #if defined(MAGICKCORE_BZLIB_DELEGATE)
1631   (void) ConcatenateMagickString(version," and BZlib",MaxTextExtent);
1632 #endif
1633 #endif
1634   entry=SetMagickInfo("MIFF");
1635   entry->decoder=(DecodeImageHandler *) ReadMIFFImage;
1636   entry->encoder=(EncodeImageHandler *) WriteMIFFImage;
1637   entry->magick=(IsImageFormatHandler *) IsMIFF;
1638   entry->seekable_stream=MagickTrue;
1639   entry->description=ConstantString("Magick Image File Format");
1640   if (*version != '\0')
1641     entry->version=ConstantString(version);
1642   entry->module=ConstantString("MIFF");
1643   (void) RegisterMagickInfo(entry);
1644   return(MagickImageCoderSignature);
1645 }
1646 \f
1647 /*
1648 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1649 %                                                                             %
1650 %                                                                             %
1651 %                                                                             %
1652 %   U n r e g i s t e r M I F F I m a g e                                     %
1653 %                                                                             %
1654 %                                                                             %
1655 %                                                                             %
1656 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1657 %
1658 %  UnregisterMIFFImage() removes format registrations made by the MIFF module
1659 %  from the list of supported formats.
1660 %
1661 %  The format of the UnregisterMIFFImage method is:
1662 %
1663 %      UnregisterMIFFImage(void)
1664 %
1665 */
1666 ModuleExport void UnregisterMIFFImage(void)
1667 {
1668   (void) UnregisterMagickInfo("MIFF");
1669 }
1670 \f
1671 /*
1672 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1673 %                                                                             %
1674 %                                                                             %
1675 %                                                                             %
1676 %   W r i t e M I F F I m a g e                                               %
1677 %                                                                             %
1678 %                                                                             %
1679 %                                                                             %
1680 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1681 %
1682 %  WriteMIFFImage() writes a MIFF image to a file.
1683 %
1684 %  The format of the WriteMIFFImage method is:
1685 %
1686 %      MagickBooleanType WriteMIFFImage(const ImageInfo *image_info,
1687 %        Image *image,ExceptionInfo *exception)
1688 %
1689 %  Compression code contributed by Kyle Shorter.
1690 %
1691 %  A description of each parameter follows:
1692 %
1693 %    o image_info: the image info.
1694 %
1695 %    o image: the image.
1696 %
1697 %    o exception: return any errors or warnings in this structure.
1698 %
1699 */
1700
1701 static unsigned char *PopRunlengthPacket(Image *image,unsigned char *pixels,
1702   size_t length,PixelInfo *pixel,ExceptionInfo *exception)
1703 {
1704   if (image->storage_class != DirectClass)
1705     {
1706       switch (image->depth)
1707       {
1708         case 32:
1709         {
1710           *pixels++=(unsigned char) ((size_t) pixel->index >> 24);
1711           *pixels++=(unsigned char) ((size_t) pixel->index >> 16);
1712         }
1713         case 16:
1714           *pixels++=(unsigned char) ((size_t) pixel->index >> 8);
1715         case 8:
1716         {
1717           *pixels++=(unsigned char) pixel->index;
1718           break;
1719         }
1720         default:
1721           (void) ThrowMagickException(exception,GetMagickModule(),
1722             CorruptImageError,"ImageDepthNotSupported","`%s'",image->filename);
1723       }
1724       switch (image->depth)
1725       {
1726         case 32:
1727         {
1728           unsigned int
1729             value;
1730
1731           if (image->alpha_trait == BlendPixelTrait)
1732             {
1733               value=ScaleQuantumToLong(ClampToQuantum(pixel->alpha));
1734               pixels=PopLongPixel(MSBEndian,value,pixels);
1735             }
1736           break;
1737         }
1738         case 16:
1739         {
1740           unsigned short
1741             value;
1742
1743           if (image->alpha_trait == BlendPixelTrait)
1744             {
1745               value=ScaleQuantumToShort(ClampToQuantum(pixel->alpha));
1746               pixels=PopShortPixel(MSBEndian,value,pixels);
1747             }
1748           break;
1749         }
1750         case 8:
1751         {
1752           unsigned char
1753             value;
1754
1755           if (image->alpha_trait == BlendPixelTrait)
1756             {
1757               value=(unsigned char) ScaleQuantumToChar(ClampToQuantum(
1758                 pixel->alpha));
1759               pixels=PopCharPixel(value,pixels);
1760             }
1761           break;
1762         }
1763         default:
1764           (void) ThrowMagickException(exception,GetMagickModule(),
1765             CorruptImageError,"ImageDepthNotSupported","`%s'",image->filename);
1766       }
1767       *pixels++=(unsigned char) length;
1768       return(pixels);
1769     }
1770   switch (image->depth)
1771   {
1772     case 32:
1773     {
1774       unsigned int
1775         value;
1776
1777       value=ScaleQuantumToLong(ClampToQuantum(pixel->red));
1778       pixels=PopLongPixel(MSBEndian,value,pixels);
1779       if (IsGrayColorspace(image->colorspace) == MagickFalse)
1780         {
1781           value=ScaleQuantumToLong(ClampToQuantum(pixel->green));
1782           pixels=PopLongPixel(MSBEndian,value,pixels);
1783           value=ScaleQuantumToLong(ClampToQuantum(pixel->blue));
1784           pixels=PopLongPixel(MSBEndian,value,pixels);
1785         }
1786       if (image->colorspace == CMYKColorspace)
1787         {
1788           value=ScaleQuantumToLong(ClampToQuantum(pixel->black));
1789           pixels=PopLongPixel(MSBEndian,value,pixels);
1790         }
1791       if (image->alpha_trait == BlendPixelTrait)
1792         {
1793           value=ScaleQuantumToLong(ClampToQuantum(pixel->alpha));
1794           pixels=PopLongPixel(MSBEndian,value,pixels);
1795         }
1796       break;
1797     }
1798     case 16:
1799     {
1800       unsigned short
1801         value;
1802
1803       value=ScaleQuantumToShort(ClampToQuantum(pixel->red));
1804       pixels=PopShortPixel(MSBEndian,value,pixels);
1805       if (IsGrayColorspace(image->colorspace) == MagickFalse)
1806         {
1807           value=ScaleQuantumToShort(ClampToQuantum(pixel->green));
1808           pixels=PopShortPixel(MSBEndian,value,pixels);
1809           value=ScaleQuantumToShort(ClampToQuantum(pixel->blue));
1810           pixels=PopShortPixel(MSBEndian,value,pixels);
1811         }
1812       if (image->colorspace == CMYKColorspace)
1813         {
1814           value=ScaleQuantumToShort(ClampToQuantum(pixel->black));
1815           pixels=PopShortPixel(MSBEndian,value,pixels);
1816         }
1817       if (image->alpha_trait == BlendPixelTrait)
1818         {
1819           value=ScaleQuantumToShort(ClampToQuantum(pixel->alpha));
1820           pixels=PopShortPixel(MSBEndian,value,pixels);
1821         }
1822       break;
1823     }
1824     case 8:
1825     {
1826       unsigned char
1827         value;
1828
1829       value=(unsigned char) ScaleQuantumToChar(ClampToQuantum(pixel->red));
1830       pixels=PopCharPixel(value,pixels);
1831       if (IsGrayColorspace(image->colorspace) == MagickFalse)
1832         {
1833           value=(unsigned char) ScaleQuantumToChar(ClampToQuantum(
1834             pixel->green));
1835           pixels=PopCharPixel(value,pixels);
1836           value=(unsigned char) ScaleQuantumToChar(ClampToQuantum(pixel->blue));
1837           pixels=PopCharPixel(value,pixels);
1838         }
1839       if (image->colorspace == CMYKColorspace)
1840         {
1841           value=(unsigned char) ScaleQuantumToChar(ClampToQuantum(
1842             pixel->black));
1843           pixels=PopCharPixel(value,pixels);
1844         }
1845       if (image->alpha_trait == BlendPixelTrait)
1846         {
1847           value=(unsigned char) ScaleQuantumToChar(ClampToQuantum(
1848             pixel->alpha));
1849           pixels=PopCharPixel(value,pixels);
1850         }
1851       break;
1852     }
1853     default:
1854       (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
1855         "ImageDepthNotSupported","`%s'",image->filename);
1856   }
1857   *pixels++=(unsigned char) length;
1858   return(pixels);
1859 }
1860
1861 static MagickBooleanType WriteMIFFImage(const ImageInfo *image_info,
1862   Image *image,ExceptionInfo *exception)
1863 {
1864 #if defined(MAGICKCORE_BZLIB_DELEGATE)
1865   bz_stream
1866     bzip_info;
1867 #endif
1868
1869   char
1870     buffer[MaxTextExtent];
1871
1872   CompressionType
1873     compression;
1874
1875   const char
1876     *property,
1877     *value;
1878
1879 #if defined(MAGICKCORE_LZMA_DELEGATE)
1880   lzma_allocator
1881     allocator;
1882
1883   lzma_stream
1884     initialize_lzma = LZMA_STREAM_INIT,
1885     lzma_info;
1886 #endif
1887
1888   MagickBooleanType
1889     status;
1890
1891   MagickOffsetType
1892     scene;
1893
1894   PixelInfo
1895     pixel,
1896     target;
1897
1898   QuantumInfo
1899     *quantum_info;
1900
1901   QuantumType
1902     quantum_type;
1903
1904   register ssize_t
1905     i;
1906
1907   size_t
1908     length,
1909     packet_size;
1910
1911   ssize_t
1912     y;
1913
1914   unsigned char
1915     *compress_pixels,
1916     *pixels,
1917     *q;
1918
1919 #if defined(MAGICKCORE_ZLIB_DELEGATE)
1920   z_stream
1921     zip_info;
1922 #endif
1923
1924   /*
1925     Open output image file.
1926   */
1927   assert(image_info != (const ImageInfo *) NULL);
1928   assert(image_info->signature == MagickSignature);
1929   assert(image != (Image *) NULL);
1930   assert(image->signature == MagickSignature);
1931   if (image->debug != MagickFalse)
1932     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1933   assert(exception != (ExceptionInfo *) NULL);
1934   assert(exception->signature == MagickSignature);
1935   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1936   if (status == MagickFalse)
1937     return(status);
1938   scene=0;
1939   do
1940   {
1941     /*
1942       Allocate image pixels.
1943     */
1944     image->depth=image->depth <= 8 ? 8UL : image->depth <= 16 ? 16UL :
1945       image->depth <= 32 ? 32UL : 64UL;
1946     quantum_info=AcquireQuantumInfo(image_info,image);
1947     if (quantum_info == (QuantumInfo *) NULL)
1948       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1949     if ((image->storage_class != PseudoClass) && (image->depth >= 32) &&
1950         (quantum_info->format == UndefinedQuantumFormat) &&
1951         (IsHighDynamicRangeImage(image,exception) != MagickFalse))
1952       {
1953         status=SetQuantumFormat(image,quantum_info,FloatingPointQuantumFormat);
1954         if (status == MagickFalse)
1955           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1956       }
1957     if ((image->storage_class == PseudoClass) &&
1958         (image->colors > (size_t) (GetQuantumRange(image->depth)+1)))
1959       (void) SetImageStorageClass(image,DirectClass,exception);
1960     if (IsImageGray(image,exception) != MagickFalse)
1961       (void) SetImageColorspace(image,GRAYColorspace,exception);
1962     compression=image->compression;
1963     if (image_info->compression != UndefinedCompression)
1964       compression=image_info->compression;
1965     switch (compression)
1966     {
1967 #if !defined(MAGICKCORE_ZLIB_DELEGATE)
1968       case LZMACompression: compression=NoCompression; break;
1969 #endif
1970 #if !defined(MAGICKCORE_ZLIB_DELEGATE)
1971       case LZWCompression:
1972       case ZipCompression: compression=NoCompression; break;
1973 #endif
1974 #if !defined(MAGICKCORE_BZLIB_DELEGATE)
1975       case BZipCompression: compression=NoCompression; break;
1976 #endif
1977       case RLECompression:
1978       {
1979         if (quantum_info->format == FloatingPointQuantumFormat)
1980           compression=NoCompression;
1981         GetPixelInfo(image,&target);
1982         break;
1983       }
1984       default:
1985         break;
1986     }
1987     packet_size=(size_t) (quantum_info->depth/8);
1988     if (image->storage_class == DirectClass)
1989       packet_size=(size_t) (3*quantum_info->depth/8);
1990     if (IsGrayColorspace(image->colorspace) != MagickFalse)
1991       packet_size=(size_t) (quantum_info->depth/8);
1992     if (image->alpha_trait == BlendPixelTrait)
1993       packet_size+=quantum_info->depth/8;
1994     if (image->colorspace == CMYKColorspace)
1995       packet_size+=quantum_info->depth/8;
1996     if (compression == RLECompression)
1997       packet_size++;
1998     length=image->columns;
1999     length=MagickMax(BZipMaxExtent(packet_size*image->columns),ZipMaxExtent(
2000       packet_size*image->columns));
2001     if ((compression == BZipCompression) || (compression == ZipCompression))
2002       if (length != (size_t) ((unsigned int) length))
2003         compression=NoCompression;
2004     compress_pixels=(unsigned char *) AcquireQuantumMemory(length,
2005       sizeof(*compress_pixels));
2006     if (compress_pixels == (unsigned char *) NULL)
2007       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2008     /*
2009       Write MIFF header.
2010     */
2011     (void) WriteBlobString(image,"id=ImageMagick  version=1.0\n");
2012     (void) FormatLocaleString(buffer,MaxTextExtent,
2013       "class=%s  colors=%.20g  alpha-trait=%s\n",CommandOptionToMnemonic(
2014       MagickClassOptions,image->storage_class),(double) image->colors,
2015       CommandOptionToMnemonic(MagickPixelTraitOptions,(ssize_t)
2016       image->alpha_trait));
2017     (void) WriteBlobString(image,buffer);
2018     (void) FormatLocaleString(buffer,MaxTextExtent,"columns=%.20g  rows=%.20g  "
2019       "depth=%.20g\n",(double) image->columns,(double) image->rows,(double)
2020       image->depth);
2021     (void) WriteBlobString(image,buffer);
2022     if (image->type != UndefinedType)
2023       {
2024         (void) FormatLocaleString(buffer,MaxTextExtent,"type=%s\n",
2025           CommandOptionToMnemonic(MagickTypeOptions,image->type));
2026         (void) WriteBlobString(image,buffer);
2027       }
2028     if (image->colorspace != UndefinedColorspace)
2029       {
2030         (void) FormatLocaleString(buffer,MaxTextExtent,"colorspace=%s\n",
2031           CommandOptionToMnemonic(MagickColorspaceOptions,image->colorspace));
2032         (void) WriteBlobString(image,buffer);
2033       }
2034     if (compression != UndefinedCompression)
2035       {
2036         (void) FormatLocaleString(buffer,MaxTextExtent,"compression=%s  "
2037           "quality=%.20g\n",CommandOptionToMnemonic(MagickCompressOptions,
2038           compression),(double) image->quality);
2039         (void) WriteBlobString(image,buffer);
2040       }
2041     if (image->units != UndefinedResolution)
2042       {
2043         (void) FormatLocaleString(buffer,MaxTextExtent,"units=%s\n",
2044           CommandOptionToMnemonic(MagickResolutionOptions,image->units));
2045         (void) WriteBlobString(image,buffer);
2046       }
2047     if ((image->resolution.x != 0) || (image->resolution.y != 0))
2048       {
2049         (void) FormatLocaleString(buffer,MaxTextExtent,
2050           "resolution=%gx%g\n",image->resolution.x,image->resolution.y);
2051         (void) WriteBlobString(image,buffer);
2052       }
2053     if ((image->page.width != 0) || (image->page.height != 0))
2054       {
2055         (void) FormatLocaleString(buffer,MaxTextExtent,
2056           "page=%.20gx%.20g%+.20g%+.20g\n",(double) image->page.width,(double)
2057           image->page.height,(double) image->page.x,(double) image->page.y);
2058         (void) WriteBlobString(image,buffer);
2059       }
2060     else
2061       if ((image->page.x != 0) || (image->page.y != 0))
2062         {
2063           (void) FormatLocaleString(buffer,MaxTextExtent,"page=%+ld%+ld\n",
2064             (long) image->page.x,(long) image->page.y);
2065           (void) WriteBlobString(image,buffer);
2066         }
2067     if ((image->tile_offset.x != 0) || (image->tile_offset.y != 0))
2068       {
2069         (void) FormatLocaleString(buffer,MaxTextExtent,"tile-offset=%+ld%+ld\n",
2070           (long) image->tile_offset.x,(long) image->tile_offset.y);
2071         (void) WriteBlobString(image,buffer);
2072       }
2073     if ((GetNextImageInList(image) != (Image *) NULL) ||
2074         (GetPreviousImageInList(image) != (Image *) NULL))
2075       {
2076         if (image->scene == 0)
2077           (void) FormatLocaleString(buffer,MaxTextExtent,"iterations=%.20g  "
2078             "delay=%.20g  ticks-per-second=%.20g\n",(double) image->iterations,
2079             (double) image->delay,(double) image->ticks_per_second);
2080         else
2081           (void) FormatLocaleString(buffer,MaxTextExtent,"scene=%.20g  "
2082             "iterations=%.20g  delay=%.20g  ticks-per-second=%.20g\n",(double)
2083             image->scene,(double) image->iterations,(double) image->delay,
2084             (double) image->ticks_per_second);
2085         (void) WriteBlobString(image,buffer);
2086       }
2087     else
2088       {
2089         if (image->scene != 0)
2090           {
2091             (void) FormatLocaleString(buffer,MaxTextExtent,"scene=%.20g\n",
2092               (double) image->scene);
2093             (void) WriteBlobString(image,buffer);
2094           }
2095         if (image->iterations != 0)
2096           {
2097             (void) FormatLocaleString(buffer,MaxTextExtent,"iterations=%.20g\n",
2098               (double) image->iterations);
2099             (void) WriteBlobString(image,buffer);
2100           }
2101         if (image->delay != 0)
2102           {
2103             (void) FormatLocaleString(buffer,MaxTextExtent,"delay=%.20g\n",
2104               (double) image->delay);
2105             (void) WriteBlobString(image,buffer);
2106           }
2107         if (image->ticks_per_second != UndefinedTicksPerSecond)
2108           {
2109             (void) FormatLocaleString(buffer,MaxTextExtent,
2110               "ticks-per-second=%.20g\n",(double) image->ticks_per_second);
2111             (void) WriteBlobString(image,buffer);
2112           }
2113       }
2114     if (image->gravity != UndefinedGravity)
2115       {
2116         (void) FormatLocaleString(buffer,MaxTextExtent,"gravity=%s\n",
2117           CommandOptionToMnemonic(MagickGravityOptions,image->gravity));
2118         (void) WriteBlobString(image,buffer);
2119       }
2120     if (image->dispose != UndefinedDispose)
2121       {
2122         (void) FormatLocaleString(buffer,MaxTextExtent,"dispose=%s\n",
2123           CommandOptionToMnemonic(MagickDisposeOptions,image->dispose));
2124         (void) WriteBlobString(image,buffer);
2125       }
2126     if (image->rendering_intent != UndefinedIntent)
2127       {
2128         (void) FormatLocaleString(buffer,MaxTextExtent,"rendering-intent=%s\n",
2129           CommandOptionToMnemonic(MagickIntentOptions,image->rendering_intent));
2130         (void) WriteBlobString(image,buffer);
2131       }
2132     if (image->gamma != 0.0)
2133       {
2134         (void) FormatLocaleString(buffer,MaxTextExtent,"gamma=%g\n",
2135           image->gamma);
2136         (void) WriteBlobString(image,buffer);
2137       }
2138     if (image->chromaticity.white_point.x != 0.0)
2139       {
2140         /*
2141           Note chomaticity points.
2142         */
2143         (void) FormatLocaleString(buffer,MaxTextExtent,"red-primary=%g,"
2144           "%g  green-primary=%g,%g  blue-primary=%g,%g\n",
2145           image->chromaticity.red_primary.x,image->chromaticity.red_primary.y,
2146           image->chromaticity.green_primary.x,
2147           image->chromaticity.green_primary.y,
2148           image->chromaticity.blue_primary.x,
2149           image->chromaticity.blue_primary.y);
2150         (void) WriteBlobString(image,buffer);
2151         (void) FormatLocaleString(buffer,MaxTextExtent,
2152           "white-point=%g,%g\n",image->chromaticity.white_point.x,
2153           image->chromaticity.white_point.y);
2154         (void) WriteBlobString(image,buffer);
2155       }
2156     if (image->orientation != UndefinedOrientation)
2157       {
2158         (void) FormatLocaleString(buffer,MaxTextExtent,"orientation=%s\n",
2159           CommandOptionToMnemonic(MagickOrientationOptions,image->orientation));
2160         (void) WriteBlobString(image,buffer);
2161       }
2162     if (image->profiles != (void *) NULL)
2163       {
2164         const char
2165           *name;
2166
2167         const StringInfo
2168           *profile;
2169
2170         /*
2171           Write image profiles.
2172         */
2173         ResetImageProfileIterator(image);
2174         name=GetNextImageProfile(image);
2175         while (name != (const char *) NULL)
2176         {
2177           profile=GetImageProfile(image,name);
2178           if (profile != (StringInfo *) NULL)
2179             {
2180               (void) FormatLocaleString(buffer,MaxTextExtent,
2181                 "profile:%s=%.20g\n",name,(double)
2182                 GetStringInfoLength(profile));
2183               (void) WriteBlobString(image,buffer);
2184             }
2185           name=GetNextImageProfile(image);
2186         }
2187       }
2188     if (image->montage != (char *) NULL)
2189       {
2190         (void) FormatLocaleString(buffer,MaxTextExtent,"montage=%s\n",
2191           image->montage);
2192         (void) WriteBlobString(image,buffer);
2193       }
2194     if (quantum_info->format == FloatingPointQuantumFormat)
2195       (void) SetImageProperty(image,"quantum:format","floating-point",
2196         exception);
2197     ResetImagePropertyIterator(image);
2198     property=GetNextImageProperty(image);
2199     while (property != (const char *) NULL)
2200     {
2201       (void) FormatLocaleString(buffer,MaxTextExtent,"%s=",property);
2202       (void) WriteBlobString(image,buffer);
2203       value=GetImageProperty(image,property,exception);
2204       if (value != (const char *) NULL)
2205         {
2206           size_t
2207             length;
2208
2209           length=strlen(value);
2210           for (i=0; i < (ssize_t) length; i++)
2211             if (isspace((int) ((unsigned char) value[i])) != 0)
2212               break;
2213           if (i == (ssize_t) length)
2214             (void) WriteBlob(image,length,(const unsigned char *) value);
2215           else
2216             {
2217               (void) WriteBlobByte(image,'{');
2218               if (strchr(value,'}') == (char *) NULL)
2219                 (void) WriteBlob(image,length,(const unsigned char *) value);
2220               else
2221                 for (i=0; i < (ssize_t) length; i++)
2222                 {
2223                   if (value[i] == (int) '}')
2224                     (void) WriteBlobByte(image,'\\');
2225                   (void) WriteBlobByte(image,value[i]);
2226                 }
2227               (void) WriteBlobByte(image,'}');
2228             }
2229         }
2230       (void) WriteBlobByte(image,'\n');
2231       property=GetNextImageProperty(image);
2232     }
2233     (void) WriteBlobString(image,"\f\n:\032");
2234     if (image->montage != (char *) NULL)
2235       {
2236         /*
2237           Write montage tile directory.
2238         */
2239         if (image->directory != (char *) NULL)
2240           (void) WriteBlob(image,strlen(image->directory),(unsigned char *)
2241             image->directory);
2242         (void) WriteBlobByte(image,'\0');
2243       }
2244     if (image->profiles != (void *) NULL)
2245       {
2246         const char
2247           *name;
2248
2249         const StringInfo
2250           *profile;
2251
2252         /*
2253           Generic profile.
2254         */
2255         ResetImageProfileIterator(image);
2256         name=GetNextImageProfile(image);
2257         while (name != (const char *) NULL)
2258         {
2259           profile=GetImageProfile(image,name);
2260           (void) WriteBlob(image,GetStringInfoLength(profile),
2261             GetStringInfoDatum(profile));
2262           name=GetNextImageProfile(image);
2263         }
2264       }
2265     if (image->storage_class == PseudoClass)
2266       {
2267         size_t
2268           packet_size;
2269
2270         unsigned char
2271           *colormap,
2272           *q;
2273
2274         /*
2275           Allocate colormap.
2276         */
2277         packet_size=(size_t) (3*quantum_info->depth/8);
2278         colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
2279           packet_size*sizeof(*colormap));
2280         if (colormap == (unsigned char *) NULL)
2281           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2282         /*
2283           Write colormap to file.
2284         */
2285         q=colormap;
2286         for (i=0; i < (ssize_t) image->colors; i++)
2287         {
2288           switch (quantum_info->depth)
2289           {
2290             default:
2291               ThrowWriterException(CorruptImageError,"ImageDepthNotSupported");
2292             case 32:
2293             {
2294               register unsigned int
2295                 pixel;
2296
2297               pixel=ScaleQuantumToLong(image->colormap[i].red);
2298               q=PopLongPixel(MSBEndian,pixel,q);
2299               pixel=ScaleQuantumToLong(image->colormap[i].green);
2300               q=PopLongPixel(MSBEndian,pixel,q);
2301               pixel=ScaleQuantumToLong(image->colormap[i].blue);
2302               q=PopLongPixel(MSBEndian,pixel,q);
2303               break;
2304             }
2305             case 16:
2306             {
2307               register unsigned short
2308                 pixel;
2309
2310               pixel=ScaleQuantumToShort(image->colormap[i].red);
2311               q=PopShortPixel(MSBEndian,pixel,q);
2312               pixel=ScaleQuantumToShort(image->colormap[i].green);
2313               q=PopShortPixel(MSBEndian,pixel,q);
2314               pixel=ScaleQuantumToShort(image->colormap[i].blue);
2315               q=PopShortPixel(MSBEndian,pixel,q);
2316               break;
2317             }
2318             case 8:
2319             {
2320               register unsigned char
2321                 pixel;
2322
2323               pixel=(unsigned char) ScaleQuantumToChar(image->colormap[i].red);
2324               q=PopCharPixel(pixel,q);
2325               pixel=(unsigned char) ScaleQuantumToChar(
2326                 image->colormap[i].green);
2327               q=PopCharPixel(pixel,q);
2328               pixel=(unsigned char) ScaleQuantumToChar(image->colormap[i].blue);
2329               q=PopCharPixel(pixel,q);
2330               break;
2331             }
2332           }
2333         }
2334         (void) WriteBlob(image,packet_size*image->colors,colormap);
2335         colormap=(unsigned char *) RelinquishMagickMemory(colormap);
2336       }
2337     /*
2338       Write image pixels to file.
2339     */
2340     status=MagickTrue;
2341     switch (compression)
2342     {
2343 #if defined(MAGICKCORE_BZLIB_DELEGATE)
2344       case BZipCompression:
2345       {
2346         int
2347           code;
2348
2349         (void) ResetMagickMemory(&bzip_info,0,sizeof(bzip_info));
2350         bzip_info.bzalloc=AcquireBZIPMemory;
2351         bzip_info.bzfree=RelinquishBZIPMemory;
2352         code=BZ2_bzCompressInit(&bzip_info,(int) (image->quality ==
2353           UndefinedCompressionQuality ? 7 : MagickMin(image->quality/10,
2354           9)),(int) image_info->verbose,0);
2355         if (code != BZ_OK)
2356           status=MagickFalse;
2357         break;
2358       }
2359 #endif
2360 #if defined(MAGICKCORE_LZMA_DELEGATE)
2361       case LZMACompression:
2362       {
2363         int
2364           code;
2365
2366         (void) ResetMagickMemory(&allocator,0,sizeof(allocator));
2367         allocator.alloc=AcquireLZMAMemory;
2368         allocator.free=RelinquishLZMAMemory;
2369         lzma_info=initialize_lzma;
2370         lzma_info.allocator=&allocator;
2371         code=lzma_easy_encoder(&lzma_info,image->quality/10,LZMA_CHECK_SHA256);
2372         if (code != LZMA_OK)
2373           status=MagickTrue;
2374         break;
2375       }
2376 #endif
2377 #if defined(MAGICKCORE_ZLIB_DELEGATE)
2378       case LZWCompression:
2379       case ZipCompression:
2380       {
2381         int
2382           code;
2383
2384         (void) ResetMagickMemory(&zip_info,0,sizeof(zip_info));
2385         zip_info.zalloc=AcquireZIPMemory;
2386         zip_info.zfree=RelinquishZIPMemory;
2387         code=deflateInit(&zip_info,(int) (image->quality ==
2388           UndefinedCompressionQuality ? 7 : MagickMin(image->quality/10,9)));
2389         if (code != Z_OK)
2390           status=MagickFalse;
2391         break;
2392       }
2393 #endif
2394       default:
2395         break;
2396     }
2397     quantum_type=GetQuantumType(image,exception);
2398     pixels=GetQuantumPixels(quantum_info);
2399     for (y=0; y < (ssize_t) image->rows; y++)
2400     {
2401       register const Quantum
2402         *restrict p;
2403
2404       register ssize_t
2405         x;
2406
2407       if (status == MagickFalse)
2408         break;
2409       p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2410       if (p == (const Quantum *) NULL)
2411         break;
2412       q=pixels;
2413       switch (compression)
2414       {
2415 #if defined(MAGICKCORE_BZLIB_DELEGATE)
2416         case BZipCompression:
2417         {
2418           bzip_info.next_in=(char *) pixels;
2419           bzip_info.avail_in=(unsigned int) (packet_size*image->columns);
2420           (void) ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2421             quantum_type,pixels,exception);
2422           do
2423           {
2424             int
2425               code;
2426
2427             bzip_info.next_out=(char *) compress_pixels;
2428             bzip_info.avail_out=(unsigned int) BZipMaxExtent(packet_size*
2429               image->columns);
2430             code=BZ2_bzCompress(&bzip_info,BZ_FLUSH);
2431             if (code != BZ_OK)
2432               status=MagickFalse;
2433             length=(size_t) (bzip_info.next_out-(char *) compress_pixels);
2434             if (length != 0)
2435               {
2436                 (void) WriteBlobMSBLong(image,(unsigned int) length);
2437                 (void) WriteBlob(image,length,compress_pixels);
2438               }
2439           } while (bzip_info.avail_in != 0);
2440           break;
2441         }
2442 #endif
2443 #if defined(MAGICKCORE_LZMA_DELEGATE)
2444         case LZMACompression:
2445         {
2446           lzma_info.next_in=pixels;
2447           lzma_info.avail_in=packet_size*image->columns;
2448           (void) ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2449             quantum_type,pixels,exception);
2450           do
2451           {
2452             int
2453               code;
2454
2455             lzma_info.next_out=compress_pixels;
2456             lzma_info.avail_out=packet_size*image->columns;
2457             code=lzma_code(&lzma_info,LZMA_RUN);
2458             if (code != LZMA_OK)
2459               status=MagickFalse;
2460             length=(size_t) (lzma_info.next_out-compress_pixels);
2461             if (length != 0)
2462               {
2463                 (void) WriteBlobMSBLong(image,(unsigned int) length);
2464                 (void) WriteBlob(image,length,compress_pixels);
2465               }
2466           } while (lzma_info.avail_in != 0);
2467           break;
2468         }
2469 #endif
2470 #if defined(MAGICKCORE_ZLIB_DELEGATE)
2471         case LZWCompression:
2472         case ZipCompression:
2473         {
2474           zip_info.next_in=pixels;
2475           zip_info.avail_in=(uInt) (packet_size*image->columns);
2476           (void) ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2477             quantum_type,pixels,exception);
2478           do
2479           {
2480             int
2481               code;
2482
2483             zip_info.next_out=compress_pixels;
2484             zip_info.avail_out=(uInt) ZipMaxExtent(packet_size*image->columns);
2485             code=deflate(&zip_info,Z_SYNC_FLUSH);
2486             if (code != Z_OK)
2487               status=MagickFalse;
2488             length=(size_t) (zip_info.next_out-compress_pixels);
2489             if (length != 0)
2490               {
2491                 (void) WriteBlobMSBLong(image,(unsigned int) length);
2492                 (void) WriteBlob(image,length,compress_pixels);
2493               }
2494           } while (zip_info.avail_in != 0);
2495           break;
2496         }
2497 #endif
2498         case RLECompression:
2499         {
2500           length=0;
2501           GetPixelInfoPixel(image,p,&pixel);
2502           p+=GetPixelChannels(image);
2503           for (x=1; x < (ssize_t) image->columns; x++)
2504           {
2505             GetPixelInfoPixel(image,p,&target);
2506             if ((length < 255) &&
2507                 (IsPixelInfoEquivalent(&pixel,&target) != MagickFalse))
2508               length++;
2509             else
2510               {
2511                 q=PopRunlengthPacket(image,q,length,&pixel,exception);
2512                 length=0;
2513               }
2514             GetPixelInfoPixel(image,p,&pixel);
2515             p+=GetPixelChannels(image);
2516           }
2517           q=PopRunlengthPacket(image,q,length,&pixel,exception);
2518           (void) WriteBlob(image,(size_t) (q-pixels),pixels);
2519           break;
2520         }
2521         default:
2522         {
2523           (void) ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2524             quantum_type,pixels,exception);
2525           (void) WriteBlob(image,packet_size*image->columns,pixels);
2526           break;
2527         }
2528       }
2529       if (image->previous == (Image *) NULL)
2530         {
2531           status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2532             image->rows);
2533           if (status == MagickFalse)
2534             break;
2535         }
2536     }
2537     switch (compression)
2538     {
2539 #if defined(MAGICKCORE_BZLIB_DELEGATE)
2540       case BZipCompression:
2541       {
2542         int
2543           code;
2544
2545         for ( ; ; )
2546         {
2547           if (status == MagickFalse)
2548             break;
2549           bzip_info.next_out=(char *) compress_pixels;
2550           bzip_info.avail_out=(unsigned int) BZipMaxExtent(packet_size*
2551             image->columns);
2552           code=BZ2_bzCompress(&bzip_info,BZ_FINISH);
2553           length=(size_t) (bzip_info.next_out-(char *) compress_pixels);
2554           if (length != 0)
2555             {
2556               (void) WriteBlobMSBLong(image,(unsigned int) length);
2557               (void) WriteBlob(image,length,compress_pixels);
2558             }
2559           if (code == BZ_STREAM_END)
2560             break;
2561         }
2562         code=BZ2_bzCompressEnd(&bzip_info);
2563         if (code != BZ_OK)
2564           status=MagickFalse;
2565         break;
2566       }
2567 #endif
2568 #if defined(MAGICKCORE_LZMA_DELEGATE)
2569       case LZMACompression:
2570       {
2571         int
2572           code;
2573
2574         for ( ; ; )
2575         {
2576           if (status == MagickFalse)
2577             break;
2578           lzma_info.next_out=compress_pixels;
2579           lzma_info.avail_out=packet_size*image->columns;
2580           code=lzma_code(&lzma_info,LZMA_FINISH);
2581           length=(size_t) (lzma_info.next_out-compress_pixels);
2582           if (length > 6)
2583             {
2584               (void) WriteBlobMSBLong(image,(unsigned int) length);
2585               (void) WriteBlob(image,length,compress_pixels);
2586             }
2587           if (code == LZMA_STREAM_END)
2588             break;
2589         }
2590         lzma_end(&lzma_info);
2591         break;
2592       }
2593 #endif
2594 #if defined(MAGICKCORE_ZLIB_DELEGATE)
2595       case LZWCompression:
2596       case ZipCompression:
2597       {
2598         int
2599           code;
2600
2601         for ( ; ; )
2602         {
2603           if (status == MagickFalse)
2604             break;
2605           zip_info.next_out=compress_pixels;
2606           zip_info.avail_out=(uInt) ZipMaxExtent(packet_size*image->columns);
2607           code=deflate(&zip_info,Z_FINISH);
2608           length=(size_t) (zip_info.next_out-compress_pixels);
2609           if (length > 6)
2610             {
2611               (void) WriteBlobMSBLong(image,(unsigned int) length);
2612               (void) WriteBlob(image,length,compress_pixels);
2613             }
2614           if (code == Z_STREAM_END)
2615             break;
2616         }
2617         code=deflateEnd(&zip_info);
2618         if (code != Z_OK)
2619           status=MagickFalse;
2620         break;
2621       }
2622 #endif
2623       default:
2624         break;
2625     }
2626     quantum_info=DestroyQuantumInfo(quantum_info);
2627     compress_pixels=(unsigned char *) RelinquishMagickMemory(compress_pixels);
2628     if (GetNextImageInList(image) == (Image *) NULL)
2629       break;
2630     image=SyncNextImageInList(image);
2631     status=SetImageProgress(image,SaveImagesTag,scene++,
2632       GetImageListLength(image));
2633     if (status == MagickFalse)
2634       break;
2635   } while (image_info->adjoin != MagickFalse);
2636   (void) CloseBlob(image);
2637   return(status);
2638 }