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