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