source: ImageMagick/branches/ImageMagick-6/coders/miff.c @ 7891

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