]> 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 %                                John Cristy                                  %
17 %                                 March 2000                                  %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2013 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                     (void) SetImageColorspace(image,(ColorspaceType) colorspace,                      exception);
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,"matte-color") == 0)
528                   {
529                     (void) QueryColorCompliance(options,AllCompliance,
530                       &image->matte_color,exception);
531                     break;
532                   }
533                 if (LocaleCompare(keyword,"maximum-error") == 0)
534                   {
535                     image->error.normalized_maximum_error=StringToDouble(
536                       options,(char **) NULL);
537                     break;
538                   }
539                 if (LocaleCompare(keyword,"mean-error") == 0)
540                   {
541                     image->error.normalized_mean_error=StringToDouble(options,
542                       (char **) NULL);
543                     break;
544                   }
545                 if (LocaleCompare(keyword,"montage") == 0)
546                   {
547                     (void) CloneString(&image->montage,options);
548                     break;
549                   }
550                 (void) SetImageProperty(image,keyword,options,exception);
551                 break;
552               }
553               case 'o':
554               case 'O':
555               {
556                 if (LocaleCompare(keyword,"orientation") == 0)
557                   {
558                     ssize_t
559                       orientation;
560
561                     orientation=ParseCommandOption(MagickOrientationOptions,
562                       MagickFalse,options);
563                     if (orientation < 0)
564                       break;
565                     image->orientation=(OrientationType) orientation;
566                     break;
567                   }
568                 (void) SetImageProperty(image,keyword,options,exception);
569                 break;
570               }
571               case 'p':
572               case 'P':
573               {
574                 if (LocaleCompare(keyword,"page") == 0)
575                   {
576                     char
577                       *geometry;
578
579                     geometry=GetPageGeometry(options);
580                     (void) ParseAbsoluteGeometry(geometry,&image->page);
581                     geometry=DestroyString(geometry);
582                     break;
583                   }
584                 if ((LocaleNCompare(keyword,"profile:",8) == 0) ||
585                     (LocaleNCompare(keyword,"profile-",8) == 0))
586                   {
587                     if (profiles == (LinkedListInfo *) NULL)
588                       profiles=NewLinkedList(0);
589                     (void) AppendValueToLinkedList(profiles,
590                       AcquireString(keyword+8));
591                     profile=BlobToStringInfo((const void *) NULL,(size_t)
592                       StringToLong(options));
593                     if (profile == (StringInfo *) NULL)
594                       ThrowReaderException(ResourceLimitError,
595                         "MemoryAllocationFailed");
596                     (void) SetImageProfile(image,keyword+8,profile,exception);
597                     profile=DestroyStringInfo(profile);
598                     break;
599                   }
600                 (void) SetImageProperty(image,keyword,options,exception);
601                 break;
602               }
603               case 'q':
604               case 'Q':
605               {
606                 if (LocaleCompare(keyword,"quality") == 0)
607                   {
608                     image->quality=StringToUnsignedLong(options);
609                     break;
610                   }
611                 (void) SetImageProperty(image,keyword,options,exception);
612                 break;
613               }
614               case 'r':
615               case 'R':
616               {
617                 if (LocaleCompare(keyword,"red-primary") == 0)
618                   {
619                     flags=ParseGeometry(options,&geometry_info);
620                     image->chromaticity.red_primary.x=geometry_info.rho;
621                     if ((flags & SigmaValue) != 0)
622                       image->chromaticity.red_primary.y=geometry_info.sigma;
623                     break;
624                   }
625                 if (LocaleCompare(keyword,"rendering-intent") == 0)
626                   {
627                     ssize_t
628                       rendering_intent;
629
630                     rendering_intent=ParseCommandOption(MagickIntentOptions,
631                       MagickFalse,options);
632                     if (rendering_intent < 0)
633                       break;
634                     image->rendering_intent=(RenderingIntent) rendering_intent;
635                     break;
636                   }
637                 if (LocaleCompare(keyword,"resolution") == 0)
638                   {
639                     flags=ParseGeometry(options,&geometry_info);
640                     image->resolution.x=geometry_info.rho;
641                     image->resolution.y=geometry_info.sigma;
642                     if ((flags & SigmaValue) == 0)
643                       image->resolution.y=image->resolution.x;
644                     break;
645                   }
646                 if (LocaleCompare(keyword,"rows") == 0)
647                   {
648                     image->rows=StringToUnsignedLong(options);
649                     break;
650                   }
651                 (void) SetImageProperty(image,keyword,options,exception);
652                 break;
653               }
654               case 's':
655               case 'S':
656               {
657                 if (LocaleCompare(keyword,"scene") == 0)
658                   {
659                     image->scene=StringToUnsignedLong(options);
660                     break;
661                   }
662                 if (LocaleCompare(keyword,"signature") == 0)
663                   {
664                     signature=(unsigned int) StringToUnsignedLong(options);
665                     break;
666                   }
667                 (void) SetImageProperty(image,keyword,options,exception);
668                 break;
669               }
670               case 't':
671               case 'T':
672               {
673                 if (LocaleCompare(keyword,"ticks-per-second") == 0)
674                   {
675                     image->ticks_per_second=(ssize_t) StringToLong(options);
676                     break;
677                   }
678                 if (LocaleCompare(keyword,"tile-offset") == 0)
679                   {
680                     char
681                       *geometry;
682
683                     geometry=GetPageGeometry(options);
684                     (void) ParseAbsoluteGeometry(geometry,&image->tile_offset);
685                     geometry=DestroyString(geometry);
686                   }
687                 if (LocaleCompare(keyword,"type") == 0)
688                   {
689                     ssize_t
690                       type;
691
692                     type=ParseCommandOption(MagickTypeOptions,MagickFalse,
693                       options);
694                     if (type < 0)
695                       break;
696                     image->type=(ImageType) type;
697                     break;
698                   }
699                 (void) SetImageProperty(image,keyword,options,exception);
700                 break;
701               }
702               case 'u':
703               case 'U':
704               {
705                 if (LocaleCompare(keyword,"units") == 0)
706                   {
707                     ssize_t
708                       units;
709
710                     units=ParseCommandOption(MagickResolutionOptions,
711                       MagickFalse,options);
712                     if (units < 0)
713                       break;
714                     image->units=(ResolutionType) units;
715                     break;
716                   }
717                 (void) SetImageProperty(image,keyword,options,exception);
718                 break;
719               }
720               case 'w':
721               case 'W':
722               {
723                 if (LocaleCompare(keyword,"white-point") == 0)
724                   {
725                     flags=ParseGeometry(options,&geometry_info);
726                     image->chromaticity.white_point.x=geometry_info.rho;
727                     image->chromaticity.white_point.y=geometry_info.sigma;
728                     if ((flags & SigmaValue) == 0)
729                       image->chromaticity.white_point.y=
730                         image->chromaticity.white_point.x;
731                     break;
732                   }
733                 (void) SetImageProperty(image,keyword,options,exception);
734                 break;
735               }
736               default:
737               {
738                 (void) SetImageProperty(image,keyword,options,exception);
739                 break;
740               }
741             }
742           }
743         else
744           c=ReadBlobByte(image);
745       while (isspace((int) ((unsigned char) c)) != 0)
746         c=ReadBlobByte(image);
747     }
748     options=DestroyString(options);
749     (void) ReadBlobByte(image);
750     /*
751       Verify that required image information is defined.
752     */
753     if ((LocaleCompare(id,"MagickCache") != 0) ||
754         (image->storage_class == UndefinedClass) ||
755         (image->compression == UndefinedCompression) || (image->columns == 0) ||
756         (image->rows == 0))
757       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
758     if (signature != GetMagickSignature((const StringInfo *) NULL))
759       ThrowReaderException(CacheError,"IncompatibleAPI");
760     if (image->montage != (char *) NULL)
761       {
762         register char
763           *p;
764
765         /*
766           Image directory.
767         */
768         length=MaxTextExtent;
769         image->directory=AcquireString((char *) NULL);
770         p=image->directory;
771         do
772         {
773           *p='\0';
774           if ((strlen(image->directory)+MaxTextExtent) >= length)
775             {
776               /*
777                 Allocate more memory for the image directory.
778               */
779               length<<=1;
780               image->directory=(char *) ResizeQuantumMemory(image->directory,
781                 length+MaxTextExtent,sizeof(*image->directory));
782               if (image->directory == (char *) NULL)
783                 ThrowReaderException(CorruptImageError,"UnableToReadImageData");
784               p=image->directory+strlen(image->directory);
785             }
786           c=ReadBlobByte(image);
787           *p++=(char) c;
788         } while (c != (int) '\0');
789       }
790     if (profiles != (LinkedListInfo *) NULL)
791       {
792         const char
793           *name;
794
795         const StringInfo
796           *profile;
797
798         register unsigned char
799           *p;
800
801         /*
802           Read image profiles.
803         */
804         ResetLinkedListIterator(profiles);
805         name=(const char *) GetNextValueInLinkedList(profiles);
806         while (name != (const char *) NULL)
807         {
808           profile=GetImageProfile(image,name);
809           if (profile != (StringInfo *) NULL)
810             {
811               p=GetStringInfoDatum(profile);
812               count=ReadBlob(image,GetStringInfoLength(profile),p);
813             }
814           name=(const char *) GetNextValueInLinkedList(profiles);
815         }
816         profiles=DestroyLinkedList(profiles,RelinquishMagickMemory);
817       }
818     depth=GetImageQuantumDepth(image,MagickFalse);
819     if (image->storage_class == PseudoClass)
820       {
821         /*
822           Create image colormap.
823         */
824         if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
825           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
826         if (image->colors != 0)
827           {
828             size_t
829               packet_size;
830
831             unsigned char
832               *colormap;
833
834             /*
835               Read image colormap from file.
836             */
837             packet_size=(size_t) (3UL*depth/8UL);
838             colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
839               packet_size*sizeof(*colormap));
840             if (colormap == (unsigned char *) NULL)
841               ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
842             count=ReadBlob(image,packet_size*image->colors,colormap);
843             if (count != (ssize_t) (packet_size*image->colors))
844               ThrowReaderException(CorruptImageError,
845                 "InsufficientImageDataInFile");
846             p=colormap;
847             switch (depth)
848             {
849               default:
850                 ThrowReaderException(CorruptImageError,
851                   "ImageDepthNotSupported");
852               case 8:
853               {
854                 unsigned char
855                   pixel;
856
857                 for (i=0; i < (ssize_t) image->colors; i++)
858                 {
859                   p=PushCharPixel(p,&pixel);
860                   image->colormap[i].red=ScaleCharToQuantum(pixel);
861                   p=PushCharPixel(p,&pixel);
862                   image->colormap[i].green=ScaleCharToQuantum(pixel);
863                   p=PushCharPixel(p,&pixel);
864                   image->colormap[i].blue=ScaleCharToQuantum(pixel);
865                 }
866                 break;
867               }
868               case 16:
869               {
870                 unsigned short
871                   pixel;
872
873                 for (i=0; i < (ssize_t) image->colors; i++)
874                 {
875                   p=PushShortPixel(MSBEndian,p,&pixel);
876                   image->colormap[i].red=ScaleShortToQuantum(pixel);
877                   p=PushShortPixel(MSBEndian,p,&pixel);
878                   image->colormap[i].green=ScaleShortToQuantum(pixel);
879                   p=PushShortPixel(MSBEndian,p,&pixel);
880                   image->colormap[i].blue=ScaleShortToQuantum(pixel);
881                 }
882                 break;
883               }
884               case 32:
885               {
886                 unsigned int
887                   pixel;
888
889                 for (i=0; i < (ssize_t) image->colors; i++)
890                 {
891                   p=PushLongPixel(MSBEndian,p,&pixel);
892                   image->colormap[i].red=ScaleLongToQuantum(pixel);
893                   p=PushLongPixel(MSBEndian,p,&pixel);
894                   image->colormap[i].green=ScaleLongToQuantum(pixel);
895                   p=PushLongPixel(MSBEndian,p,&pixel);
896                   image->colormap[i].blue=ScaleLongToQuantum(pixel);
897                 }
898                 break;
899               }
900             }
901             colormap=(unsigned char *) RelinquishMagickMemory(colormap);
902           }
903       }
904     if (EOFBlob(image) != MagickFalse)
905       {
906         ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
907           image->filename);
908         break;
909       }
910     if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
911       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
912         break;
913     /*
914       Attach persistent pixel cache.
915     */
916     status=PersistPixelCache(image,cache_filename,MagickTrue,&offset,exception);
917     if (status == MagickFalse)
918       ThrowReaderException(CacheError,"UnableToPersistPixelCache");
919     /*
920       Proceed to next image.
921     */
922     do
923     {
924       c=ReadBlobByte(image);
925     } while ((isgraph(c) == MagickFalse) && (c != EOF));
926     if (c != EOF)
927       {
928         /*
929           Allocate next image structure.
930         */
931         AcquireNextImage(image_info,image,exception);
932         if (GetNextImageInList(image) == (Image *) NULL)
933           {
934             image=DestroyImageList(image);
935             return((Image *) NULL);
936           }
937         image=SyncNextImageInList(image);
938         status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
939           GetBlobSize(image));
940         if (status == MagickFalse)
941           break;
942       }
943   } while (c != EOF);
944   (void) CloseBlob(image);
945   return(GetFirstImageInList(image));
946 }
947 \f
948 /*
949 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
950 %                                                                             %
951 %                                                                             %
952 %                                                                             %
953 %   R e g i s t e r M P C I m a g e                                           %
954 %                                                                             %
955 %                                                                             %
956 %                                                                             %
957 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
958 %
959 %  RegisterMPCImage() adds properties for the Cache image format to
960 %  the list of supported formats.  The properties include the image format
961 %  tag, a method to read and/or write the format, whether the format
962 %  supports the saving of more than one frame to the same file or blob,
963 %  whether the format supports native in-memory I/O, and a brief
964 %  description of the format.
965 %
966 %  The format of the RegisterMPCImage method is:
967 %
968 %      size_t RegisterMPCImage(void)
969 %
970 */
971 ModuleExport size_t RegisterMPCImage(void)
972 {
973   MagickInfo
974     *entry;
975
976   entry=SetMagickInfo("CACHE");
977   entry->description=ConstantString("Magick Persistent Cache image format");
978   entry->module=ConstantString("CACHE");
979   entry->stealth=MagickTrue;
980   (void) RegisterMagickInfo(entry);
981   entry=SetMagickInfo("MPC");
982   entry->decoder=(DecodeImageHandler *) ReadMPCImage;
983   entry->encoder=(EncodeImageHandler *) WriteMPCImage;
984   entry->magick=(IsImageFormatHandler *) IsMPC;
985   entry->description=ConstantString("Magick Persistent Cache image format");
986   entry->module=ConstantString("MPC");
987   (void) RegisterMagickInfo(entry);
988   return(MagickImageCoderSignature);
989 }
990 \f
991 /*
992 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
993 %                                                                             %
994 %                                                                             %
995 %                                                                             %
996 %   U n r e g i s t e r M P C I m a g e                                       %
997 %                                                                             %
998 %                                                                             %
999 %                                                                             %
1000 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1001 %
1002 %  UnregisterMPCImage() removes format registrations made by the
1003 %  MPC module from the list of supported formats.
1004 %
1005 %  The format of the UnregisterMPCImage method is:
1006 %
1007 %      UnregisterMPCImage(void)
1008 %
1009 */
1010 ModuleExport void UnregisterMPCImage(void)
1011 {
1012   (void) UnregisterMagickInfo("CACHE");
1013   (void) UnregisterMagickInfo("MPC");
1014 }
1015 \f
1016 /*
1017 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1018 %                                                                             %
1019 %                                                                             %
1020 %                                                                             %
1021 %   W r i t e M P C I m a g e                                                 %
1022 %                                                                             %
1023 %                                                                             %
1024 %                                                                             %
1025 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1026 %
1027 %  WriteMPCImage() writes an Magick Persistent Cache image to a file.
1028 %
1029 %  The format of the WriteMPCImage method is:
1030 %
1031 %      MagickBooleanType WriteMPCImage(const ImageInfo *image_info,
1032 %        Image *image,ExceptionInfo *exception)
1033 %
1034 %  A description of each parameter follows:
1035 %
1036 %    o image_info: the image info.
1037 %
1038 %    o image: the image.
1039 %
1040 %    o exception: return any errors or warnings in this structure.
1041 %
1042 */
1043 static MagickBooleanType WriteMPCImage(const ImageInfo *image_info,Image *image,
1044   ExceptionInfo *exception)
1045 {
1046   char
1047     buffer[MaxTextExtent],
1048     cache_filename[MaxTextExtent];
1049
1050   const char
1051     *property,
1052     *value;
1053
1054   MagickBooleanType
1055     status;
1056
1057   MagickOffsetType
1058     offset,
1059     scene;
1060
1061   register ssize_t
1062     i;
1063
1064   size_t
1065     depth,
1066     one;
1067
1068   /*
1069     Open persistent cache.
1070   */
1071   assert(image_info != (const ImageInfo *) NULL);
1072   assert(image_info->signature == MagickSignature);
1073   assert(image != (Image *) NULL);
1074   assert(image->signature == MagickSignature);
1075   if (image->debug != MagickFalse)
1076     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1077   assert(exception != (ExceptionInfo *) NULL);
1078   assert(exception->signature == MagickSignature);
1079   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1080   if (status == MagickFalse)
1081     return(status);
1082   (void) CopyMagickString(cache_filename,image->filename,MaxTextExtent);
1083   AppendImageFormat("cache",cache_filename);
1084   scene=0;
1085   offset=0;
1086   one=1;
1087   do
1088   {
1089     /*
1090       Write persistent cache meta-information.
1091     */
1092     depth=GetImageQuantumDepth(image,MagickTrue);
1093     if ((image->storage_class == PseudoClass) &&
1094         (image->colors > (one << depth)))
1095       image->storage_class=DirectClass;
1096     (void) WriteBlobString(image,"id=MagickCache\n");
1097     (void) FormatLocaleString(buffer,MaxTextExtent,"signature=%u\n",
1098       GetMagickSignature((const StringInfo *) NULL));
1099     (void) WriteBlobString(image,buffer);
1100     (void) FormatLocaleString(buffer,MaxTextExtent,
1101       "class=%s  colors=%.20g  alpha-trait=%s\n",CommandOptionToMnemonic(
1102       MagickClassOptions,image->storage_class),(double) image->colors,
1103       CommandOptionToMnemonic(MagickPixelTraitOptions,(ssize_t)
1104       image->alpha_trait));
1105     (void) WriteBlobString(image,buffer);
1106     (void) FormatLocaleString(buffer,MaxTextExtent,
1107       "columns=%.20g  rows=%.20g depth=%.20g\n",(double) image->columns,
1108       (double) image->rows,(double) image->depth);
1109     (void) WriteBlobString(image,buffer);
1110     if (image->type != UndefinedType)
1111       {
1112         (void) FormatLocaleString(buffer,MaxTextExtent,"type=%s\n",
1113           CommandOptionToMnemonic(MagickTypeOptions,image->type));
1114         (void) WriteBlobString(image,buffer);
1115       }
1116     if (image->colorspace != UndefinedColorspace)
1117       {
1118         (void) FormatLocaleString(buffer,MaxTextExtent,"colorspace=%s\n",
1119           CommandOptionToMnemonic(MagickColorspaceOptions,image->colorspace));
1120         (void) WriteBlobString(image,buffer);
1121       }
1122     if (image->endian != UndefinedEndian)
1123       {
1124         (void) FormatLocaleString(buffer,MaxTextExtent,"endian=%s\n",
1125           CommandOptionToMnemonic(MagickEndianOptions,image->endian));
1126         (void) WriteBlobString(image,buffer);
1127       }
1128     if (image->compression != UndefinedCompression)
1129       {
1130         (void) FormatLocaleString(buffer,MaxTextExtent,
1131           "compression=%s  quality=%.20g\n",CommandOptionToMnemonic(
1132           MagickCompressOptions,image->compression),(double) image->quality);
1133         (void) WriteBlobString(image,buffer);
1134       }
1135     if (image->units != UndefinedResolution)
1136       {
1137         (void) FormatLocaleString(buffer,MaxTextExtent,"units=%s\n",
1138           CommandOptionToMnemonic(MagickResolutionOptions,image->units));
1139         (void) WriteBlobString(image,buffer);
1140       }
1141     if ((image->resolution.x != 0) || (image->resolution.y != 0))
1142       {
1143         (void) FormatLocaleString(buffer,MaxTextExtent,
1144           "resolution=%gx%g\n",image->resolution.x,image->resolution.y);
1145         (void) WriteBlobString(image,buffer);
1146       }
1147     if ((image->page.width != 0) || (image->page.height != 0))
1148       {
1149         (void) FormatLocaleString(buffer,MaxTextExtent,
1150           "page=%.20gx%.20g%+.20g%+.20g\n",(double) image->page.width,(double)
1151           image->page.height,(double) image->page.x,(double) image->page.y);
1152         (void) WriteBlobString(image,buffer);
1153       }
1154     else
1155       if ((image->page.x != 0) || (image->page.y != 0))
1156         {
1157           (void) FormatLocaleString(buffer,MaxTextExtent,"page=%+ld%+ld\n",
1158             (long) image->page.x,(long) image->page.y);
1159           (void) WriteBlobString(image,buffer);
1160         }
1161     if ((image->page.x != 0) || (image->page.y != 0))
1162       {
1163         (void) FormatLocaleString(buffer,MaxTextExtent,"tile-offset=%+ld%+ld\n",
1164           (long) image->tile_offset.x,(long) image->tile_offset.y);
1165         (void) WriteBlobString(image,buffer);
1166       }
1167     if ((GetNextImageInList(image) != (Image *) NULL) ||
1168         (GetPreviousImageInList(image) != (Image *) NULL))
1169       {
1170         if (image->scene == 0)
1171           (void) FormatLocaleString(buffer,MaxTextExtent,
1172             "iterations=%.20g  delay=%.20g  ticks-per-second=%.20g\n",(double)
1173             image->iterations,(double) image->delay,(double)
1174             image->ticks_per_second);
1175         else
1176           (void) FormatLocaleString(buffer,MaxTextExtent,"scene=%.20g  "
1177             "iterations=%.20g  delay=%.20g  ticks-per-second=%.20g\n",
1178             (double) image->scene,(double) image->iterations,(double)
1179             image->delay,(double) image->ticks_per_second);
1180         (void) WriteBlobString(image,buffer);
1181       }
1182     else
1183       {
1184         if (image->scene != 0)
1185           {
1186             (void) FormatLocaleString(buffer,MaxTextExtent,"scene=%.20g\n",
1187               (double) image->scene);
1188             (void) WriteBlobString(image,buffer);
1189           }
1190         if (image->iterations != 0)
1191           {
1192             (void) FormatLocaleString(buffer,MaxTextExtent,"iterations=%.20g\n",
1193               (double) image->iterations);
1194             (void) WriteBlobString(image,buffer);
1195           }
1196         if (image->delay != 0)
1197           {
1198             (void) FormatLocaleString(buffer,MaxTextExtent,"delay=%.20g\n",
1199               (double) image->delay);
1200             (void) WriteBlobString(image,buffer);
1201           }
1202         if (image->ticks_per_second != UndefinedTicksPerSecond)
1203           {
1204             (void) FormatLocaleString(buffer,MaxTextExtent,
1205               "ticks-per-second=%.20g\n",(double) image->ticks_per_second);
1206             (void) WriteBlobString(image,buffer);
1207           }
1208       }
1209     if (image->gravity != UndefinedGravity)
1210       {
1211         (void) FormatLocaleString(buffer,MaxTextExtent,"gravity=%s\n",
1212           CommandOptionToMnemonic(MagickGravityOptions,image->gravity));
1213         (void) WriteBlobString(image,buffer);
1214       }
1215     if (image->dispose != UndefinedDispose)
1216       {
1217         (void) FormatLocaleString(buffer,MaxTextExtent,"dispose=%s\n",
1218           CommandOptionToMnemonic(MagickDisposeOptions,image->dispose));
1219         (void) WriteBlobString(image,buffer);
1220       }
1221     if (image->rendering_intent != UndefinedIntent)
1222       {
1223         (void) FormatLocaleString(buffer,MaxTextExtent,
1224           "rendering-intent=%s\n",CommandOptionToMnemonic(MagickIntentOptions,
1225           image->rendering_intent));
1226         (void) WriteBlobString(image,buffer);
1227       }
1228     if (image->gamma != 0.0)
1229       {
1230         (void) FormatLocaleString(buffer,MaxTextExtent,"gamma=%g\n",
1231           image->gamma);
1232         (void) WriteBlobString(image,buffer);
1233       }
1234     if (image->chromaticity.white_point.x != 0.0)
1235       {
1236         /*
1237           Note chomaticity points.
1238         */
1239         (void) FormatLocaleString(buffer,MaxTextExtent,"red-primary="
1240           "%g,%g  green-primary=%g,%g  blue-primary=%g,%g\n",
1241           image->chromaticity.red_primary.x,image->chromaticity.red_primary.y,
1242           image->chromaticity.green_primary.x,
1243           image->chromaticity.green_primary.y,
1244           image->chromaticity.blue_primary.x,
1245           image->chromaticity.blue_primary.y);
1246         (void) WriteBlobString(image,buffer);
1247         (void) FormatLocaleString(buffer,MaxTextExtent,
1248           "white-point=%g,%g\n",image->chromaticity.white_point.x,
1249           image->chromaticity.white_point.y);
1250         (void) WriteBlobString(image,buffer);
1251       }
1252     if (image->orientation != UndefinedOrientation)
1253       {
1254         (void) FormatLocaleString(buffer,MaxTextExtent,
1255           "orientation=%s\n",CommandOptionToMnemonic(MagickOrientationOptions,
1256           image->orientation));
1257         (void) WriteBlobString(image,buffer);
1258       }
1259     if (image->profiles != (void *) NULL)
1260       {
1261         const char
1262           *name;
1263
1264         const StringInfo
1265           *profile;
1266
1267         /*
1268           Generic profile.
1269         */
1270         ResetImageProfileIterator(image);
1271         for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1272         {
1273           profile=GetImageProfile(image,name);
1274           if (profile != (StringInfo *) NULL)
1275             {
1276               (void) FormatLocaleString(buffer,MaxTextExtent,
1277                 "profile:%s=%.20g\n",name,(double)
1278                 GetStringInfoLength(profile));
1279               (void) WriteBlobString(image,buffer);
1280             }
1281           name=GetNextImageProfile(image);
1282         }
1283       }
1284     if (image->montage != (char *) NULL)
1285       {
1286         (void) FormatLocaleString(buffer,MaxTextExtent,"montage=%s\n",
1287           image->montage);
1288         (void) WriteBlobString(image,buffer);
1289       }
1290     ResetImagePropertyIterator(image);
1291     property=GetNextImageProperty(image);
1292     while (property != (const char *) NULL)
1293     {
1294       (void) FormatLocaleString(buffer,MaxTextExtent,"%s=",property);
1295       (void) WriteBlobString(image,buffer);
1296       value=GetImageProperty(image,property,exception);
1297       if (value != (const char *) NULL)
1298         {
1299           size_t
1300             length;
1301
1302           length=strlen(value);
1303           for (i=0; i < (ssize_t) length; i++)
1304             if (isspace((int) ((unsigned char) value[i])) != 0)
1305               break;
1306           if (i == (ssize_t) length)
1307             (void) WriteBlob(image,length,(const unsigned char *) value);
1308           else
1309             {
1310               (void) WriteBlobByte(image,'{');
1311               if (strchr(value,'}') == (char *) NULL)
1312                 (void) WriteBlob(image,length,(const unsigned char *) value);
1313               else
1314                 for (i=0; i < (ssize_t) length; i++)
1315                 {
1316                   if (value[i] == (int) '}')
1317                     (void) WriteBlobByte(image,'\\');
1318                   (void) WriteBlobByte(image,value[i]);
1319                 }
1320               (void) WriteBlobByte(image,'}');
1321             }
1322         }
1323       (void) WriteBlobByte(image,'\n');
1324       property=GetNextImageProperty(image);
1325     }
1326     ResetImageArtifactIterator(image);
1327     (void) WriteBlobString(image,"\f\n:\032");
1328     if (image->montage != (char *) NULL)
1329       {
1330         /*
1331           Write montage tile directory.
1332         */
1333         if (image->directory != (char *) NULL)
1334           (void) WriteBlobString(image,image->directory);
1335         (void) WriteBlobByte(image,'\0');
1336       }
1337     if (image->profiles != 0)
1338       {
1339         const char
1340           *name;
1341
1342         const StringInfo
1343           *profile;
1344
1345         /*
1346           Write image profiles.
1347         */
1348         ResetImageProfileIterator(image);
1349         name=GetNextImageProfile(image);
1350         while (name != (const char *) NULL)
1351         {
1352           profile=GetImageProfile(image,name);
1353           (void) WriteBlob(image,GetStringInfoLength(profile),
1354             GetStringInfoDatum(profile));
1355           name=GetNextImageProfile(image);
1356         }
1357       }
1358     if (image->storage_class == PseudoClass)
1359       {
1360         size_t
1361           packet_size;
1362
1363         unsigned char
1364           *colormap,
1365           *q;
1366
1367         /*
1368           Allocate colormap.
1369         */
1370         packet_size=(size_t) (3UL*depth/8UL);
1371         colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
1372           packet_size*sizeof(*colormap));
1373         if (colormap == (unsigned char *) NULL)
1374           return(MagickFalse);
1375         /*
1376           Write colormap to file.
1377         */
1378         q=colormap;
1379         for (i=0; i < (ssize_t) image->colors; i++)
1380         {
1381           switch (depth)
1382           {
1383             default:
1384               ThrowWriterException(CorruptImageError,"ImageDepthNotSupported");
1385             case 32:
1386             {
1387               unsigned int
1388                 pixel;
1389
1390               pixel=ScaleQuantumToLong(image->colormap[i].red);
1391               q=PopLongPixel(MSBEndian,pixel,q);
1392               pixel=ScaleQuantumToLong(image->colormap[i].green);
1393               q=PopLongPixel(MSBEndian,pixel,q);
1394               pixel=ScaleQuantumToLong(image->colormap[i].blue);
1395               q=PopLongPixel(MSBEndian,pixel,q);
1396             }
1397             case 16:
1398             {
1399               unsigned short
1400                 pixel;
1401
1402               pixel=ScaleQuantumToShort(image->colormap[i].red);
1403               q=PopShortPixel(MSBEndian,pixel,q);
1404               pixel=ScaleQuantumToShort(image->colormap[i].green);
1405               q=PopShortPixel(MSBEndian,pixel,q);
1406               pixel=ScaleQuantumToShort(image->colormap[i].blue);
1407               q=PopShortPixel(MSBEndian,pixel,q);
1408               break;
1409             }
1410             case 8:
1411             {
1412               unsigned char
1413                 pixel;
1414
1415               pixel=(unsigned char) ScaleQuantumToChar(image->colormap[i].red);
1416               q=PopCharPixel(pixel,q);
1417               pixel=(unsigned char) ScaleQuantumToChar(
1418                 image->colormap[i].green);
1419               q=PopCharPixel(pixel,q);
1420               pixel=(unsigned char) ScaleQuantumToChar(image->colormap[i].blue);
1421               q=PopCharPixel(pixel,q);
1422               break;
1423             }
1424           }
1425         }
1426         (void) WriteBlob(image,packet_size*image->colors,colormap);
1427         colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1428       }
1429     /*
1430       Initialize persistent pixel cache.
1431     */
1432     status=PersistPixelCache(image,cache_filename,MagickFalse,&offset,
1433       exception);
1434     if (status == MagickFalse)
1435       ThrowWriterException(CacheError,"UnableToPersistPixelCache");
1436     if (GetNextImageInList(image) == (Image *) NULL)
1437       break;
1438     image=SyncNextImageInList(image);
1439     if (image->progress_monitor != (MagickProgressMonitor) NULL)
1440       {
1441         status=image->progress_monitor(SaveImagesTag,scene,
1442           GetImageListLength(image),image->client_data);
1443         if (status == MagickFalse)
1444           break;
1445       }
1446     scene++;
1447   } while (image_info->adjoin != MagickFalse);
1448   (void) CloseBlob(image);
1449   return(status);
1450 }