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