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