root / ImageMagick / trunk / coders / mpc.c

Revision 12083, 47.0 kB (checked in by cristy, 6 weeks ago)
Line 
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-2008 ImageMagick Studio LLC, a non-profit organization      %
21%  dedicated to making software imaging solutions freely available.           %
22%                                                                             %
23%  You may not use this file except in compliance with the License.  You may  %
24%  obtain a copy of the License at                                            %
25%                                                                             %
26%    http://www.imagemagick.org/script/license.php                            %
27%                                                                             %
28%  Unless required by applicable law or agreed to in writing, software        %
29%  distributed under the License is distributed on an "AS IS" BASIS,          %
30%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31%  See the License for the specific language governing permissions and        %
32%  limitations under the License.                                             %
33%                                                                             %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41  Include declarations.
42*/
43#include "magick/studio.h"
44#include "magick/artifact.h"
45#include "magick/blob.h"
46#include "magick/blob-private.h"
47#include "magick/cache.h"
48#include "magick/color.h"
49#include "magick/color-private.h"
50#include "magick/constitute.h"
51#include "magick/exception.h"
52#include "magick/exception-private.h"
53#include "magick/geometry.h"
54#include "magick/hashmap.h"
55#include "magick/image.h"
56#include "magick/image-private.h"
57#include "magick/list.h"
58#include "magick/magick.h"
59#include "magick/memory_.h"
60#include "magick/monitor.h"
61#include "magick/monitor-private.h"
62#include "magick/option.h"
63#include "magick/profile.h"
64#include "magick/property.h"
65#include "magick/quantum-private.h"
66#include "magick/static.h"
67#include "magick/statistic.h"
68#include "magick/string_.h"
69#include "magick/module.h"
70#include "magick/utility.h"
71
72/*
73  Forward declarations.
74*/
75static MagickBooleanType
76  WriteMPCImage(const ImageInfo *,Image *);
77
78/*
79%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
80%                                                                             %
81%                                                                             %
82%                                                                             %
83%   I s M P C                                                                 %
84%                                                                             %
85%                                                                             %
86%                                                                             %
87%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
88%
89%  IsMPC() returns MagickTrue if the image format type, identified by the
90%  magick string, is an Magick Persistent Cache image.
91%
92%  The format of the IsMPC method is:
93%
94%      MagickBooleanType IsMPC(const unsigned char *magick,const size_t length)
95%
96%  A description of each parameter follows:
97%
98%    o magick: This string is generally the first few bytes of an image file
99%      or blob.
100%
101%    o length: Specifies the length of the magick string.
102%
103*/
104static MagickBooleanType IsMPC(const unsigned char *magick,const size_t length)
105{
106  if (length < 14)
107    return(MagickFalse);
108  if (LocaleNCompare((char *) magick,"id=MagickCache",14) == 0)
109    return(MagickTrue);
110  return(MagickFalse);
111}
112
113/*
114%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
115%                                                                             %
116%                                                                             %
117%                                                                             %
118%   R e a d C A C H E I m a g e                                               %
119%                                                                             %
120%                                                                             %
121%                                                                             %
122%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
123%
124%  ReadMPCImage() reads an Magick Persistent Cache image file and returns
125%  it.  It allocates the memory necessary for the new Image structure and
126%  returns a pointer to the new image.
127%
128%  The format of the ReadMPCImage method is:
129%
130%      Image *ReadMPCImage(const ImageInfo *image_info,ExceptionInfo *exception)
131%
132%  Decompression code contributed by Kyle Shorter.
133%
134%  A description of each parameter follows:
135%
136%    o image_info: the image info.
137%
138%    o exception: return any errors or warnings in this structure.
139%
140*/
141static Image *ReadMPCImage(const ImageInfo *image_info,ExceptionInfo *exception)
142{
143  char
144    cache_filename[MaxTextExtent],
145    id[MaxTextExtent],
146    keyword[MaxTextExtent],
147    *options;
148
149  const unsigned char
150    *p;
151
152  GeometryInfo
153    geometry_info;
154
155  Image
156    *image;
157
158  int
159    c;
160
161  LinkedListInfo
162    *profiles;
163
164  MagickBooleanType
165    status;
166
167  MagickOffsetType
168    offset;
169
170  MagickStatusType
171    flags;
172
173  register long
174    i;
175
176  size_t
177    length;
178
179  ssize_t
180    count;
181
182  StringInfo
183    *profile;
184
185  unsigned long
186    depth,
187    quantum_depth;
188
189  /*
190    Open image file.
191  */
192  assert(image_info != (const ImageInfo *) NULL);
193  assert(image_info->signature == MagickSignature);
194  if (image_info->debug != MagickFalse)
195    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
196      image_info->filename);
197  assert(exception != (ExceptionInfo *) NULL);
198  assert(exception->signature == MagickSignature);
199  image=AcquireImage(image_info);
200  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
201  if (status == MagickFalse)
202    {
203      image=DestroyImageList(image);
204      return((Image *) NULL);
205    }
206  (void) CopyMagickString(cache_filename,image->filename,MaxTextExtent);
207  AppendImageFormat("cache",cache_filename);
208  c=ReadBlobByte(image);
209  if (c == EOF)
210    {
211      image=DestroyImage(image);
212      return((Image *) NULL);
213    }
214  *id='\0';
215  (void) ResetMagickMemory(keyword,0,sizeof(keyword));
216  offset=0;
217  do
218  {
219    /*
220      Decode image header;  header terminates one character beyond a ':'.
221    */
222    profiles=(LinkedListInfo *) NULL;
223    length=MaxTextExtent;
224    options=AcquireString((char *) NULL);
225    quantum_depth=MAGICKCORE_QUANTUM_DEPTH;
226    image->depth=8;
227    image->compression=NoCompression;
228    while ((isgraph(c) != MagickFalse) && (c != (int) ':'))
229    {
230      register char
231        *p;
232
233      if (c == (int) '{')
234        {
235          char
236            *comment;
237
238          /*
239            Read comment-- any text between { }.
240          */
241          length=MaxTextExtent;
242          comment=AcquireString((char *) NULL);
243          for (p=comment; comment != (char *) NULL; p++)
244          {
245            c=ReadBlobByte(image);
246            if ((c == EOF) || (c == (int) '}'))
247              break;
248            if ((size_t) (p-comment+1) >= length)
249              {
250                *p='\0';
251                length<<=1;
252                comment=(char *) ResizeQuantumMemory(comment,length+
253                  MaxTextExtent,sizeof(*comment));
254                if (comment == (char *) NULL)
255                  break;
256                p=comment+strlen(comment);
257              }
258            *p=(char) c;
259          }
260          if (comment == (char *) NULL)
261            ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
262          *p='\0';
263          (void) SetImageProperty(image,"comment",comment);
264          comment=DestroyString(comment);
265          c=ReadBlobByte(image);
266        }
267      else
268        if (isalnum(c) != MagickFalse)
269          {
270            /*
271              Get the keyword.
272            */
273            p=keyword;
274            do
275            {
276              if (isspace((int) ((unsigned char) c)) != 0)
277                break;
278              if (c == (int) '=')
279                break;
280              if ((size_t) (p-keyword) < MaxTextExtent)
281                *p++=(char) c;
282              c=ReadBlobByte(image);
283            } while (c != EOF);
284            *p='\0';
285            p=options;
286            while (isspace((int) ((unsigned char) c)) != 0)
287              c=ReadBlobByte(image);
288            if (c == (int) '=')
289              {
290                /*
291                  Get the keyword value.
292                */
293                c=ReadBlobByte(image);
294                while ((c != (int) '}') && (c != EOF))
295                {
296                  if ((size_t) (p-options+1) >= length)
297                    {
298                      *p='\0';
299                      length<<=1;
300                      options=(char *) ResizeQuantumMemory(options,length+
301                        MaxTextExtent,sizeof(*options));
302                      if (options == (char *) NULL)
303                        break;
304                      p=options+strlen(options);
305                    }
306                  if (options == (char *) NULL)
307                    ThrowReaderException(ResourceLimitError,
308                      "MemoryAllocationFailed");
309                  *p++=(char) c;
310                  c=ReadBlobByte(image);
311                  if (*options != '{')
312                    if (isspace((int) ((unsigned char) c)) != 0)
313                      break;
314                }
315              }
316            *p='\0';
317            if (*options == '{')
318              (void) CopyMagickString(options,options+1,MaxTextExtent);
319            /*
320              Assign a value to the specified keyword.
321            */
322            switch (*keyword)
323            {
324              case 'b':
325              case 'B':
326              {
327                if (LocaleCompare(keyword,"background-color") == 0)
328                  {
329                    (void) QueryColorDatabase(options,&image->background_color,
330                      exception);
331                    break;
332                  }
333                if (LocaleCompare(keyword,"blue-primary") == 0)
334                  {
335                    flags=ParseGeometry(options,&geometry_info);
336                    image->chromaticity.blue_primary.x=geometry_info.rho;
337                    image->chromaticity.blue_primary.y=geometry_info.sigma;
338                    if ((flags & SigmaValue) == 0)
339                      image->chromaticity.blue_primary.y=
340                        image->chromaticity.blue_primary.x;
341                    break;
342                  }
343                if (LocaleCompare(keyword,"border-color") == 0)
344                  {
345                    (void) QueryColorDatabase(options,&image->border_color,
346                      exception);
347                    break;
348                  }
349                (void) SetImageProperty(image,keyword,options);
350                break;
351              }
352              case 'c':
353              case 'C':
354              {
355                if (LocaleCompare(keyword,"class") == 0)
356                  {
357                    image->storage_class=(ClassType)
358                      ParseMagickOption(MagickClassOptions,MagickFalse,options);
359                    break;
360                  }
361                if (LocaleCompare(keyword,"colors") == 0)
362                  {
363                    image->colors=(unsigned long) atol(options);
364                    break;
365                  }
366                if (LocaleCompare(keyword,"colorspace") == 0)
367                  {
368                    image->colorspace=(ColorspaceType) ParseMagickOption(
369                      MagickColorspaceOptions,MagickFalse,options);
370                    break;
371                  }
372                if (LocaleCompare(keyword,"compression") == 0)
373                  {
374                    image->compression=(CompressionType) ParseMagickOption(
375                      MagickCompressOptions,MagickFalse,options);
376                    break;
377                  }
378                if (LocaleCompare(keyword,"columns") == 0)
379                  {
380                    image->columns=(unsigned long) atol(options);
381                    break;
382                  }
383                (void) SetImageProperty(image,keyword,options);
384                break;
385              }
386              case 'd':
387              case 'D':
388              {
389                if (LocaleCompare(keyword,"delay") == 0)
390                  {
391                    image->delay=(unsigned long) atol(options);
392                    break;
393                  }
394                if (LocaleCompare(keyword,"depth") == 0)
395                  {
396                    image->depth=(unsigned long) atol(options);
397                    break;
398                  }
399                if (LocaleCompare(keyword,"dispose") == 0)
400                  {
401                    image->dispose=(DisposeType) ParseMagickOption(
402                      MagickDisposeOptions,MagickFalse,options);
403                    break;
404                  }
405                (void) SetImageProperty(image,keyword,options);
406                break;
407              }
408              case 'e':
409              case 'E':
410              {
411                if (LocaleCompare(keyword,"endian") == 0)
412                  {
413                    image->endian=(EndianType) ParseMagickOption(
414                      MagickEndianOptions,MagickFalse,options);
415                    break;
416                  }
417                if (LocaleCompare(keyword,"error") == 0)
418                  {
419                    image->error.mean_error_per_pixel=atof(options);
420                    break;
421                  }
422                (void) SetImageProperty(image,keyword,options);
423                break;
424              }
425              case 'g':
426              case 'G':
427              {
428                if (LocaleCompare(keyword,"gamma") == 0)
429                  {
430                    image->gamma=atof(options);
431                    break;
432                  }
433                if (LocaleCompare(keyword,"green-primary") == 0)
434                  {
435                    flags=ParseGeometry(options,&geometry_info);
436                    image->chromaticity.green_primary.x=geometry_info.rho;
437                    image->chromaticity.green_primary.y=geometry_info.sigma;
438                    if ((flags & SigmaValue) == 0)
439                      image->chromaticity.green_primary.y=
440                        image->chromaticity.green_primary.x;
441                    break;
442                  }
443                (void) SetImageProperty(image,keyword,options);
444                break;
445              }
446              case 'i':
447              case 'I':
448              {
449                if (LocaleCompare(keyword,"id") == 0)
450                  {
451                    (void) CopyMagickString(id,options,MaxTextExtent);
452                    break;
453                  }
454                if (LocaleCompare(keyword,"iterations") == 0)
455                  {
456                    image->iterations=(unsigned long) atol(options);
457                    break;
458                  }
459                (void) SetImageProperty(image,keyword,options);
460                break;
461              }
462              case 'm':
463              case 'M':
464              {
465                if (LocaleCompare(keyword,"matte") == 0)
466                  {
467                    image->matte=(MagickBooleanType) ParseMagickOption(
468                      MagickBooleanOptions,MagickFalse,options);
469                    break;
470                  }
471                if (LocaleCompare(keyword,"matte-color") == 0)
472                  {
473                    (void) QueryColorDatabase(options,&image->matte_color,
474                      exception);
475                    break;
476                  }
477                if (LocaleCompare(keyword,"maximum-error") == 0)
478                  {
479                    image->error.normalized_maximum_error=atof(options);
480                    break;
481                  }
482                if (LocaleCompare(keyword,"mean-error") == 0)
483                  {
484                    image->error.normalized_mean_error=atof(options);
485                    break;
486                  }
487                if (LocaleCompare(keyword,"montage") == 0)
488                  {
489                    (void) CloneString(&image->montage,options);
490                    break;
491                  }
492                (void) SetImageProperty(image,keyword,options);
493                break;
494              }
495              case 'o':
496              case 'O':
497              {
498                if (LocaleCompare(keyword,"opaque") == 0)
499                  {
500                    image->matte=(MagickBooleanType) ParseMagickOption(
501                      MagickBooleanOptions,MagickFalse,options);
502                    break;
503                  }
504                if (LocaleCompare(keyword,"orientation") == 0)
505                  {
506                    image->orientation=(OrientationType) ParseMagickOption(
507                      MagickOrientationOptions,MagickFalse,options);
508                    break;
509                  }
510                (void) SetImageProperty(image,keyword,options);
511                break;
512              }
513              case 'p':
514              case 'P':
515              {
516                if (LocaleCompare(keyword,"page") == 0)
517                  {
518                    char
519                      *geometry;
520
521                    geometry=GetPageGeometry(options);
522                    (void) ParseAbsoluteGeometry(geometry,&image->page);
523                    geometry=DestroyString(geometry);
524                    break;
525                  }
526                if (LocaleNCompare(keyword,"profile-",8) == 0)
527                  {
528                    if (profiles == (LinkedListInfo *) NULL)
529                      profiles=NewLinkedList(0);
530                    (void) AppendValueToLinkedList(profiles,
531                      AcquireString(keyword+8));
532                    profile=AcquireStringInfo((size_t) atol(options));
533                    (void) SetImageProfile(image,keyword+8,profile);
534                    profile=DestroyStringInfo(profile);
535                    break;
536                  }
537                (void) SetImageProperty(image,keyword,options);
538                break;
539              }
540              case 'q':
541              case 'Q':
542              {
543                if (LocaleCompare(keyword,"quality") == 0)
544                  {
545                    image->quality=(unsigned long) atol(options);
546                    break;
547                  }
548                if (LocaleCompare(keyword,"quantum-depth") == 0)
549                  {
550                    quantum_depth=(unsigned long) atol(options);
551                    break;
552                  }
553                (void) SetImageProperty(image,keyword,options);
554                break;
555              }
556              case 'r':
557              case 'R':
558              {
559                if (LocaleCompare(keyword,"red-primary") == 0)
560                  {
561                    flags=ParseGeometry(options,&geometry_info);
562                    image->chromaticity.red_primary.x=geometry_info.rho;
563                    if ((flags & SigmaValue) != 0)
564                      image->chromaticity.red_primary.y=geometry_info.sigma;
565                    break;
566                  }
567                if (LocaleCompare(keyword,"rendering-intent") == 0)
568                  {
569                    image->rendering_intent=(RenderingIntent) ParseMagickOption(
570                      MagickIntentOptions,MagickFalse,options);
571                    break;
572                  }
573                if (LocaleCompare(keyword,"resolution") == 0)
574                  {
575                    flags=ParseGeometry(options,&geometry_info);
576                    image->x_resolution=geometry_info.rho;
577                    image->y_resolution=geometry_info.sigma;
578                    if ((flags & SigmaValue) == 0)
579                      image->y_resolution=image->x_resolution;
580                    break;
581                  }
582                if (LocaleCompare(keyword,"rows") == 0)
583                  {
584                    image->rows=(unsigned long) atol(options);
585                    break;
586                  }
587                (void) SetImageProperty(image,keyword,options);
588                break;
589              }
590              case 's':
591              case 'S':
592              {
593                if (LocaleCompare(keyword,"scene") == 0)
594                  {
595                    image->scene=(unsigned long) atol(options);
596                    break;
597                  }
598                (void) SetImageProperty(image,keyword,options);
599                break;
600              }
601              case 't':
602              case 'T':
603              {
604                if (LocaleCompare(keyword,"ticks-per-second") == 0)
605                  {
606                    image->ticks_per_second=(long) atol(options);
607                    break;
608                  }
609                if (LocaleCompare(keyword,"tile-offset") == 0)
610                  {
611                    char
612                      *geometry;
613
614                    geometry=GetPageGeometry(options);
615                    (void) ParseAbsoluteGeometry(geometry,&image->tile_offset);
616                    geometry=DestroyString(geometry);
617                  }
618                if (LocaleCompare(keyword,"type") == 0)
619                  {
620                    image->type=(ImageType) ParseMagickOption(MagickTypeOptions,                      MagickFalse,options);
621                    break;
622                  }
623                (void) SetImageProperty(image,keyword,options);
624                break;
625              }
626              case 'u':
627              case 'U':
628              {
629                if (LocaleCompare(keyword,"units") == 0)
630                  {
631                    image->units=(ResolutionType) ParseMagickOption(
632                      MagickResolutionOptions,MagickFalse,options);
633                    break;
634                  }
635                (void) SetImageProperty(image,keyword,options);
636                break;
637              }
638              case 'w':
639              case 'W':
640              {
641                if (LocaleCompare(keyword,"white-point") == 0)
642                  {
643                    flags=ParseGeometry(options,&geometry_info);
644                    image->chromaticity.white_point.x=geometry_info.rho;
645                    image->chromaticity.white_point.y=geometry_info.sigma;
646                    if ((flags & SigmaValue) == 0)
647                      image->chromaticity.white_point.y=
648                        image->chromaticity.white_point.x;
649                    break;
650                  }
651                (void) SetImageProperty(image,keyword,options);
652                break;
653              }
654              default:
655              {
656                (void) SetImageProperty(image,keyword,options);
657                break;
658              }
659            }
660          }
661        else
662          c=ReadBlobByte(image);
663      while (isspace((int) ((unsigned char) c)) != 0)
664        c=ReadBlobByte(image);
665    }
666    options=DestroyString(options);
667    (void) ReadBlobByte(image);
668    /*
669      Verify that required image information is defined.
670    */
671    if ((LocaleCompare(id,"MagickCache") != 0) ||
672        (image->storage_class == UndefinedClass) ||
673        (image->compression == UndefinedCompression) || (image->columns == 0) ||
674        (image->rows == 0))
675      ThrowReaderException(CorruptImageError,"ImproperImageHeader");
676    if (quantum_depth != MAGICKCORE_QUANTUM_DEPTH)
677      ThrowReaderException(CacheError,"InconsistentPersistentCacheDepth");
678    if (image->montage != (char *) NULL)
679      {
680        register char
681          *p;
682
683        /*
684          Image directory.
685        */
686        length=MaxTextExtent;
687        image->directory=AcquireString((char *) NULL);
688        p=image->directory;
689        do
690        {
691          *p='\0';
692          if ((strlen(image->directory)+MaxTextExtent) >= length)
693            {
694              /*
695                Allocate more memory for the image directory.
696              */
697              length<<=1;
698              image->directory=(char *) ResizeQuantumMemory(image->directory,
699                length+MaxTextExtent,sizeof(*image->directory));
700              if (image->directory == (char *) NULL)
701                ThrowReaderException(CorruptImageError,"UnableToReadImageData");
702              p=image->directory+strlen(image->directory);
703            }
704          c=ReadBlobByte(image);
705          *p++=(char) c;
706        } while (c != (int) '\0');
707      }
708    if (profiles != (LinkedListInfo *) NULL)
709      {
710        const char
711          *name;
712
713        const StringInfo
714          *profile;
715
716        const unsigned char
717          *p;
718
719        /*
720          Read image profiles.
721        */
722        ResetLinkedListIterator(profiles);
723        name=(const char *) GetNextValueInLinkedList(profiles);
724        while (name != (const char *) NULL)
725        {
726          profile=GetImageProfile(image,name);
727          if (profile != (StringInfo *) NULL)
728            {
729              p=GetStringInfoDatum(profile);
730              count=ReadBlob(image,GetStringInfoLength(profile),
731                (unsigned char *) p);
732            }
733          name=(const char *) GetNextValueInLinkedList(profiles);
734        }
735        profiles=DestroyLinkedList(profiles,RelinquishMagickMemory);
736      }
737    depth=GetImageQuantumDepth(image,MagickFalse);
738    if (image->storage_class == PseudoClass)
739      {
740        /*
741          Create image colormap.
742        */
743        if (AcquireImageColormap(image,image->colors) == MagickFalse)
744          ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
745        if (image->colors != 0)
746          {
747            size_t
748              packet_size;
749
750            unsigned char
751              *colormap;
752
753            /*
754              Read image colormap from file.
755            */
756            packet_size=(size_t) (3UL*depth/8UL);
757            colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
758              packet_size*sizeof(*colormap));
759            if (colormap == (unsigned char *) NULL)
760              ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
761            count=ReadBlob(image,packet_size*image->colors,colormap);
762            if (count != (ssize_t) (packet_size*image->colors))
763              ThrowReaderException(CorruptImageError,
764                "InsufficientImageDataInFile");
765            p=colormap;
766            switch (depth)
767            {
768              default:
769                ThrowReaderException(CorruptImageError,
770                  "ImageDepthNotSupported");
771              case 8:
772              {
773                unsigned char
774                  pixel;
775
776                for (i=0; i < (long) image->colors; i++)
777                {
778                  p=PushCharPixel(p,&pixel);
779                  image->colormap[i].red=ScaleCharToQuantum(pixel);
780                  p=PushCharPixel(p,&pixel);
781                  image->colormap[i].green=ScaleCharToQuantum(pixel);
782                  p=PushCharPixel(p,&pixel);
783                  image->colormap[i].blue=ScaleCharToQuantum(pixel);
784                }
785                break;
786              }
787              case 16:
788              {
789                unsigned short
790                  pixel;
791
792                for (i=0; i < (long) image->colors; i++)
793                {
794                  p=PushShortPixel(MSBEndian,p,&pixel);
795                  image->colormap[i].red=ScaleShortToQuantum(pixel);
796                  p=PushShortPixel(MSBEndian,p,&pixel);
797                  image->colormap[i].green=ScaleShortToQuantum(pixel);
798                  p=PushShortPixel(MSBEndian,p,&pixel);
799                  image->colormap[i].blue=ScaleShortToQuantum(pixel);
800                }
801                break;
802              }
803              case 32:
804              {
805                unsigned long
806                  pixel;
807
808                for (i=0; i < (long) image->colors; i++)
809                {
810                  p=PushLongPixel(MSBEndian,p,&pixel);
811                  image->colormap[i].red=ScaleLongToQuantum(pixel);
812                  p=PushLongPixel(MSBEndian,p,&pixel);
813                  image->colormap[i].green=ScaleLongToQuantum(pixel);
814                  p=PushLongPixel(MSBEndian,p,&pixel);
815                  image->colormap[i].blue=ScaleLongToQuantum(pixel);
816                }
817                break;
818              }
819            }
820            colormap=(unsigned char *) RelinquishMagickMemory(colormap);
821          }
822      }
823    if (EOFBlob(image) != MagickFalse)
824      {
825        ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
826          image->filename);
827        break;
828      }
829    if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
830      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
831        break;
832    /*
833      Attach persistent pixel cache.
834    */
835    status=PersistCache(image,cache_filename,MagickTrue,&offset,exception);
836    if (status == MagickFalse)
837      ThrowReaderException(CacheError,"UnableToPersistPixelCache");
838    /*
839      Proceed to next image.
840    */
841    do
842    {
843      c=ReadBlobByte(image);
844    } while ((isgraph(c) == MagickFalse) && (c != EOF));
845    if (c != EOF)
846      {
847        /*
848          Allocate next image structure.
849        */
850        AcquireNextImage(image_info,image);
851        if (GetNextImageInList(image) == (Image *) NULL)
852          {
853            image=DestroyImageList(image);
854            return((Image *) NULL);
855          }
856        image=SyncNextImageInList(image);
857        status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
858          GetBlobSize(image));
859        if (status == MagickFalse)
860          break;
861      }
862  } while (c != EOF);
863  (void) CloseBlob(image);
864  return(GetFirstImageInList(image));
865}
866
867/*
868%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
869%                                                                             %
870%                                                                             %
871%                                                                             %
872%   R e g i s t e r M P C I m a g e                                           %
873%                                                                             %
874%                                                                             %
875%                                                                             %
876%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
877%
878%  RegisterMPCImage() adds properties for the Cache image format to
879%  the list of supported formats.  The properties include the image format
880%  tag, a method to read and/or write the format, whether the format
881%  supports the saving of more than one frame to the same file or blob,
882%  whether the format supports native in-memory I/O, and a brief
883%  description of the format.
884%
885%  The format of the RegisterMPCImage method is:
886%
887%      unsigned long RegisterMPCImage(void)
888%
889*/
890ModuleExport unsigned long RegisterMPCImage(void)
891{
892  MagickInfo
893    *entry;
894
895  entry=SetMagickInfo("CACHE");
896  entry->description=ConstantString("Magick Persistent Cache image format");
897  entry->module=ConstantString("CACHE");
898  entry->stealth=MagickTrue;
899  (void) RegisterMagickInfo(entry);
900  entry=SetMagickInfo("MPC");
901  entry->decoder=(DecodeImageHandler *) ReadMPCImage;
902  entry->encoder=(EncodeImageHandler *) WriteMPCImage;
903  entry->magick=(IsImageFormatHandler *) IsMPC;
904  entry->description=ConstantString("Magick Persistent Cache image format");
905  entry->module=ConstantString("MPC");
906  (void) RegisterMagickInfo(entry);
907  return(MagickImageCoderSignature);
908}
909
910/*
911%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
912%                                                                             %
913%                                                                             %
914%                                                                             %
915%   U n r e g i s t e r M P C I m a g e                                       %
916%                                                                             %
917%                                                                             %
918%                                                                             %
919%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
920%
921%  UnregisterMPCImage() removes format registrations made by the
922%  MPC module from the list of supported formats.
923%
924%  The format of the UnregisterMPCImage method is:
925%
926%      UnregisterMPCImage(void)
927%
928*/
929ModuleExport void UnregisterMPCImage(void)
930{
931  (void) UnregisterMagickInfo("CACHE");
932  (void) UnregisterMagickInfo("MPC");
933}
934
935/*
936%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
937%                                                                             %
938%                                                                             %
939