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