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