]> granicus.if.org Git - imagemagick/blob - coders/miff.c
f2626864df51f4784ee6b0d0192306084c7ee56d
[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->type == BilevelType) || (image->type == GrayscaleType) ||
1213         (image->type == GrayscaleMatteType))
1214       packet_size=quantum_info->depth/8;
1215     if (image->matte != MagickFalse)
1216       packet_size+=quantum_info->depth/8;
1217     if (image->colorspace == CMYKColorspace)
1218       packet_size+=quantum_info->depth/8;
1219     if (image->compression == RLECompression)
1220       packet_size++;
1221     length=image->columns;
1222     length=MagickMax(MagickMax(BZipMaxExtent(packet_size*image->columns),
1223       LZMAMaxExtent(packet_size*image->columns)),ZipMaxExtent(packet_size*
1224       image->columns));
1225     compress_pixels=(unsigned char *) AcquireQuantumMemory(length,
1226       sizeof(*compress_pixels));
1227     if (compress_pixels == (unsigned char *) NULL)
1228       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1229     /*
1230       Read image pixels.
1231     */
1232     quantum_type=RGBQuantum;
1233     if (image->matte != MagickFalse)
1234       quantum_type=RGBAQuantum;
1235     if (image->colorspace == CMYKColorspace)
1236       {
1237         quantum_type=CMYKQuantum;
1238         if (image->matte != MagickFalse)
1239           quantum_type=CMYKAQuantum;
1240       }
1241     if (image->storage_class == PseudoClass)
1242       {
1243         quantum_type=IndexQuantum;
1244         if (image->matte != MagickFalse)
1245           quantum_type=IndexAlphaQuantum;
1246       }
1247     if ((image->type == BilevelType) || (image->type == GrayscaleType) ||
1248         (image->type == GrayscaleMatteType))
1249       {
1250         quantum_type=GrayQuantum;
1251         if (image->matte != MagickFalse)
1252           quantum_type=GrayAlphaQuantum;
1253       }
1254     status=MagickTrue;
1255     switch (image->compression)
1256     {
1257 #if defined(MAGICKCORE_BZLIB_DELEGATE)
1258       case BZipCompression:
1259       {
1260         (void) ResetMagickMemory(&bzip_info,0,sizeof(bzip_info));
1261         bzip_info.bzalloc=AcquireBZIPMemory;
1262         bzip_info.bzfree=RelinquishBZIPMemory;
1263         bzip_info.opaque=(void *) NULL;
1264         code=BZ2_bzDecompressInit(&bzip_info,(int) image_info->verbose,
1265           MagickFalse);
1266         if (code != BZ_OK)
1267           status=MagickFalse;
1268         break;
1269       }
1270 #endif
1271 #if defined(MAGICKCORE_LZMA_DELEGATE)
1272       case LZMACompression:
1273       {
1274         (void) ResetMagickMemory(&allocator,0,sizeof(allocator));
1275         allocator.alloc=AcquireLZMAMemory;
1276         allocator.free=RelinquishLZMAMemory;
1277         lzma_info=initialize_lzma;
1278         lzma_info.allocator=(&allocator);
1279         code=lzma_auto_decoder(&lzma_info,-1,0);
1280         if (code != LZMA_OK)
1281           status=MagickFalse;
1282         break;
1283       }
1284 #endif
1285 #if defined(MAGICKCORE_ZLIB_DELEGATE)
1286       case LZWCompression:
1287       case ZipCompression:
1288       {
1289         (void) ResetMagickMemory(&zip_info,0,sizeof(zip_info));
1290         zip_info.zalloc=AcquireZIPMemory;
1291         zip_info.zfree=RelinquishZIPMemory;
1292         zip_info.opaque=(voidpf) NULL;
1293         code=inflateInit(&zip_info);
1294         if (code != Z_OK)
1295           status=MagickFalse;
1296         break;
1297       }
1298 #endif
1299       case RLECompression:
1300       {
1301         GetPixelInfo(image,&pixel);
1302         break;
1303       }
1304       default:
1305         break;
1306     }
1307     pixels=GetQuantumPixels(quantum_info);
1308     length=0;
1309     for (y=0; y < (ssize_t) image->rows; y++)
1310     {
1311       register ssize_t
1312         x;
1313
1314       register Quantum
1315         *restrict q;
1316
1317       if (status == MagickFalse)
1318         break;
1319       q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1320       if (q == (Quantum *) NULL)
1321         break;
1322       switch (image->compression)
1323       {
1324 #if defined(MAGICKCORE_BZLIB_DELEGATE)
1325         case BZipCompression:
1326         {
1327           bzip_info.next_out=(char *) pixels;
1328           bzip_info.avail_out=(unsigned int) (packet_size*image->columns);
1329           do
1330           {
1331             if (bzip_info.avail_in == 0)
1332               {
1333                 bzip_info.next_in=(char *) compress_pixels;
1334                 length=(size_t) BZipMaxExtent(packet_size*image->columns);
1335                 if (version != 0)
1336                   length=(size_t) ReadBlobMSBLong(image);
1337                 bzip_info.avail_in=(unsigned int) ReadBlob(image,length,
1338                   (unsigned char *) bzip_info.next_in);
1339               }
1340             if (BZ2_bzDecompress(&bzip_info) == BZ_STREAM_END)
1341               break;
1342           } while (bzip_info.avail_out != 0);
1343           (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1344             quantum_type,pixels,exception);
1345           break;
1346         }
1347 #endif
1348 #if defined(MAGICKCORE_LZMA_DELEGATE)
1349         case LZMACompression:
1350         {
1351           lzma_info.next_out=pixels;
1352           lzma_info.avail_out=packet_size*image->columns;
1353           do
1354           {
1355             if (lzma_info.avail_in == 0)
1356               {
1357                 lzma_info.next_in=compress_pixels;
1358                 length=(size_t) ReadBlobMSBLong(image);
1359                 lzma_info.avail_in=(unsigned int) ReadBlob(image,length,
1360                   (unsigned char *) lzma_info.next_in);
1361               }
1362             code=lzma_code(&lzma_info,LZMA_RUN);
1363             if (code < 0)
1364               {
1365                 status=MagickFalse;
1366                 break;
1367               }
1368             if (code == LZMA_STREAM_END)
1369               break;
1370           } while (lzma_info.avail_out != 0);
1371           (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1372             quantum_type,pixels,exception);
1373           break;
1374         }
1375 #endif
1376 #if defined(MAGICKCORE_ZLIB_DELEGATE)
1377         case LZWCompression:
1378         case ZipCompression:
1379         {
1380           zip_info.next_out=pixels;
1381           zip_info.avail_out=(uInt) (packet_size*image->columns);
1382           do
1383           {
1384             if (zip_info.avail_in == 0)
1385               {
1386                 zip_info.next_in=compress_pixels;
1387                 length=(size_t) ZipMaxExtent(packet_size*image->columns);
1388                 if (version != 0)
1389                   length=(size_t) ReadBlobMSBLong(image);
1390                 zip_info.avail_in=(unsigned int) ReadBlob(image,length,
1391                   zip_info.next_in);
1392               }
1393             if (inflate(&zip_info,Z_SYNC_FLUSH) == Z_STREAM_END)
1394               break;
1395           } while (zip_info.avail_out != 0);
1396           (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1397             quantum_type,pixels,exception);
1398           break;
1399         }
1400 #endif
1401         case RLECompression:
1402         {
1403           for (x=0; x < (ssize_t) image->columns; x++)
1404           {
1405             if (length == 0)
1406               {
1407                 count=ReadBlob(image,packet_size,pixels);
1408                 PushRunlengthPacket(image,pixels,&length,&pixel);
1409               }
1410             length--;
1411             if (image->storage_class == PseudoClass)
1412               SetPixelIndex(image,ClampToQuantum(pixel.index),q);
1413             else
1414               {
1415                 SetPixelRed(image,ClampToQuantum(pixel.red),q);
1416                 SetPixelGreen(image,ClampToQuantum(pixel.green),q);
1417                 SetPixelBlue(image,ClampToQuantum(pixel.blue),q);
1418                 if (image->colorspace == CMYKColorspace)
1419                   SetPixelBlack(image,ClampToQuantum(pixel.black),q);
1420               }
1421             if (image->matte != MagickFalse)
1422               SetPixelAlpha(image,ClampToQuantum(pixel.alpha),q);
1423             q+=GetPixelChannels(image);
1424           }
1425           break;
1426         }
1427         default:
1428         {
1429           count=ReadBlob(image,packet_size*image->columns,pixels);
1430           (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1431             quantum_type,pixels,exception);
1432           break;
1433         }
1434       }
1435       if (SyncAuthenticPixels(image,exception) == MagickFalse)
1436         break;
1437     }
1438     SetQuantumImageType(image,quantum_type);
1439     switch (image->compression)
1440     {
1441 #if defined(MAGICKCORE_BZLIB_DELEGATE)
1442       case BZipCompression:
1443       {
1444         if (version == 0)
1445           {
1446             MagickOffsetType
1447               offset;
1448
1449             offset=SeekBlob(image,-((MagickOffsetType)
1450               bzip_info.avail_in),SEEK_CUR);
1451             if (offset < 0)
1452               ThrowReaderException(CorruptImageError,
1453                 "ImproperImageHeader");
1454           }
1455         code=BZ2_bzDecompressEnd(&bzip_info);
1456         if (code != BZ_OK)
1457           status=MagickFalse;
1458         break;
1459       }
1460 #endif
1461 #if defined(MAGICKCORE_LZMA_DELEGATE)
1462       case LZMACompression:
1463       {
1464         code=lzma_code(&lzma_info,LZMA_FINISH);
1465         if ((code != LZMA_STREAM_END) && (code != LZMA_OK))
1466           status=MagickFalse;
1467         lzma_end(&lzma_info);
1468         break;
1469       }
1470 #endif
1471 #if defined(MAGICKCORE_ZLIB_DELEGATE)
1472       case LZWCompression:
1473       case ZipCompression:
1474       {
1475         if (version == 0)
1476           {
1477             MagickOffsetType
1478               offset;
1479
1480             offset=SeekBlob(image,-((MagickOffsetType) zip_info.avail_in),
1481               SEEK_CUR);
1482             if (offset < 0)
1483               ThrowReaderException(CorruptImageError,
1484                 "ImproperImageHeader");
1485           }
1486         code=inflateEnd(&zip_info);
1487         if (code != LZMA_OK)
1488           status=MagickFalse;
1489         break;
1490       }
1491 #endif
1492       default:
1493         break;
1494     }
1495     quantum_info=DestroyQuantumInfo(quantum_info);
1496     compress_pixels=(unsigned char *) RelinquishMagickMemory(compress_pixels);
1497     if (((y != (ssize_t) image->rows)) || (status == MagickFalse))
1498       {
1499         image=DestroyImageList(image);
1500         return((Image *) NULL);
1501       }
1502     if (EOFBlob(image) != MagickFalse)
1503       {
1504         ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
1505           image->filename);
1506         break;
1507       }
1508     /*
1509       Proceed to next image.
1510     */
1511     if (image_info->number_scenes != 0)
1512       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1513         break;
1514     do
1515     {
1516       c=ReadBlobByte(image);
1517     } while ((isgraph(c) == MagickFalse) && (c != EOF));
1518     if (c != EOF)
1519       {
1520         /*
1521           Allocate next image structure.
1522         */
1523         AcquireNextImage(image_info,image);
1524         if (GetNextImageInList(image) == (Image *) NULL)
1525           {
1526             image=DestroyImageList(image);
1527             return((Image *) NULL);
1528           }
1529         image=SyncNextImageInList(image);
1530         status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
1531           GetBlobSize(image));
1532         if (status == MagickFalse)
1533           break;
1534       }
1535   } while (c != EOF);
1536   (void) CloseBlob(image);
1537   return(GetFirstImageInList(image));
1538 }
1539 \f
1540 /*
1541 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1542 %                                                                             %
1543 %                                                                             %
1544 %                                                                             %
1545 %   R e g i s t e r M I F F I m a g e                                         %
1546 %                                                                             %
1547 %                                                                             %
1548 %                                                                             %
1549 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1550 %
1551 %  RegisterMIFFImage() adds properties for the MIFF image format to the list of
1552 %  supported formats.  The properties include the image format tag, a method to
1553 %  read and/or write the format, whether the format supports the saving of more
1554 %  than one frame to the same file or blob, whether the format supports native
1555 %  in-memory I/O, and a brief description of the format.
1556 %
1557 %  The format of the RegisterMIFFImage method is:
1558 %
1559 %      size_t RegisterMIFFImage(void)
1560 %
1561 */
1562 ModuleExport size_t RegisterMIFFImage(void)
1563 {
1564   char
1565     version[MaxTextExtent];
1566
1567   MagickInfo
1568     *entry;
1569
1570   *version='\0';
1571 #if defined(MagickImageCoderSignatureText)
1572   (void) CopyMagickString(version,MagickLibVersionText,MaxTextExtent);
1573 #if defined(ZLIB_VERSION)
1574   (void) ConcatenateMagickString(version," with Zlib ",MaxTextExtent);
1575   (void) ConcatenateMagickString(version,ZLIB_VERSION,MaxTextExtent);
1576 #endif
1577 #if defined(MAGICKCORE_BZLIB_DELEGATE)
1578   (void) ConcatenateMagickString(version," and BZlib",MaxTextExtent);
1579 #endif
1580 #endif
1581   entry=SetMagickInfo("MIFF");
1582   entry->decoder=(DecodeImageHandler *) ReadMIFFImage;
1583   entry->encoder=(EncodeImageHandler *) WriteMIFFImage;
1584   entry->magick=(IsImageFormatHandler *) IsMIFF;
1585   entry->seekable_stream=MagickTrue;
1586   entry->description=ConstantString("Magick Image File Format");
1587   if (*version != '\0')
1588     entry->version=ConstantString(version);
1589   entry->module=ConstantString("MIFF");
1590   (void) RegisterMagickInfo(entry);
1591   return(MagickImageCoderSignature);
1592 }
1593 \f
1594 /*
1595 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1596 %                                                                             %
1597 %                                                                             %
1598 %                                                                             %
1599 %   U n r e g i s t e r M I F F I m a g e                                     %
1600 %                                                                             %
1601 %                                                                             %
1602 %                                                                             %
1603 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1604 %
1605 %  UnregisterMIFFImage() removes format registrations made by the MIFF module
1606 %  from the list of supported formats.
1607 %
1608 %  The format of the UnregisterMIFFImage method is:
1609 %
1610 %      UnregisterMIFFImage(void)
1611 %
1612 */
1613 ModuleExport void UnregisterMIFFImage(void)
1614 {
1615   (void) UnregisterMagickInfo("MIFF");
1616 }
1617 \f
1618 /*
1619 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1620 %                                                                             %
1621 %                                                                             %
1622 %                                                                             %
1623 %   W r i t e M I F F I m a g e                                               %
1624 %                                                                             %
1625 %                                                                             %
1626 %                                                                             %
1627 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1628 %
1629 %  WriteMIFFImage() writes a MIFF image to a file.
1630 %
1631 %  The format of the WriteMIFFImage method is:
1632 %
1633 %      MagickBooleanType WriteMIFFImage(const ImageInfo *image_info,
1634 %        Image *image,ExceptionInfo *exception)
1635 %
1636 %  Compression code contributed by Kyle Shorter.
1637 %
1638 %  A description of each parameter follows:
1639 %
1640 %    o image_info: the image info.
1641 %
1642 %    o image: the image.
1643 %
1644 %    o exception: return any errors or warnings in this structure.
1645 %
1646 */
1647
1648 static unsigned char *PopRunlengthPacket(Image *image,unsigned char *pixels,
1649   size_t length,PixelInfo *pixel)
1650 {
1651   if (image->storage_class != DirectClass)
1652     {
1653       switch (image->depth)
1654       {
1655         case 32:
1656         {
1657           *pixels++=(unsigned char) ((size_t) pixel->index >> 24);
1658           *pixels++=(unsigned char) ((size_t) pixel->index >> 16);
1659         }
1660         case 16:
1661           *pixels++=(unsigned char) ((size_t) pixel->index >> 8);
1662         case 8:
1663         {
1664           *pixels++=(unsigned char) pixel->index;
1665           break;
1666         }
1667         default:
1668           (void) ThrowMagickException(&image->exception,GetMagickModule(),
1669             CorruptImageError,"ImageDepthNotSupported","`%s'",image->filename);
1670       }
1671       switch (image->depth)
1672       {
1673         case 32:
1674         {
1675           unsigned int
1676             value;
1677
1678           if (image->matte != MagickFalse)
1679             {
1680               value=ScaleQuantumToLong(ClampToQuantum(pixel->alpha));
1681               pixels=PopLongPixel(MSBEndian,value,pixels);
1682             }
1683           break;
1684         }
1685         case 16:
1686         {
1687           unsigned short
1688             value;
1689
1690           if (image->matte != MagickFalse)
1691             {
1692               value=ScaleQuantumToShort(ClampToQuantum(pixel->alpha));
1693               pixels=PopShortPixel(MSBEndian,value,pixels);
1694             }
1695           break;
1696         }
1697         case 8:
1698         {
1699           unsigned char
1700             value;
1701
1702           if (image->matte != MagickFalse)
1703             {
1704               value=(unsigned char) ScaleQuantumToChar(ClampToQuantum(
1705                 pixel->alpha));
1706               pixels=PopCharPixel(value,pixels);
1707             }
1708           break;
1709         }
1710         default:
1711           (void) ThrowMagickException(&image->exception,GetMagickModule(),
1712             CorruptImageError,"ImageDepthNotSupported","`%s'",image->filename);
1713       }
1714       *pixels++=(unsigned char) length;
1715       return(pixels);
1716     }
1717   switch (image->depth)
1718   {
1719     case 32:
1720     {
1721       unsigned int
1722         value;
1723
1724       value=ScaleQuantumToLong(ClampToQuantum(pixel->red));
1725       pixels=PopLongPixel(MSBEndian,value,pixels);
1726       value=ScaleQuantumToLong(ClampToQuantum(pixel->green));
1727       pixels=PopLongPixel(MSBEndian,value,pixels);
1728       value=ScaleQuantumToLong(ClampToQuantum(pixel->blue));
1729       pixels=PopLongPixel(MSBEndian,value,pixels);
1730       if (image->colorspace == CMYKColorspace)
1731         {
1732           value=ScaleQuantumToLong(ClampToQuantum(pixel->black));
1733           pixels=PopLongPixel(MSBEndian,value,pixels);
1734         }
1735       if (image->matte != MagickFalse)
1736         {
1737           value=ScaleQuantumToLong(ClampToQuantum(pixel->alpha));
1738           pixels=PopLongPixel(MSBEndian,value,pixels);
1739         }
1740       break;
1741     }
1742     case 16:
1743     {
1744       unsigned short
1745         value;
1746
1747       value=ScaleQuantumToShort(ClampToQuantum(pixel->red));
1748       pixels=PopShortPixel(MSBEndian,value,pixels);
1749       value=ScaleQuantumToShort(ClampToQuantum(pixel->green));
1750       pixels=PopShortPixel(MSBEndian,value,pixels);
1751       value=ScaleQuantumToShort(ClampToQuantum(pixel->blue));
1752       pixels=PopShortPixel(MSBEndian,value,pixels);
1753       if (image->colorspace == CMYKColorspace)
1754         {
1755           value=ScaleQuantumToShort(ClampToQuantum(pixel->black));
1756           pixels=PopShortPixel(MSBEndian,value,pixels);
1757         }
1758       if (image->matte != MagickFalse)
1759         {
1760           value=ScaleQuantumToShort(ClampToQuantum(pixel->alpha));
1761           pixels=PopShortPixel(MSBEndian,value,pixels);
1762         }
1763       break;
1764     }
1765     case 8:
1766     {
1767       unsigned char
1768         value;
1769
1770       value=(unsigned char) ScaleQuantumToChar(ClampToQuantum(pixel->red));
1771       pixels=PopCharPixel(value,pixels);
1772       value=(unsigned char) ScaleQuantumToChar(ClampToQuantum(pixel->green));
1773       pixels=PopCharPixel(value,pixels);
1774       value=(unsigned char) ScaleQuantumToChar(ClampToQuantum(pixel->blue));
1775       pixels=PopCharPixel(value,pixels);
1776       if (image->colorspace == CMYKColorspace)
1777         {
1778           value=(unsigned char) ScaleQuantumToChar(ClampToQuantum(
1779             pixel->black));
1780           pixels=PopCharPixel(value,pixels);
1781         }
1782       if (image->matte != MagickFalse)
1783         {
1784           value=(unsigned char) ScaleQuantumToChar(ClampToQuantum(
1785             pixel->alpha));
1786           pixels=PopCharPixel(value,pixels);
1787         }
1788       break;
1789     }
1790     default:
1791       (void) ThrowMagickException(&image->exception,GetMagickModule(),
1792         CorruptImageError,"ImageDepthNotSupported","`%s'",image->filename);
1793   }
1794   *pixels++=(unsigned char) length;
1795   return(pixels);
1796 }
1797
1798 static MagickBooleanType WriteMIFFImage(const ImageInfo *image_info,
1799   Image *image,ExceptionInfo *exception)
1800 {
1801 #if defined(MAGICKCORE_BZLIB_DELEGATE)
1802   bz_stream
1803     bzip_info;
1804 #endif
1805
1806   char
1807     buffer[MaxTextExtent];
1808
1809   CompressionType
1810     compression;
1811
1812   const char
1813     *property,
1814     *value;
1815
1816   int
1817     code;
1818
1819 #if defined(MAGICKCORE_LZMA_DELEGATE)
1820   lzma_allocator
1821     allocator;
1822
1823   lzma_stream
1824     initialize_lzma = LZMA_STREAM_INIT,
1825     lzma_info;
1826 #endif
1827
1828   MagickBooleanType
1829     status;
1830
1831   MagickOffsetType
1832     scene;
1833
1834   PixelInfo
1835     pixel,
1836     target;
1837
1838   QuantumInfo
1839     *quantum_info;
1840
1841   QuantumType
1842     quantum_type;
1843
1844   register ssize_t
1845     i;
1846
1847   size_t
1848     length,
1849     packet_size;
1850
1851   ssize_t
1852     y;
1853
1854   unsigned char
1855     *compress_pixels,
1856     *pixels,
1857     *q;
1858
1859 #if defined(MAGICKCORE_ZLIB_DELEGATE)
1860   z_stream
1861     zip_info;
1862 #endif
1863
1864   /*
1865     Open output image file.
1866   */
1867   assert(image_info != (const ImageInfo *) NULL);
1868   assert(image_info->signature == MagickSignature);
1869   assert(image != (Image *) NULL);
1870   assert(image->signature == MagickSignature);
1871   if (image->debug != MagickFalse)
1872     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1873   assert(exception != (ExceptionInfo *) NULL);
1874   assert(exception->signature == MagickSignature);
1875   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1876   if (status == MagickFalse)
1877     return(status);
1878   code=0;
1879   scene=0;
1880   do
1881   {
1882     /*
1883       Allocate image pixels.
1884     */
1885     image->depth=image->depth <= 8 ? 8UL : image->depth <= 16 ? 16UL :
1886       image->depth <= 32 ? 32UL : 64UL;
1887     quantum_info=AcquireQuantumInfo(image_info,image);
1888     if (quantum_info == (QuantumInfo *) NULL)
1889       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1890     if ((image->storage_class != PseudoClass) && (image->depth >= 32) &&
1891         (quantum_info->format == UndefinedQuantumFormat) &&
1892         (IsHighDynamicRangeImage(image,exception) != MagickFalse))
1893       {
1894         status=SetQuantumFormat(image,quantum_info,FloatingPointQuantumFormat);
1895         if (status == MagickFalse)
1896           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1897       }
1898     if ((image->storage_class == PseudoClass) &&
1899         (image->colors > (size_t) (GetQuantumRange(image->depth)+1)))
1900       (void) SetImageStorageClass(image,DirectClass,exception);
1901     if (IsImageGray(image,exception) != MagickFalse)
1902       {
1903         (void) SetImageStorageClass(image,DirectClass,exception);
1904         (void) SetImageColorspace(image,GRAYColorspace,exception);
1905       }
1906     compression=image->compression;
1907     if (image_info->compression != UndefinedCompression)
1908       compression=image_info->compression;
1909     switch (compression)
1910     {
1911 #if !defined(MAGICKCORE_ZLIB_DELEGATE)
1912       case LZMACompression: compression=NoCompression; break;
1913 #endif
1914 #if !defined(MAGICKCORE_ZLIB_DELEGATE)
1915       case LZWCompression:
1916       case ZipCompression: compression=NoCompression; break;
1917 #endif
1918 #if !defined(MAGICKCORE_BZLIB_DELEGATE)
1919       case BZipCompression: compression=NoCompression; break;
1920 #endif
1921       case RLECompression:
1922       {
1923         if (quantum_info->format == FloatingPointQuantumFormat)
1924           compression=NoCompression;
1925         GetPixelInfo(image,&target);
1926         break;
1927       }
1928       default:
1929         break;
1930     }
1931     packet_size=(size_t) (quantum_info->depth/8);
1932     if (image->storage_class == DirectClass)
1933       packet_size=(size_t) (3*quantum_info->depth/8);
1934     if (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 }