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