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