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