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