]> granicus.if.org Git - imagemagick/blob - coders/mpc.c
(no commit message)
[imagemagick] / coders / mpc.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                            M   M  PPPP    CCCC                              %
7 %                            MM MM  P   P  C                                  %
8 %                            M M M  PPPP   C                                  %
9 %                            M   M  P      C                                  %
10 %                            M   M  P       CCCC                              %
11 %                                                                             %
12 %                                                                             %
13 %              Read/Write Magick Persistant Cache Image Format                %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                   Cristy                                    %
17 %                                 March 2000                                  %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2014 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 \f
40 /*
41   Include declarations.
42 */
43 #include "MagickCore/studio.h"
44 #include "MagickCore/artifact.h"
45 #include "MagickCore/attribute.h"
46 #include "MagickCore/blob.h"
47 #include "MagickCore/blob-private.h"
48 #include "MagickCore/cache.h"
49 #include "MagickCore/color.h"
50 #include "MagickCore/color-private.h"
51 #include "MagickCore/colormap.h"
52 #include "MagickCore/constitute.h"
53 #include "MagickCore/exception.h"
54 #include "MagickCore/exception-private.h"
55 #include "MagickCore/geometry.h"
56 #include "MagickCore/hashmap.h"
57 #include "MagickCore/image.h"
58 #include "MagickCore/image-private.h"
59 #include "MagickCore/list.h"
60 #include "MagickCore/magick.h"
61 #include "MagickCore/memory_.h"
62 #include "MagickCore/module.h"
63 #include "MagickCore/monitor.h"
64 #include "MagickCore/monitor-private.h"
65 #include "MagickCore/option.h"
66 #include "MagickCore/profile.h"
67 #include "MagickCore/property.h"
68 #include "MagickCore/quantum-private.h"
69 #include "MagickCore/static.h"
70 #include "MagickCore/statistic.h"
71 #include "MagickCore/string_.h"
72 #include "MagickCore/string-private.h"
73 #include "MagickCore/utility.h"
74 #include "MagickCore/version-private.h"
75 \f
76 /*
77   Forward declarations.
78 */
79 static MagickBooleanType
80   WriteMPCImage(const ImageInfo *,Image *,ExceptionInfo *);
81 \f
82 /*
83 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
84 %                                                                             %
85 %                                                                             %
86 %                                                                             %
87 %   I s M P C                                                                 %
88 %                                                                             %
89 %                                                                             %
90 %                                                                             %
91 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
92 %
93 %  IsMPC() returns MagickTrue if the image format type, identified by the
94 %  magick string, is an Magick Persistent Cache image.
95 %
96 %  The format of the IsMPC method is:
97 %
98 %      MagickBooleanType IsMPC(const unsigned char *magick,const size_t length)
99 %
100 %  A description of each parameter follows:
101 %
102 %    o magick: compare image format pattern against these bytes.
103 %
104 %    o length: Specifies the length of the magick string.
105 %
106 */
107 static MagickBooleanType IsMPC(const unsigned char *magick,const size_t length)
108 {
109   if (length < 14)
110     return(MagickFalse);
111   if (LocaleNCompare((const char *) magick,"id=MagickCache",14) == 0)
112     return(MagickTrue);
113   return(MagickFalse);
114 }
115 \f
116 /*
117 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
118 %                                                                             %
119 %                                                                             %
120 %                                                                             %
121 %   R e a d C A C H E I m a g e                                               %
122 %                                                                             %
123 %                                                                             %
124 %                                                                             %
125 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
126 %
127 %  ReadMPCImage() reads an Magick Persistent Cache image file and returns
128 %  it.  It allocates the memory necessary for the new Image structure and
129 %  returns a pointer to the new image.
130 %
131 %  The format of the ReadMPCImage method is:
132 %
133 %      Image *ReadMPCImage(const ImageInfo *image_info,ExceptionInfo *exception)
134 %
135 %  Decompression code contributed by Kyle Shorter.
136 %
137 %  A description of each parameter follows:
138 %
139 %    o image_info: the image info.
140 %
141 %    o exception: return any errors or warnings in this structure.
142 %
143 */
144 static Image *ReadMPCImage(const ImageInfo *image_info,ExceptionInfo *exception)
145 {
146   char
147     cache_filename[MaxTextExtent],
148     id[MaxTextExtent],
149     keyword[MaxTextExtent],
150     *options;
151
152   const unsigned char
153     *p;
154
155   GeometryInfo
156     geometry_info;
157
158   Image
159     *image;
160
161   int
162     c;
163
164   LinkedListInfo
165     *profiles;
166
167   MagickBooleanType
168     status;
169
170   MagickOffsetType
171     offset;
172
173   MagickStatusType
174     flags;
175
176   register ssize_t
177     i;
178
179   size_t
180     depth,
181     length;
182
183   ssize_t
184     count;
185
186   StringInfo
187     *profile;
188
189   unsigned int
190     signature;
191
192   /*
193     Open image file.
194   */
195   assert(image_info != (const ImageInfo *) NULL);
196   assert(image_info->signature == MagickSignature);
197   if (image_info->debug != MagickFalse)
198     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
199       image_info->filename);
200   assert(exception != (ExceptionInfo *) NULL);
201   assert(exception->signature == MagickSignature);
202   image=AcquireImage(image_info,exception);
203   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
204   if (status == MagickFalse)
205     {
206       image=DestroyImageList(image);
207       return((Image *) NULL);
208     }
209   (void) CopyMagickString(cache_filename,image->filename,MaxTextExtent);
210   AppendImageFormat("cache",cache_filename);
211   c=ReadBlobByte(image);
212   if (c == EOF)
213     {
214       image=DestroyImage(image);
215       return((Image *) NULL);
216     }
217   *id='\0';
218   (void) ResetMagickMemory(keyword,0,sizeof(keyword));
219   offset=0;
220   do
221   {
222     /*
223       Decode image header;  header terminates one character beyond a ':'.
224     */
225     profiles=(LinkedListInfo *) NULL;
226     length=MaxTextExtent;
227     options=AcquireString((char *) NULL);
228     signature=GetMagickSignature((const StringInfo *) NULL);
229     image->depth=8;
230     image->compression=NoCompression;
231     while ((isgraph(c) != MagickFalse) && (c != (int) ':'))
232     {
233       register char
234         *p;
235
236       if (c == (int) '{')
237         {
238           char
239             *comment;
240
241           /*
242             Read comment-- any text between { }.
243           */
244           length=MaxTextExtent;
245           comment=AcquireString((char *) NULL);
246           for (p=comment; comment != (char *) NULL; p++)
247           {
248             c=ReadBlobByte(image);
249             if (c == (int) '\\')
250               c=ReadBlobByte(image);
251             else
252               if ((c == EOF) || (c == (int) '}'))
253                 break;
254             if ((size_t) (p-comment+1) >= length)
255               {
256                 *p='\0';
257                 length<<=1;
258                 comment=(char *) ResizeQuantumMemory(comment,length+
259                   MaxTextExtent,sizeof(*comment));
260                 if (comment == (char *) NULL)
261                   break;
262                 p=comment+strlen(comment);
263               }
264             *p=(char) c;
265           }
266           if (comment == (char *) NULL)
267             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
268           *p='\0';
269           (void) SetImageProperty(image,"comment",comment,exception);
270           comment=DestroyString(comment);
271           c=ReadBlobByte(image);
272         }
273       else
274         if (isalnum(c) != MagickFalse)
275           {
276             /*
277               Get the keyword.
278             */
279             p=keyword;
280             do
281             {
282               if (c == (int) '=')
283                 break;
284               if ((size_t) (p-keyword) < (MaxTextExtent-1))
285                 *p++=(char) c;
286               c=ReadBlobByte(image);
287             } while (c != EOF);
288             *p='\0';
289             p=options;
290             while (isspace((int) ((unsigned char) c)) != 0)
291               c=ReadBlobByte(image);
292             if (c == (int) '=')
293               {
294                 /*
295                   Get the keyword value.
296                 */
297                 c=ReadBlobByte(image);
298                 while ((c != (int) '}') && (c != EOF))
299                 {
300                   if ((size_t) (p-options+1) >= length)
301                     {
302                       *p='\0';
303                       length<<=1;
304                       options=(char *) ResizeQuantumMemory(options,length+
305                         MaxTextExtent,sizeof(*options));
306                       if (options == (char *) NULL)
307                         break;
308                       p=options+strlen(options);
309                     }
310                   if (options == (char *) NULL)
311                     ThrowReaderException(ResourceLimitError,
312                       "MemoryAllocationFailed");
313                   *p++=(char) c;
314                   c=ReadBlobByte(image);
315                   if (c == '\\')
316                     {
317                       c=ReadBlobByte(image);
318                       if (c == (int) '}')
319                         {
320                           *p++=(char) c;
321                           c=ReadBlobByte(image);
322                         }
323                     }
324                   if (*options != '{')
325                     if (isspace((int) ((unsigned char) c)) != 0)
326                       break;
327                 }
328               }
329             *p='\0';
330             if (*options == '{')
331               (void) CopyMagickString(options,options+1,strlen(options));
332             /*
333               Assign a value to the specified keyword.
334             */
335             switch (*keyword)
336             {
337               case 'a':
338               case 'A':
339               {
340                 if (LocaleCompare(keyword,"alpha-trait") == 0)
341                   {
342                     ssize_t
343                       alpha_trait;
344
345                     alpha_trait=ParseCommandOption(MagickPixelTraitOptions,
346                       MagickFalse,options);
347                     if (alpha_trait < 0)
348                       break;
349                     image->alpha_trait=(PixelTrait) alpha_trait;
350                     break;
351                   }
352                 (void) SetImageProperty(image,keyword,options,exception);
353                 break;
354               }
355               case 'b':
356               case 'B':
357               {
358                 if (LocaleCompare(keyword,"background-color") == 0)
359                   {
360                     (void) QueryColorCompliance(options,AllCompliance,
361                       &image->background_color,exception);
362                     break;
363                   }
364                 if (LocaleCompare(keyword,"blue-primary") == 0)
365                   {
366                     flags=ParseGeometry(options,&geometry_info);
367                     image->chromaticity.blue_primary.x=geometry_info.rho;
368                     image->chromaticity.blue_primary.y=geometry_info.sigma;
369                     if ((flags & SigmaValue) == 0)
370                       image->chromaticity.blue_primary.y=
371                         image->chromaticity.blue_primary.x;
372                     break;
373                   }
374                 if (LocaleCompare(keyword,"border-color") == 0)
375                   {
376                     (void) QueryColorCompliance(options,AllCompliance,
377                       &image->border_color,exception);
378                     break;
379                   }
380                 (void) SetImageProperty(image,keyword,options,exception);
381                 break;
382               }
383               case 'c':
384               case 'C':
385               {
386                 if (LocaleCompare(keyword,"class") == 0)
387                   {
388                     ssize_t
389                       storage_class;
390
391                     storage_class=ParseCommandOption(MagickClassOptions,
392                       MagickFalse,options);
393                     if (storage_class < 0)
394                       break;
395                     image->storage_class=(ClassType) storage_class;
396                     break;
397                   }
398                 if (LocaleCompare(keyword,"colors") == 0)
399                   {
400                     image->colors=StringToUnsignedLong(options);
401                     break;
402                   }
403                 if (LocaleCompare(keyword,"colorspace") == 0)
404                   {
405                     ssize_t
406                       colorspace;
407
408                     colorspace=ParseCommandOption(MagickColorspaceOptions,
409                       MagickFalse,options);
410                     if (colorspace < 0)
411                       break;
412                     image->colorspace=(ColorspaceType) colorspace;
413                     break;
414                   }
415                 if (LocaleCompare(keyword,"compression") == 0)
416                   {
417                     ssize_t
418                       compression;
419
420                     compression=ParseCommandOption(MagickCompressOptions,
421                       MagickFalse,options);
422                     if (compression < 0)
423                       break;
424                     image->compression=(CompressionType) compression;
425                     break;
426                   }
427                 if (LocaleCompare(keyword,"columns") == 0)
428                   {
429                     image->columns=StringToUnsignedLong(options);
430                     break;
431                   }
432                 (void) SetImageProperty(image,keyword,options,exception);
433                 break;
434               }
435               case 'd':
436               case 'D':
437               {
438                 if (LocaleCompare(keyword,"delay") == 0)
439                   {
440                     image->delay=StringToUnsignedLong(options);
441                     break;
442                   }
443                 if (LocaleCompare(keyword,"depth") == 0)
444                   {
445                     image->depth=StringToUnsignedLong(options);
446                     break;
447                   }
448                 if (LocaleCompare(keyword,"dispose") == 0)
449                   {
450                     ssize_t
451                       dispose;
452
453                     dispose=ParseCommandOption(MagickDisposeOptions,MagickFalse,
454                       options);
455                     if (dispose < 0)
456                       break;
457                     image->dispose=(DisposeType) dispose;
458                     break;
459                   }
460                 (void) SetImageProperty(image,keyword,options,exception);
461                 break;
462               }
463               case 'e':
464               case 'E':
465               {
466                 if (LocaleCompare(keyword,"endian") == 0)
467                   {
468                     ssize_t
469                       endian;
470
471                     endian=ParseCommandOption(MagickEndianOptions,MagickFalse,
472                       options);
473                     if (endian < 0)
474                       break;
475                     image->endian=(EndianType) endian;
476                     break;
477                   }
478                 if (LocaleCompare(keyword,"error") == 0)
479                   {
480                     image->error.mean_error_per_pixel=StringToDouble(options,
481                       (char **) NULL);
482                     break;
483                   }
484                 (void) SetImageProperty(image,keyword,options,exception);
485                 break;
486               }
487               case 'g':
488               case 'G':
489               {
490                 if (LocaleCompare(keyword,"gamma") == 0)
491                   {
492                     image->gamma=StringToDouble(options,(char **) NULL);
493                     break;
494                   }
495                 if (LocaleCompare(keyword,"green-primary") == 0)
496                   {
497                     flags=ParseGeometry(options,&geometry_info);
498                     image->chromaticity.green_primary.x=geometry_info.rho;
499                     image->chromaticity.green_primary.y=geometry_info.sigma;
500                     if ((flags & SigmaValue) == 0)
501                       image->chromaticity.green_primary.y=
502                         image->chromaticity.green_primary.x;
503                     break;
504                   }
505                 (void) SetImageProperty(image,keyword,options,exception);
506                 break;
507               }
508               case 'i':
509               case 'I':
510               {
511                 if (LocaleCompare(keyword,"id") == 0)
512                   {
513                     (void) CopyMagickString(id,options,MaxTextExtent);
514                     break;
515                   }
516                 if (LocaleCompare(keyword,"iterations") == 0)
517                   {
518                     image->iterations=StringToUnsignedLong(options);
519                     break;
520                   }
521                 (void) SetImageProperty(image,keyword,options,exception);
522                 break;
523               }
524               case 'm':
525               case 'M':
526               {
527                 if (LocaleCompare(keyword,"magick-signature") == 0)
528                   {
529                     signature=(unsigned int) StringToUnsignedLong(options);
530                     break;
531                   }
532                 if (LocaleCompare(keyword,"matte-color") == 0)
533                   {
534                     (void) QueryColorCompliance(options,AllCompliance,
535                       &image->matte_color,exception);
536                     break;
537                   }
538                 if (LocaleCompare(keyword,"maximum-error") == 0)
539                   {
540                     image->error.normalized_maximum_error=StringToDouble(
541                       options,(char **) NULL);
542                     break;
543                   }
544                 if (LocaleCompare(keyword,"mean-error") == 0)
545                   {
546                     image->error.normalized_mean_error=StringToDouble(options,
547                       (char **) NULL);
548                     break;
549                   }
550                 if (LocaleCompare(keyword,"montage") == 0)
551                   {
552                     (void) CloneString(&image->montage,options);
553                     break;
554                   }
555                 (void) SetImageProperty(image,keyword,options,exception);
556                 break;
557               }
558               case 'o':
559               case 'O':
560               {
561                 if (LocaleCompare(keyword,"orientation") == 0)
562                   {
563                     ssize_t
564                       orientation;
565
566                     orientation=ParseCommandOption(MagickOrientationOptions,
567                       MagickFalse,options);
568                     if (orientation < 0)
569                       break;
570                     image->orientation=(OrientationType) orientation;
571                     break;
572                   }
573                 (void) SetImageProperty(image,keyword,options,exception);
574                 break;
575               }
576               case 'p':
577               case 'P':
578               {
579                 if (LocaleCompare(keyword,"page") == 0)
580                   {
581                     char
582                       *geometry;
583
584                     geometry=GetPageGeometry(options);
585                     (void) ParseAbsoluteGeometry(geometry,&image->page);
586                     geometry=DestroyString(geometry);
587                     break;
588                   }
589                 if (LocaleCompare(keyword,"pixel-intensity") == 0)
590                   {
591                     ssize_t
592                       intensity;
593
594                     intensity=ParseCommandOption(MagickPixelIntensityOptions,
595                       MagickFalse,options);
596                     if (intensity < 0)
597                       break;
598                     image->intensity=(PixelIntensityMethod) intensity;
599                     break;
600                   }
601                 if ((LocaleNCompare(keyword,"profile:",8) == 0) ||
602                     (LocaleNCompare(keyword,"profile-",8) == 0))
603                   {
604                     if (profiles == (LinkedListInfo *) NULL)
605                       profiles=NewLinkedList(0);
606                     (void) AppendValueToLinkedList(profiles,
607                       AcquireString(keyword+8));
608                     profile=BlobToStringInfo((const void *) NULL,(size_t)
609                       StringToLong(options));
610                     if (profile == (StringInfo *) NULL)
611                       ThrowReaderException(ResourceLimitError,
612                         "MemoryAllocationFailed");
613                     (void) SetImageProfile(image,keyword+8,profile,exception);
614                     profile=DestroyStringInfo(profile);
615                     break;
616                   }
617                 (void) SetImageProperty(image,keyword,options,exception);
618                 break;
619               }
620               case 'q':
621               case 'Q':
622               {
623                 if (LocaleCompare(keyword,"quality") == 0)
624                   {
625                     image->quality=StringToUnsignedLong(options);
626                     break;
627                   }
628                 (void) SetImageProperty(image,keyword,options,exception);
629                 break;
630               }
631               case 'r':
632               case 'R':
633               {
634                 if (LocaleCompare(keyword,"red-primary") == 0)
635                   {
636                     flags=ParseGeometry(options,&geometry_info);
637                     image->chromaticity.red_primary.x=geometry_info.rho;
638                     if ((flags & SigmaValue) != 0)
639                       image->chromaticity.red_primary.y=geometry_info.sigma;
640                     break;
641                   }
642                 if (LocaleCompare(keyword,"rendering-intent") == 0)
643                   {
644                     ssize_t
645                       rendering_intent;
646
647                     rendering_intent=ParseCommandOption(MagickIntentOptions,
648                       MagickFalse,options);
649                     if (rendering_intent < 0)
650                       break;
651                     image->rendering_intent=(RenderingIntent) rendering_intent;
652                     break;
653                   }
654                 if (LocaleCompare(keyword,"resolution") == 0)
655                   {
656                     flags=ParseGeometry(options,&geometry_info);
657                     image->resolution.x=geometry_info.rho;
658                     image->resolution.y=geometry_info.sigma;
659                     if ((flags & SigmaValue) == 0)
660                       image->resolution.y=image->resolution.x;
661                     break;
662                   }
663                 if (LocaleCompare(keyword,"rows") == 0)
664                   {
665                     image->rows=StringToUnsignedLong(options);
666                     break;
667                   }
668                 (void) SetImageProperty(image,keyword,options,exception);
669                 break;
670               }
671               case 's':
672               case 'S':
673               {
674                 if (LocaleCompare(keyword,"scene") == 0)
675                   {
676                     image->scene=StringToUnsignedLong(options);
677                     break;
678                   }
679                 (void) SetImageProperty(image,keyword,options,exception);
680                 break;
681               }
682               case 't':
683               case 'T':
684               {
685                 if (LocaleCompare(keyword,"ticks-per-second") == 0)
686                   {
687                     image->ticks_per_second=(ssize_t) StringToLong(options);
688                     break;
689                   }
690                 if (LocaleCompare(keyword,"tile-offset") == 0)
691                   {
692                     char
693                       *geometry;
694
695                     geometry=GetPageGeometry(options);
696                     (void) ParseAbsoluteGeometry(geometry,&image->tile_offset);
697                     geometry=DestroyString(geometry);
698                   }
699                 if (LocaleCompare(keyword,"type") == 0)
700                   {
701                     ssize_t
702                       type;
703
704                     type=ParseCommandOption(MagickTypeOptions,MagickFalse,
705                       options);
706                     if (type < 0)
707                       break;
708                     image->type=(ImageType) type;
709                     break;
710                   }
711                 (void) SetImageProperty(image,keyword,options,exception);
712                 break;
713               }
714               case 'u':
715               case 'U':
716               {
717                 if (LocaleCompare(keyword,"units") == 0)
718                   {
719                     ssize_t
720                       units;
721
722                     units=ParseCommandOption(MagickResolutionOptions,
723                       MagickFalse,options);
724                     if (units < 0)
725                       break;
726                     image->units=(ResolutionType) units;
727                     break;
728                   }
729                 (void) SetImageProperty(image,keyword,options,exception);
730                 break;
731               }
732               case 'w':
733               case 'W':
734               {
735                 if (LocaleCompare(keyword,"white-point") == 0)
736                   {
737                     flags=ParseGeometry(options,&geometry_info);
738                     image->chromaticity.white_point.x=geometry_info.rho;
739                     image->chromaticity.white_point.y=geometry_info.sigma;
740                     if ((flags & SigmaValue) == 0)
741                       image->chromaticity.white_point.y=
742                         image->chromaticity.white_point.x;
743                     break;
744                   }
745                 (void) SetImageProperty(image,keyword,options,exception);
746                 break;
747               }
748               default:
749               {
750                 (void) SetImageProperty(image,keyword,options,exception);
751                 break;
752               }
753             }
754           }
755         else
756           c=ReadBlobByte(image);
757       while (isspace((int) ((unsigned char) c)) != 0)
758         c=ReadBlobByte(image);
759     }
760     options=DestroyString(options);
761     (void) ReadBlobByte(image);
762     /*
763       Verify that required image information is defined.
764     */
765     if ((LocaleCompare(id,"MagickCache") != 0) ||
766         (image->storage_class == UndefinedClass) ||
767         (image->compression == UndefinedCompression) || (image->columns == 0) ||
768         (image->rows == 0))
769       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
770     if (signature != GetMagickSignature((const StringInfo *) NULL))
771       ThrowReaderException(CacheError,"IncompatibleAPI");
772     if (image->montage != (char *) NULL)
773       {
774         register char
775           *p;
776
777         /*
778           Image directory.
779         */
780         length=MaxTextExtent;
781         image->directory=AcquireString((char *) NULL);
782         p=image->directory;
783         do
784         {
785           *p='\0';
786           if ((strlen(image->directory)+MaxTextExtent) >= length)
787             {
788               /*
789                 Allocate more memory for the image directory.
790               */
791               length<<=1;
792               image->directory=(char *) ResizeQuantumMemory(image->directory,
793                 length+MaxTextExtent,sizeof(*image->directory));
794               if (image->directory == (char *) NULL)
795                 ThrowReaderException(CorruptImageError,"UnableToReadImageData");
796               p=image->directory+strlen(image->directory);
797             }
798           c=ReadBlobByte(image);
799           *p++=(char) c;
800         } while (c != (int) '\0');
801       }
802     if (profiles != (LinkedListInfo *) NULL)
803       {
804         const char
805           *name;
806
807         const StringInfo
808           *profile;
809
810         register unsigned char
811           *p;
812
813         /*
814           Read image profiles.
815         */
816         ResetLinkedListIterator(profiles);
817         name=(const char *) GetNextValueInLinkedList(profiles);
818         while (name != (const char *) NULL)
819         {
820           profile=GetImageProfile(image,name);
821           if (profile != (StringInfo *) NULL)
822             {
823               p=GetStringInfoDatum(profile);
824               count=ReadBlob(image,GetStringInfoLength(profile),p);
825             }
826           name=(const char *) GetNextValueInLinkedList(profiles);
827         }
828         profiles=DestroyLinkedList(profiles,RelinquishMagickMemory);
829       }
830     depth=GetImageQuantumDepth(image,MagickFalse);
831     if (image->storage_class == PseudoClass)
832       {
833         /*
834           Create image colormap.
835         */
836         if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
837           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
838         if (image->colors != 0)
839           {
840             size_t
841               packet_size;
842
843             unsigned char
844               *colormap;
845
846             /*
847               Read image colormap from file.
848             */
849             packet_size=(size_t) (3UL*depth/8UL);
850             colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
851               packet_size*sizeof(*colormap));
852             if (colormap == (unsigned char *) NULL)
853               ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
854             count=ReadBlob(image,packet_size*image->colors,colormap);
855             if (count != (ssize_t) (packet_size*image->colors))
856               ThrowReaderException(CorruptImageError,
857                 "InsufficientImageDataInFile");
858             p=colormap;
859             switch (depth)
860             {
861               default:
862                 ThrowReaderException(CorruptImageError,
863                   "ImageDepthNotSupported");
864               case 8:
865               {
866                 unsigned char
867                   pixel;
868
869                 for (i=0; i < (ssize_t) image->colors; i++)
870                 {
871                   p=PushCharPixel(p,&pixel);
872                   image->colormap[i].red=ScaleCharToQuantum(pixel);
873                   p=PushCharPixel(p,&pixel);
874                   image->colormap[i].green=ScaleCharToQuantum(pixel);
875                   p=PushCharPixel(p,&pixel);
876                   image->colormap[i].blue=ScaleCharToQuantum(pixel);
877                 }
878                 break;
879               }
880               case 16:
881               {
882                 unsigned short
883                   pixel;
884
885                 for (i=0; i < (ssize_t) image->colors; i++)
886                 {
887                   p=PushShortPixel(MSBEndian,p,&pixel);
888                   image->colormap[i].red=ScaleShortToQuantum(pixel);
889                   p=PushShortPixel(MSBEndian,p,&pixel);
890                   image->colormap[i].green=ScaleShortToQuantum(pixel);
891                   p=PushShortPixel(MSBEndian,p,&pixel);
892                   image->colormap[i].blue=ScaleShortToQuantum(pixel);
893                 }
894                 break;
895               }
896               case 32:
897               {
898                 unsigned int
899                   pixel;
900
901                 for (i=0; i < (ssize_t) image->colors; i++)
902                 {
903                   p=PushLongPixel(MSBEndian,p,&pixel);
904                   image->colormap[i].red=ScaleLongToQuantum(pixel);
905                   p=PushLongPixel(MSBEndian,p,&pixel);
906                   image->colormap[i].green=ScaleLongToQuantum(pixel);
907                   p=PushLongPixel(MSBEndian,p,&pixel);
908                   image->colormap[i].blue=ScaleLongToQuantum(pixel);
909                 }
910                 break;
911               }
912             }
913             colormap=(unsigned char *) RelinquishMagickMemory(colormap);
914           }
915       }
916     if (EOFBlob(image) != MagickFalse)
917       {
918         ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
919           image->filename);
920         break;
921       }
922     if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
923       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
924         break;
925     /*
926       Attach persistent pixel cache.
927     */
928     status=PersistPixelCache(image,cache_filename,MagickTrue,&offset,exception);
929     if (status == MagickFalse)
930       ThrowReaderException(CacheError,"UnableToPersistPixelCache");
931     /*
932       Proceed to next image.
933     */
934     do
935     {
936       c=ReadBlobByte(image);
937     } while ((isgraph(c) == MagickFalse) && (c != EOF));
938     if (c != EOF)
939       {
940         /*
941           Allocate next image structure.
942         */
943         AcquireNextImage(image_info,image,exception);
944         if (GetNextImageInList(image) == (Image *) NULL)
945           {
946             image=DestroyImageList(image);
947             return((Image *) NULL);
948           }
949         image=SyncNextImageInList(image);
950         status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
951           GetBlobSize(image));
952         if (status == MagickFalse)
953           break;
954       }
955   } while (c != EOF);
956   (void) CloseBlob(image);
957   return(GetFirstImageInList(image));
958 }
959 \f
960 /*
961 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
962 %                                                                             %
963 %                                                                             %
964 %                                                                             %
965 %   R e g i s t e r M P C I m a g e                                           %
966 %                                                                             %
967 %                                                                             %
968 %                                                                             %
969 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
970 %
971 %  RegisterMPCImage() adds properties for the Cache image format to
972 %  the list of supported formats.  The properties include the image format
973 %  tag, a method to read and/or write the format, whether the format
974 %  supports the saving of more than one frame to the same file or blob,
975 %  whether the format supports native in-memory I/O, and a brief
976 %  description of the format.
977 %
978 %  The format of the RegisterMPCImage method is:
979 %
980 %      size_t RegisterMPCImage(void)
981 %
982 */
983 ModuleExport size_t RegisterMPCImage(void)
984 {
985   MagickInfo
986     *entry;
987
988   entry=SetMagickInfo("CACHE");
989   entry->description=ConstantString("Magick Persistent Cache image format");
990   entry->module=ConstantString("CACHE");
991   entry->stealth=MagickTrue;
992   (void) RegisterMagickInfo(entry);
993   entry=SetMagickInfo("MPC");
994   entry->decoder=(DecodeImageHandler *) ReadMPCImage;
995   entry->encoder=(EncodeImageHandler *) WriteMPCImage;
996   entry->magick=(IsImageFormatHandler *) IsMPC;
997   entry->description=ConstantString("Magick Persistent Cache image format");
998   entry->module=ConstantString("MPC");
999   (void) RegisterMagickInfo(entry);
1000   return(MagickImageCoderSignature);
1001 }
1002 \f
1003 /*
1004 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1005 %                                                                             %
1006 %                                                                             %
1007 %                                                                             %
1008 %   U n r e g i s t e r M P C I m a g e                                       %
1009 %                                                                             %
1010 %                                                                             %
1011 %                                                                             %
1012 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1013 %
1014 %  UnregisterMPCImage() removes format registrations made by the
1015 %  MPC module from the list of supported formats.
1016 %
1017 %  The format of the UnregisterMPCImage method is:
1018 %
1019 %      UnregisterMPCImage(void)
1020 %
1021 */
1022 ModuleExport void UnregisterMPCImage(void)
1023 {
1024   (void) UnregisterMagickInfo("CACHE");
1025   (void) UnregisterMagickInfo("MPC");
1026 }
1027 \f
1028 /*
1029 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1030 %                                                                             %
1031 %                                                                             %
1032 %                                                                             %
1033 %   W r i t e M P C I m a g e                                                 %
1034 %                                                                             %
1035 %                                                                             %
1036 %                                                                             %
1037 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1038 %
1039 %  WriteMPCImage() writes an Magick Persistent Cache image to a file.
1040 %
1041 %  The format of the WriteMPCImage method is:
1042 %
1043 %      MagickBooleanType WriteMPCImage(const ImageInfo *image_info,
1044 %        Image *image,ExceptionInfo *exception)
1045 %
1046 %  A description of each parameter follows:
1047 %
1048 %    o image_info: the image info.
1049 %
1050 %    o image: the image.
1051 %
1052 %    o exception: return any errors or warnings in this structure.
1053 %
1054 */
1055 static MagickBooleanType WriteMPCImage(const ImageInfo *image_info,Image *image,
1056   ExceptionInfo *exception)
1057 {
1058   char
1059     buffer[MaxTextExtent],
1060     cache_filename[MaxTextExtent];
1061
1062   const char
1063     *property,
1064     *value;
1065
1066   MagickBooleanType
1067     status;
1068
1069   MagickOffsetType
1070     offset,
1071     scene;
1072
1073   register ssize_t
1074     i;
1075
1076   size_t
1077     depth;
1078
1079   /*
1080     Open persistent cache.
1081   */
1082   assert(image_info != (const ImageInfo *) NULL);
1083   assert(image_info->signature == MagickSignature);
1084   assert(image != (Image *) NULL);
1085   assert(image->signature == MagickSignature);
1086   if (image->debug != MagickFalse)
1087     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1088   assert(exception != (ExceptionInfo *) NULL);
1089   assert(exception->signature == MagickSignature);
1090   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1091   if (status == MagickFalse)
1092     return(status);
1093   (void) CopyMagickString(cache_filename,image->filename,MaxTextExtent);
1094   AppendImageFormat("cache",cache_filename);
1095   scene=0;
1096   offset=0;
1097   do
1098   {
1099     /*
1100       Write persistent cache meta-information.
1101     */
1102     depth=GetImageQuantumDepth(image,MagickTrue);
1103     if ((image->storage_class == PseudoClass) &&
1104         (image->colors > (size_t) (GetQuantumRange(image->depth)+1)))
1105       (void) SetImageStorageClass(image,DirectClass,exception);
1106     (void) WriteBlobString(image,"id=MagickCache\n");
1107     (void) FormatLocaleString(buffer,MaxTextExtent,"magick-signature=%u\n",
1108       GetMagickSignature((const StringInfo *) NULL));
1109     (void) WriteBlobString(image,buffer);
1110     (void) FormatLocaleString(buffer,MaxTextExtent,
1111       "class=%s  colors=%.20g  alpha-trait=%s\n",CommandOptionToMnemonic(
1112       MagickClassOptions,image->storage_class),(double) image->colors,
1113       CommandOptionToMnemonic(MagickPixelTraitOptions,(ssize_t)
1114       image->alpha_trait));
1115     (void) WriteBlobString(image,buffer);
1116     (void) FormatLocaleString(buffer,MaxTextExtent,
1117       "columns=%.20g  rows=%.20g depth=%.20g\n",(double) image->columns,
1118       (double) image->rows,(double) image->depth);
1119     (void) WriteBlobString(image,buffer);
1120     if (image->type != UndefinedType)
1121       {
1122         (void) FormatLocaleString(buffer,MaxTextExtent,"type=%s\n",
1123           CommandOptionToMnemonic(MagickTypeOptions,image->type));
1124         (void) WriteBlobString(image,buffer);
1125       }
1126     if (image->colorspace != UndefinedColorspace)
1127       {
1128         (void) FormatLocaleString(buffer,MaxTextExtent,"colorspace=%s\n",
1129           CommandOptionToMnemonic(MagickColorspaceOptions,image->colorspace));
1130         (void) WriteBlobString(image,buffer);
1131       }
1132     if (image->intensity != UndefinedPixelIntensityMethod)
1133       {
1134         (void) FormatLocaleString(buffer,MaxTextExtent,"pixel-intensity=%s\n",
1135           CommandOptionToMnemonic(MagickPixelIntensityOptions,
1136           image->intensity));
1137         (void) WriteBlobString(image,buffer);
1138       }
1139     if (image->endian != UndefinedEndian)
1140       {
1141         (void) FormatLocaleString(buffer,MaxTextExtent,"endian=%s\n",
1142           CommandOptionToMnemonic(MagickEndianOptions,image->endian));
1143         (void) WriteBlobString(image,buffer);
1144       }
1145     if (image->compression != UndefinedCompression)
1146       {
1147         (void) FormatLocaleString(buffer,MaxTextExtent,
1148           "compression=%s  quality=%.20g\n",CommandOptionToMnemonic(
1149           MagickCompressOptions,image->compression),(double) image->quality);
1150         (void) WriteBlobString(image,buffer);
1151       }
1152     if (image->units != UndefinedResolution)
1153       {
1154         (void) FormatLocaleString(buffer,MaxTextExtent,"units=%s\n",
1155           CommandOptionToMnemonic(MagickResolutionOptions,image->units));
1156         (void) WriteBlobString(image,buffer);
1157       }
1158     if ((image->resolution.x != 0) || (image->resolution.y != 0))
1159       {
1160         (void) FormatLocaleString(buffer,MaxTextExtent,
1161           "resolution=%gx%g\n",image->resolution.x,image->resolution.y);
1162         (void) WriteBlobString(image,buffer);
1163       }
1164     if ((image->page.width != 0) || (image->page.height != 0))
1165       {
1166         (void) FormatLocaleString(buffer,MaxTextExtent,
1167           "page=%.20gx%.20g%+.20g%+.20g\n",(double) image->page.width,(double)
1168           image->page.height,(double) image->page.x,(double) image->page.y);
1169         (void) WriteBlobString(image,buffer);
1170       }
1171     else
1172       if ((image->page.x != 0) || (image->page.y != 0))
1173         {
1174           (void) FormatLocaleString(buffer,MaxTextExtent,"page=%+ld%+ld\n",
1175             (long) image->page.x,(long) image->page.y);
1176           (void) WriteBlobString(image,buffer);
1177         }
1178     if ((image->page.x != 0) || (image->page.y != 0))
1179       {
1180         (void) FormatLocaleString(buffer,MaxTextExtent,"tile-offset=%+ld%+ld\n",
1181           (long) image->tile_offset.x,(long) image->tile_offset.y);
1182         (void) WriteBlobString(image,buffer);
1183       }
1184     if ((GetNextImageInList(image) != (Image *) NULL) ||
1185         (GetPreviousImageInList(image) != (Image *) NULL))
1186       {
1187         if (image->scene == 0)
1188           (void) FormatLocaleString(buffer,MaxTextExtent,
1189             "iterations=%.20g  delay=%.20g  ticks-per-second=%.20g\n",(double)
1190             image->iterations,(double) image->delay,(double)
1191             image->ticks_per_second);
1192         else
1193           (void) FormatLocaleString(buffer,MaxTextExtent,"scene=%.20g  "
1194             "iterations=%.20g  delay=%.20g  ticks-per-second=%.20g\n",
1195             (double) image->scene,(double) image->iterations,(double)
1196             image->delay,(double) image->ticks_per_second);
1197         (void) WriteBlobString(image,buffer);
1198       }
1199     else
1200       {
1201         if (image->scene != 0)
1202           {
1203             (void) FormatLocaleString(buffer,MaxTextExtent,"scene=%.20g\n",
1204               (double) image->scene);
1205             (void) WriteBlobString(image,buffer);
1206           }
1207         if (image->iterations != 0)
1208           {
1209             (void) FormatLocaleString(buffer,MaxTextExtent,"iterations=%.20g\n",
1210               (double) image->iterations);
1211             (void) WriteBlobString(image,buffer);
1212           }
1213         if (image->delay != 0)
1214           {
1215             (void) FormatLocaleString(buffer,MaxTextExtent,"delay=%.20g\n",
1216               (double) image->delay);
1217             (void) WriteBlobString(image,buffer);
1218           }
1219         if (image->ticks_per_second != UndefinedTicksPerSecond)
1220           {
1221             (void) FormatLocaleString(buffer,MaxTextExtent,
1222               "ticks-per-second=%.20g\n",(double) image->ticks_per_second);
1223             (void) WriteBlobString(image,buffer);
1224           }
1225       }
1226     if (image->gravity != UndefinedGravity)
1227       {
1228         (void) FormatLocaleString(buffer,MaxTextExtent,"gravity=%s\n",
1229           CommandOptionToMnemonic(MagickGravityOptions,image->gravity));
1230         (void) WriteBlobString(image,buffer);
1231       }
1232     if (image->dispose != UndefinedDispose)
1233       {
1234         (void) FormatLocaleString(buffer,MaxTextExtent,"dispose=%s\n",
1235           CommandOptionToMnemonic(MagickDisposeOptions,image->dispose));
1236         (void) WriteBlobString(image,buffer);
1237       }
1238     if (image->rendering_intent != UndefinedIntent)
1239       {
1240         (void) FormatLocaleString(buffer,MaxTextExtent,
1241           "rendering-intent=%s\n",CommandOptionToMnemonic(MagickIntentOptions,
1242           image->rendering_intent));
1243         (void) WriteBlobString(image,buffer);
1244       }
1245     if (image->gamma != 0.0)
1246       {
1247         (void) FormatLocaleString(buffer,MaxTextExtent,"gamma=%g\n",
1248           image->gamma);
1249         (void) WriteBlobString(image,buffer);
1250       }
1251     if (image->chromaticity.white_point.x != 0.0)
1252       {
1253         /*
1254           Note chomaticity points.
1255         */
1256         (void) FormatLocaleString(buffer,MaxTextExtent,"red-primary="
1257           "%g,%g  green-primary=%g,%g  blue-primary=%g,%g\n",
1258           image->chromaticity.red_primary.x,image->chromaticity.red_primary.y,
1259           image->chromaticity.green_primary.x,
1260           image->chromaticity.green_primary.y,
1261           image->chromaticity.blue_primary.x,
1262           image->chromaticity.blue_primary.y);
1263         (void) WriteBlobString(image,buffer);
1264         (void) FormatLocaleString(buffer,MaxTextExtent,
1265           "white-point=%g,%g\n",image->chromaticity.white_point.x,
1266           image->chromaticity.white_point.y);
1267         (void) WriteBlobString(image,buffer);
1268       }
1269     if (image->orientation != UndefinedOrientation)
1270       {
1271         (void) FormatLocaleString(buffer,MaxTextExtent,
1272           "orientation=%s\n",CommandOptionToMnemonic(MagickOrientationOptions,
1273           image->orientation));
1274         (void) WriteBlobString(image,buffer);
1275       }
1276     if (image->profiles != (void *) NULL)
1277       {
1278         const char
1279           *name;
1280
1281         const StringInfo
1282           *profile;
1283
1284         /*
1285           Generic profile.
1286         */
1287         ResetImageProfileIterator(image);
1288         for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1289         {
1290           profile=GetImageProfile(image,name);
1291           if (profile != (StringInfo *) NULL)
1292             {
1293               (void) FormatLocaleString(buffer,MaxTextExtent,
1294                 "profile:%s=%.20g\n",name,(double)
1295                 GetStringInfoLength(profile));
1296               (void) WriteBlobString(image,buffer);
1297             }
1298           name=GetNextImageProfile(image);
1299         }
1300       }
1301     if (image->montage != (char *) NULL)
1302       {
1303         (void) FormatLocaleString(buffer,MaxTextExtent,"montage=%s\n",
1304           image->montage);
1305         (void) WriteBlobString(image,buffer);
1306       }
1307     ResetImagePropertyIterator(image);
1308     property=GetNextImageProperty(image);
1309     while (property != (const char *) NULL)
1310     {
1311       (void) FormatLocaleString(buffer,MaxTextExtent,"%s=",property);
1312       (void) WriteBlobString(image,buffer);
1313       value=GetImageProperty(image,property,exception);
1314       if (value != (const char *) NULL)
1315         {
1316           size_t
1317             length;
1318
1319           length=strlen(value);
1320           for (i=0; i < (ssize_t) length; i++)
1321             if (isspace((int) ((unsigned char) value[i])) != 0)
1322               break;
1323           if ((i == (ssize_t) length) && (i != 0))
1324             (void) WriteBlob(image,length,(const unsigned char *) value);
1325           else
1326             {
1327               (void) WriteBlobByte(image,'{');
1328               if (strchr(value,'}') == (char *) NULL)
1329                 (void) WriteBlob(image,length,(const unsigned char *) value);
1330               else
1331                 for (i=0; i < (ssize_t) length; i++)
1332                 {
1333                   if (value[i] == (int) '}')
1334                     (void) WriteBlobByte(image,'\\');
1335                   (void) WriteBlobByte(image,value[i]);
1336                 }
1337               (void) WriteBlobByte(image,'}');
1338             }
1339         }
1340       (void) WriteBlobByte(image,'\n');
1341       property=GetNextImageProperty(image);
1342     }
1343     (void) WriteBlobString(image,"\f\n:\032");
1344     if (image->montage != (char *) NULL)
1345       {
1346         /*
1347           Write montage tile directory.
1348         */
1349         if (image->directory != (char *) NULL)
1350           (void) WriteBlobString(image,image->directory);
1351         (void) WriteBlobByte(image,'\0');
1352       }
1353     if (image->profiles != 0)
1354       {
1355         const char
1356           *name;
1357
1358         const StringInfo
1359           *profile;
1360
1361         /*
1362           Write image profiles.
1363         */
1364         ResetImageProfileIterator(image);
1365         name=GetNextImageProfile(image);
1366         while (name != (const char *) NULL)
1367         {
1368           profile=GetImageProfile(image,name);
1369           (void) WriteBlob(image,GetStringInfoLength(profile),
1370             GetStringInfoDatum(profile));
1371           name=GetNextImageProfile(image);
1372         }
1373       }
1374     if (image->storage_class == PseudoClass)
1375       {
1376         size_t
1377           packet_size;
1378
1379         unsigned char
1380           *colormap,
1381           *q;
1382
1383         /*
1384           Allocate colormap.
1385         */
1386         packet_size=(size_t) (3UL*depth/8UL);
1387         colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
1388           packet_size*sizeof(*colormap));
1389         if (colormap == (unsigned char *) NULL)
1390           return(MagickFalse);
1391         /*
1392           Write colormap to file.
1393         */
1394         q=colormap;
1395         for (i=0; i < (ssize_t) image->colors; i++)
1396         {
1397           switch (depth)
1398           {
1399             default:
1400               ThrowWriterException(CorruptImageError,"ImageDepthNotSupported");
1401             case 32:
1402             {
1403               unsigned int
1404                 pixel;
1405
1406               pixel=ScaleQuantumToLong(image->colormap[i].red);
1407               q=PopLongPixel(MSBEndian,pixel,q);
1408               pixel=ScaleQuantumToLong(image->colormap[i].green);
1409               q=PopLongPixel(MSBEndian,pixel,q);
1410               pixel=ScaleQuantumToLong(image->colormap[i].blue);
1411               q=PopLongPixel(MSBEndian,pixel,q);
1412             }
1413             case 16:
1414             {
1415               unsigned short
1416                 pixel;
1417
1418               pixel=ScaleQuantumToShort(image->colormap[i].red);
1419               q=PopShortPixel(MSBEndian,pixel,q);
1420               pixel=ScaleQuantumToShort(image->colormap[i].green);
1421               q=PopShortPixel(MSBEndian,pixel,q);
1422               pixel=ScaleQuantumToShort(image->colormap[i].blue);
1423               q=PopShortPixel(MSBEndian,pixel,q);
1424               break;
1425             }
1426             case 8:
1427             {
1428               unsigned char
1429                 pixel;
1430
1431               pixel=(unsigned char) ScaleQuantumToChar(image->colormap[i].red);
1432               q=PopCharPixel(pixel,q);
1433               pixel=(unsigned char) ScaleQuantumToChar(
1434                 image->colormap[i].green);
1435               q=PopCharPixel(pixel,q);
1436               pixel=(unsigned char) ScaleQuantumToChar(image->colormap[i].blue);
1437               q=PopCharPixel(pixel,q);
1438               break;
1439             }
1440           }
1441         }
1442         (void) WriteBlob(image,packet_size*image->colors,colormap);
1443         colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1444       }
1445     /*
1446       Initialize persistent pixel cache.
1447     */
1448     status=PersistPixelCache(image,cache_filename,MagickFalse,&offset,
1449       exception);
1450     if (status == MagickFalse)
1451       ThrowWriterException(CacheError,"UnableToPersistPixelCache");
1452     if (GetNextImageInList(image) == (Image *) NULL)
1453       break;
1454     image=SyncNextImageInList(image);
1455     if (image->progress_monitor != (MagickProgressMonitor) NULL)
1456       {
1457         status=image->progress_monitor(SaveImagesTag,scene,
1458           GetImageListLength(image),image->client_data);
1459         if (status == MagickFalse)
1460           break;
1461       }
1462     scene++;
1463   } while (image_info->adjoin != MagickFalse);
1464   (void) CloseBlob(image);
1465   return(status);
1466 }