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