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