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