blob: a788536cf65ba77ede4c25620fc2654aad128463 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
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% %
cristy7e41fe82010-12-04 23:12:08 +000020% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% 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"
cristy5a2ca482009-10-14 18:24:56 +000045#include "magick/attribute.h"
cristy3ed852e2009-09-05 21:47:34 +000046#include "magick/blob.h"
47#include "magick/blob-private.h"
48#include "magick/cache.h"
49#include "magick/color.h"
50#include "magick/color-private.h"
cristye7e40552010-04-24 21:34:22 +000051#include "magick/colormap.h"
cristy3ed852e2009-09-05 21:47:34 +000052#include "magick/constitute.h"
53#include "magick/exception.h"
54#include "magick/exception-private.h"
55#include "magick/geometry.h"
56#include "magick/hashmap.h"
57#include "magick/image.h"
58#include "magick/image-private.h"
59#include "magick/list.h"
60#include "magick/magick.h"
61#include "magick/memory_.h"
cristyf2f27272009-12-17 14:48:46 +000062#include "magick/module.h"
cristy3ed852e2009-09-05 21:47:34 +000063#include "magick/monitor.h"
64#include "magick/monitor-private.h"
65#include "magick/option.h"
66#include "magick/profile.h"
67#include "magick/property.h"
68#include "magick/quantum-private.h"
69#include "magick/static.h"
70#include "magick/statistic.h"
71#include "magick/string_.h"
cristyf2f27272009-12-17 14:48:46 +000072#include "magick/string-private.h"
cristy3ed852e2009-09-05 21:47:34 +000073#include "magick/utility.h"
74
75/*
76 Forward declarations.
77*/
78static MagickBooleanType
79 WriteMPCImage(const ImageInfo *,Image *);
80
81/*
82%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
83% %
84% %
85% %
86% I s M P C %
87% %
88% %
89% %
90%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
91%
92% IsMPC() returns MagickTrue if the image format type, identified by the
93% magick string, is an Magick Persistent Cache image.
94%
95% The format of the IsMPC method is:
96%
97% MagickBooleanType IsMPC(const unsigned char *magick,const size_t length)
98%
99% A description of each parameter follows:
100%
101% o magick: compare image format pattern against these bytes.
102%
103% o length: Specifies the length of the magick string.
104%
105*/
106static MagickBooleanType IsMPC(const unsigned char *magick,const size_t length)
107{
108 if (length < 14)
109 return(MagickFalse);
110 if (LocaleNCompare((const char *) magick,"id=MagickCache",14) == 0)
111 return(MagickTrue);
112 return(MagickFalse);
113}
114
115/*
116%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
117% %
118% %
119% %
120% R e a d C A C H E I m a g e %
121% %
122% %
123% %
124%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
125%
126% ReadMPCImage() reads an Magick Persistent Cache image file and returns
127% it. It allocates the memory necessary for the new Image structure and
128% returns a pointer to the new image.
129%
130% The format of the ReadMPCImage method is:
131%
132% Image *ReadMPCImage(const ImageInfo *image_info,ExceptionInfo *exception)
133%
134% Decompression code contributed by Kyle Shorter.
135%
136% A description of each parameter follows:
137%
138% o image_info: the image info.
139%
140% o exception: return any errors or warnings in this structure.
141%
142*/
143static Image *ReadMPCImage(const ImageInfo *image_info,ExceptionInfo *exception)
144{
145 char
146 cache_filename[MaxTextExtent],
147 id[MaxTextExtent],
148 keyword[MaxTextExtent],
149 *options;
150
151 const unsigned char
152 *p;
153
154 GeometryInfo
155 geometry_info;
156
157 Image
158 *image;
159
160 int
161 c;
162
163 LinkedListInfo
164 *profiles;
165
166 MagickBooleanType
167 status;
168
169 MagickOffsetType
170 offset;
171
172 MagickStatusType
173 flags;
174
cristybb503372010-05-27 20:51:26 +0000175 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000176 i;
177
178 size_t
cristyaff6d802011-04-26 01:46:31 +0000179 depth,
180 length,
181 quantum_depth;
cristy3ed852e2009-09-05 21:47:34 +0000182
183 ssize_t
184 count;
185
186 StringInfo
187 *profile;
188
cristy3ed852e2009-09-05 21:47:34 +0000189 /*
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 {
cristy3ed852e2009-09-05 21:47:34 +0000276 if (c == (int) '=')
277 break;
278 if ((size_t) (p-keyword) < (MaxTextExtent-1))
279 *p++=(char) c;
280 c=ReadBlobByte(image);
281 } while (c != EOF);
282 *p='\0';
283 p=options;
284 while (isspace((int) ((unsigned char) c)) != 0)
285 c=ReadBlobByte(image);
286 if (c == (int) '=')
287 {
288 /*
289 Get the keyword value.
290 */
291 c=ReadBlobByte(image);
292 while ((c != (int) '}') && (c != EOF))
293 {
294 if ((size_t) (p-options+1) >= length)
295 {
296 *p='\0';
297 length<<=1;
298 options=(char *) ResizeQuantumMemory(options,length+
299 MaxTextExtent,sizeof(*options));
300 if (options == (char *) NULL)
301 break;
302 p=options+strlen(options);
303 }
304 if (options == (char *) NULL)
305 ThrowReaderException(ResourceLimitError,
306 "MemoryAllocationFailed");
307 *p++=(char) c;
308 c=ReadBlobByte(image);
309 if (*options != '{')
310 if (isspace((int) ((unsigned char) c)) != 0)
311 break;
312 }
313 }
314 *p='\0';
315 if (*options == '{')
316 (void) CopyMagickString(options,options+1,MaxTextExtent);
317 /*
318 Assign a value to the specified keyword.
319 */
320 switch (*keyword)
321 {
322 case 'b':
323 case 'B':
324 {
325 if (LocaleCompare(keyword,"background-color") == 0)
326 {
327 (void) QueryColorDatabase(options,&image->background_color,
328 exception);
329 break;
330 }
331 if (LocaleCompare(keyword,"blue-primary") == 0)
332 {
333 flags=ParseGeometry(options,&geometry_info);
334 image->chromaticity.blue_primary.x=geometry_info.rho;
335 image->chromaticity.blue_primary.y=geometry_info.sigma;
336 if ((flags & SigmaValue) == 0)
337 image->chromaticity.blue_primary.y=
338 image->chromaticity.blue_primary.x;
339 break;
340 }
341 if (LocaleCompare(keyword,"border-color") == 0)
342 {
343 (void) QueryColorDatabase(options,&image->border_color,
344 exception);
345 break;
346 }
347 (void) SetImageProperty(image,keyword,options);
348 break;
349 }
350 case 'c':
351 case 'C':
352 {
353 if (LocaleCompare(keyword,"class") == 0)
354 {
cristybb503372010-05-27 20:51:26 +0000355 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000356 storage_class;
357
cristy042ee782011-04-22 18:48:30 +0000358 storage_class=ParseCommandOption(MagickClassOptions,
cristy3ed852e2009-09-05 21:47:34 +0000359 MagickFalse,options);
360 if (storage_class < 0)
361 break;
362 image->storage_class=(ClassType) storage_class;
363 break;
364 }
365 if (LocaleCompare(keyword,"colors") == 0)
366 {
cristye27293e2009-12-18 02:53:20 +0000367 image->colors=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000368 break;
369 }
370 if (LocaleCompare(keyword,"colorspace") == 0)
371 {
cristybb503372010-05-27 20:51:26 +0000372 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000373 colorspace;
374
cristy042ee782011-04-22 18:48:30 +0000375 colorspace=ParseCommandOption(MagickColorspaceOptions,
cristy3ed852e2009-09-05 21:47:34 +0000376 MagickFalse,options);
377 if (colorspace < 0)
378 break;
379 image->colorspace=(ColorspaceType) colorspace;
380 break;
381 }
382 if (LocaleCompare(keyword,"compression") == 0)
383 {
cristybb503372010-05-27 20:51:26 +0000384 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000385 compression;
386
cristy042ee782011-04-22 18:48:30 +0000387 compression=ParseCommandOption(MagickCompressOptions,
cristy3ed852e2009-09-05 21:47:34 +0000388 MagickFalse,options);
389 if (compression < 0)
390 break;
391 image->compression=(CompressionType) compression;
392 break;
393 }
394 if (LocaleCompare(keyword,"columns") == 0)
395 {
cristye27293e2009-12-18 02:53:20 +0000396 image->columns=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000397 break;
398 }
399 (void) SetImageProperty(image,keyword,options);
400 break;
401 }
402 case 'd':
403 case 'D':
404 {
405 if (LocaleCompare(keyword,"delay") == 0)
406 {
cristye27293e2009-12-18 02:53:20 +0000407 image->delay=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000408 break;
409 }
410 if (LocaleCompare(keyword,"depth") == 0)
411 {
cristye27293e2009-12-18 02:53:20 +0000412 image->depth=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000413 break;
414 }
415 if (LocaleCompare(keyword,"dispose") == 0)
416 {
cristybb503372010-05-27 20:51:26 +0000417 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000418 dispose;
419
cristy042ee782011-04-22 18:48:30 +0000420 dispose=ParseCommandOption(MagickDisposeOptions,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000421 options);
422 if (dispose < 0)
423 break;
424 image->dispose=(DisposeType) dispose;
425 break;
426 }
427 (void) SetImageProperty(image,keyword,options);
428 break;
429 }
430 case 'e':
431 case 'E':
432 {
433 if (LocaleCompare(keyword,"endian") == 0)
434 {
cristybb503372010-05-27 20:51:26 +0000435 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000436 endian;
437
cristy042ee782011-04-22 18:48:30 +0000438 endian=ParseCommandOption(MagickEndianOptions,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000439 options);
440 if (endian < 0)
441 break;
442 image->endian=(EndianType) endian;
443 break;
444 }
445 if (LocaleCompare(keyword,"error") == 0)
446 {
cristyf2f27272009-12-17 14:48:46 +0000447 image->error.mean_error_per_pixel=StringToDouble(options);
cristy3ed852e2009-09-05 21:47:34 +0000448 break;
449 }
450 (void) SetImageProperty(image,keyword,options);
451 break;
452 }
453 case 'g':
454 case 'G':
455 {
456 if (LocaleCompare(keyword,"gamma") == 0)
457 {
cristyf2f27272009-12-17 14:48:46 +0000458 image->gamma=StringToDouble(options);
cristy3ed852e2009-09-05 21:47:34 +0000459 break;
460 }
461 if (LocaleCompare(keyword,"green-primary") == 0)
462 {
463 flags=ParseGeometry(options,&geometry_info);
464 image->chromaticity.green_primary.x=geometry_info.rho;
465 image->chromaticity.green_primary.y=geometry_info.sigma;
466 if ((flags & SigmaValue) == 0)
467 image->chromaticity.green_primary.y=
468 image->chromaticity.green_primary.x;
469 break;
470 }
471 (void) SetImageProperty(image,keyword,options);
472 break;
473 }
474 case 'i':
475 case 'I':
476 {
477 if (LocaleCompare(keyword,"id") == 0)
478 {
479 (void) CopyMagickString(id,options,MaxTextExtent);
480 break;
481 }
482 if (LocaleCompare(keyword,"iterations") == 0)
483 {
cristye27293e2009-12-18 02:53:20 +0000484 image->iterations=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000485 break;
486 }
487 (void) SetImageProperty(image,keyword,options);
488 break;
489 }
490 case 'm':
491 case 'M':
492 {
493 if (LocaleCompare(keyword,"matte") == 0)
494 {
cristybb503372010-05-27 20:51:26 +0000495 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000496 matte;
497
cristy042ee782011-04-22 18:48:30 +0000498 matte=ParseCommandOption(MagickBooleanOptions,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000499 options);
500 if (matte < 0)
501 break;
502 image->matte=(MagickBooleanType) matte;
503 break;
504 }
505 if (LocaleCompare(keyword,"matte-color") == 0)
506 {
507 (void) QueryColorDatabase(options,&image->matte_color,
508 exception);
509 break;
510 }
511 if (LocaleCompare(keyword,"maximum-error") == 0)
512 {
cristyaff6d802011-04-26 01:46:31 +0000513 image->error.normalized_maximum_error=
514 StringToDouble(options);
cristy3ed852e2009-09-05 21:47:34 +0000515 break;
516 }
517 if (LocaleCompare(keyword,"mean-error") == 0)
518 {
cristyf2f27272009-12-17 14:48:46 +0000519 image->error.normalized_mean_error=StringToDouble(options);
cristy3ed852e2009-09-05 21:47:34 +0000520 break;
521 }
522 if (LocaleCompare(keyword,"montage") == 0)
523 {
524 (void) CloneString(&image->montage,options);
525 break;
526 }
527 (void) SetImageProperty(image,keyword,options);
528 break;
529 }
530 case 'o':
531 case 'O':
532 {
533 if (LocaleCompare(keyword,"opaque") == 0)
534 {
cristybb503372010-05-27 20:51:26 +0000535 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000536 matte;
537
cristy042ee782011-04-22 18:48:30 +0000538 matte=ParseCommandOption(MagickBooleanOptions,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000539 options);
540 if (matte < 0)
541 break;
542 image->matte=(MagickBooleanType) matte;
543 break;
544 }
545 if (LocaleCompare(keyword,"orientation") == 0)
546 {
cristybb503372010-05-27 20:51:26 +0000547 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000548 orientation;
549
cristy042ee782011-04-22 18:48:30 +0000550 orientation=ParseCommandOption(MagickOrientationOptions,
cristy3ed852e2009-09-05 21:47:34 +0000551 MagickFalse,options);
552 if (orientation < 0)
553 break;
554 image->orientation=(OrientationType) orientation;
555 break;
556 }
557 (void) SetImageProperty(image,keyword,options);
558 break;
559 }
560 case 'p':
561 case 'P':
562 {
563 if (LocaleCompare(keyword,"page") == 0)
564 {
565 char
566 *geometry;
567
568 geometry=GetPageGeometry(options);
569 (void) ParseAbsoluteGeometry(geometry,&image->page);
570 geometry=DestroyString(geometry);
571 break;
572 }
573 if ((LocaleNCompare(keyword,"profile:",8) == 0) ||
574 (LocaleNCompare(keyword,"profile-",8) == 0))
575 {
576 if (profiles == (LinkedListInfo *) NULL)
577 profiles=NewLinkedList(0);
578 (void) AppendValueToLinkedList(profiles,
579 AcquireString(keyword+8));
cristyf2f27272009-12-17 14:48:46 +0000580 profile=AcquireStringInfo((size_t) StringToLong(options));
cristy3ed852e2009-09-05 21:47:34 +0000581 (void) SetImageProfile(image,keyword+8,profile);
582 profile=DestroyStringInfo(profile);
583 break;
584 }
585 (void) SetImageProperty(image,keyword,options);
586 break;
587 }
588 case 'q':
589 case 'Q':
590 {
591 if (LocaleCompare(keyword,"quality") == 0)
592 {
cristye27293e2009-12-18 02:53:20 +0000593 image->quality=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000594 break;
595 }
596 if (LocaleCompare(keyword,"quantum-depth") == 0)
597 {
cristye27293e2009-12-18 02:53:20 +0000598 quantum_depth=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000599 break;
600 }
601 (void) SetImageProperty(image,keyword,options);
602 break;
603 }
604 case 'r':
605 case 'R':
606 {
607 if (LocaleCompare(keyword,"red-primary") == 0)
608 {
609 flags=ParseGeometry(options,&geometry_info);
610 image->chromaticity.red_primary.x=geometry_info.rho;
611 if ((flags & SigmaValue) != 0)
612 image->chromaticity.red_primary.y=geometry_info.sigma;
613 break;
614 }
615 if (LocaleCompare(keyword,"rendering-intent") == 0)
616 {
cristybb503372010-05-27 20:51:26 +0000617 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000618 rendering_intent;
619
cristy042ee782011-04-22 18:48:30 +0000620 rendering_intent=ParseCommandOption(MagickIntentOptions,
cristy3ed852e2009-09-05 21:47:34 +0000621 MagickFalse,options);
622 if (rendering_intent < 0)
623 break;
624 image->rendering_intent=(RenderingIntent) rendering_intent;
625 break;
626 }
627 if (LocaleCompare(keyword,"resolution") == 0)
628 {
629 flags=ParseGeometry(options,&geometry_info);
630 image->x_resolution=geometry_info.rho;
631 image->y_resolution=geometry_info.sigma;
632 if ((flags & SigmaValue) == 0)
633 image->y_resolution=image->x_resolution;
634 break;
635 }
636 if (LocaleCompare(keyword,"rows") == 0)
637 {
cristye27293e2009-12-18 02:53:20 +0000638 image->rows=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000639 break;
640 }
641 (void) SetImageProperty(image,keyword,options);
642 break;
643 }
644 case 's':
645 case 'S':
646 {
647 if (LocaleCompare(keyword,"scene") == 0)
648 {
cristye27293e2009-12-18 02:53:20 +0000649 image->scene=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000650 break;
651 }
652 (void) SetImageProperty(image,keyword,options);
653 break;
654 }
655 case 't':
656 case 'T':
657 {
658 if (LocaleCompare(keyword,"ticks-per-second") == 0)
659 {
cristybb503372010-05-27 20:51:26 +0000660 image->ticks_per_second=(ssize_t) StringToLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000661 break;
662 }
663 if (LocaleCompare(keyword,"tile-offset") == 0)
664 {
665 char
666 *geometry;
667
668 geometry=GetPageGeometry(options);
669 (void) ParseAbsoluteGeometry(geometry,&image->tile_offset);
670 geometry=DestroyString(geometry);
671 }
672 if (LocaleCompare(keyword,"type") == 0)
673 {
cristybb503372010-05-27 20:51:26 +0000674 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000675 type;
676
cristy042ee782011-04-22 18:48:30 +0000677 type=ParseCommandOption(MagickTypeOptions,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000678 options);
679 if (type < 0)
680 break;
681 image->type=(ImageType) type;
682 break;
683 }
684 (void) SetImageProperty(image,keyword,options);
685 break;
686 }
687 case 'u':
688 case 'U':
689 {
690 if (LocaleCompare(keyword,"units") == 0)
691 {
cristybb503372010-05-27 20:51:26 +0000692 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000693 units;
694
cristy042ee782011-04-22 18:48:30 +0000695 units=ParseCommandOption(MagickResolutionOptions,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000696 options);
697 if (units < 0)
698 break;
699 image->units=(ResolutionType) units;
700 break;
701 }
702 (void) SetImageProperty(image,keyword,options);
703 break;
704 }
705 case 'w':
706 case 'W':
707 {
708 if (LocaleCompare(keyword,"white-point") == 0)
709 {
710 flags=ParseGeometry(options,&geometry_info);
711 image->chromaticity.white_point.x=geometry_info.rho;
712 image->chromaticity.white_point.y=geometry_info.sigma;
713 if ((flags & SigmaValue) == 0)
714 image->chromaticity.white_point.y=
715 image->chromaticity.white_point.x;
716 break;
717 }
718 (void) SetImageProperty(image,keyword,options);
719 break;
720 }
721 default:
722 {
723 (void) SetImageProperty(image,keyword,options);
724 break;
725 }
726 }
727 }
728 else
729 c=ReadBlobByte(image);
730 while (isspace((int) ((unsigned char) c)) != 0)
731 c=ReadBlobByte(image);
732 }
733 options=DestroyString(options);
734 (void) ReadBlobByte(image);
735 /*
736 Verify that required image information is defined.
737 */
738 if ((LocaleCompare(id,"MagickCache") != 0) ||
739 (image->storage_class == UndefinedClass) ||
740 (image->compression == UndefinedCompression) || (image->columns == 0) ||
741 (image->rows == 0))
742 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
743 if (quantum_depth != MAGICKCORE_QUANTUM_DEPTH)
744 ThrowReaderException(CacheError,"InconsistentPersistentCacheDepth");
745 if (image->montage != (char *) NULL)
746 {
747 register char
748 *p;
749
750 /*
751 Image directory.
752 */
753 length=MaxTextExtent;
754 image->directory=AcquireString((char *) NULL);
755 p=image->directory;
756 do
757 {
758 *p='\0';
759 if ((strlen(image->directory)+MaxTextExtent) >= length)
760 {
761 /*
762 Allocate more memory for the image directory.
763 */
764 length<<=1;
765 image->directory=(char *) ResizeQuantumMemory(image->directory,
766 length+MaxTextExtent,sizeof(*image->directory));
767 if (image->directory == (char *) NULL)
768 ThrowReaderException(CorruptImageError,"UnableToReadImageData");
769 p=image->directory+strlen(image->directory);
770 }
771 c=ReadBlobByte(image);
772 *p++=(char) c;
773 } while (c != (int) '\0');
774 }
775 if (profiles != (LinkedListInfo *) NULL)
776 {
777 const char
778 *name;
779
780 const StringInfo
781 *profile;
782
783 register unsigned char
784 *p;
785
786 /*
787 Read image profiles.
788 */
789 ResetLinkedListIterator(profiles);
790 name=(const char *) GetNextValueInLinkedList(profiles);
791 while (name != (const char *) NULL)
792 {
793 profile=GetImageProfile(image,name);
794 if (profile != (StringInfo *) NULL)
795 {
796 p=GetStringInfoDatum(profile);
797 count=ReadBlob(image,GetStringInfoLength(profile),p);
798 }
799 name=(const char *) GetNextValueInLinkedList(profiles);
800 }
801 profiles=DestroyLinkedList(profiles,RelinquishMagickMemory);
802 }
803 depth=GetImageQuantumDepth(image,MagickFalse);
804 if (image->storage_class == PseudoClass)
805 {
806 /*
807 Create image colormap.
808 */
809 if (AcquireImageColormap(image,image->colors) == MagickFalse)
810 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
811 if (image->colors != 0)
812 {
813 size_t
814 packet_size;
815
816 unsigned char
817 *colormap;
818
819 /*
820 Read image colormap from file.
821 */
822 packet_size=(size_t) (3UL*depth/8UL);
823 colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
824 packet_size*sizeof(*colormap));
825 if (colormap == (unsigned char *) NULL)
826 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
827 count=ReadBlob(image,packet_size*image->colors,colormap);
828 if (count != (ssize_t) (packet_size*image->colors))
829 ThrowReaderException(CorruptImageError,
830 "InsufficientImageDataInFile");
831 p=colormap;
832 switch (depth)
833 {
834 default:
835 ThrowReaderException(CorruptImageError,
836 "ImageDepthNotSupported");
837 case 8:
838 {
839 unsigned char
840 pixel;
841
cristybb503372010-05-27 20:51:26 +0000842 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +0000843 {
844 p=PushCharPixel(p,&pixel);
845 image->colormap[i].red=ScaleCharToQuantum(pixel);
846 p=PushCharPixel(p,&pixel);
847 image->colormap[i].green=ScaleCharToQuantum(pixel);
848 p=PushCharPixel(p,&pixel);
849 image->colormap[i].blue=ScaleCharToQuantum(pixel);
850 }
851 break;
852 }
853 case 16:
854 {
855 unsigned short
856 pixel;
857
cristybb503372010-05-27 20:51:26 +0000858 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +0000859 {
860 p=PushShortPixel(MSBEndian,p,&pixel);
861 image->colormap[i].red=ScaleShortToQuantum(pixel);
862 p=PushShortPixel(MSBEndian,p,&pixel);
863 image->colormap[i].green=ScaleShortToQuantum(pixel);
864 p=PushShortPixel(MSBEndian,p,&pixel);
865 image->colormap[i].blue=ScaleShortToQuantum(pixel);
866 }
867 break;
868 }
869 case 32:
870 {
cristy4cb162a2010-05-30 03:04:47 +0000871 unsigned int
cristy3ed852e2009-09-05 21:47:34 +0000872 pixel;
873
cristybb503372010-05-27 20:51:26 +0000874 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +0000875 {
876 p=PushLongPixel(MSBEndian,p,&pixel);
877 image->colormap[i].red=ScaleLongToQuantum(pixel);
878 p=PushLongPixel(MSBEndian,p,&pixel);
879 image->colormap[i].green=ScaleLongToQuantum(pixel);
880 p=PushLongPixel(MSBEndian,p,&pixel);
881 image->colormap[i].blue=ScaleLongToQuantum(pixel);
882 }
883 break;
884 }
885 }
886 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
887 }
888 }
889 if (EOFBlob(image) != MagickFalse)
890 {
891 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
892 image->filename);
893 break;
894 }
895 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
896 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
897 break;
898 /*
899 Attach persistent pixel cache.
900 */
901 status=PersistPixelCache(image,cache_filename,MagickTrue,&offset,exception);
902 if (status == MagickFalse)
903 ThrowReaderException(CacheError,"UnableToPersistPixelCache");
904 /*
905 Proceed to next image.
906 */
907 do
908 {
909 c=ReadBlobByte(image);
910 } while ((isgraph(c) == MagickFalse) && (c != EOF));
911 if (c != EOF)
912 {
913 /*
914 Allocate next image structure.
915 */
916 AcquireNextImage(image_info,image);
917 if (GetNextImageInList(image) == (Image *) NULL)
918 {
919 image=DestroyImageList(image);
920 return((Image *) NULL);
921 }
922 image=SyncNextImageInList(image);
923 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
924 GetBlobSize(image));
925 if (status == MagickFalse)
926 break;
927 }
928 } while (c != EOF);
929 (void) CloseBlob(image);
930 return(GetFirstImageInList(image));
931}
932
933/*
934%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
935% %
936% %
937% %
938% R e g i s t e r M P C I m a g e %
939% %
940% %
941% %
942%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
943%
944% RegisterMPCImage() adds properties for the Cache image format to
945% the list of supported formats. The properties include the image format
946% tag, a method to read and/or write the format, whether the format
947% supports the saving of more than one frame to the same file or blob,
948% whether the format supports native in-memory I/O, and a brief
949% description of the format.
950%
951% The format of the RegisterMPCImage method is:
952%
cristybb503372010-05-27 20:51:26 +0000953% size_t RegisterMPCImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000954%
955*/
cristybb503372010-05-27 20:51:26 +0000956ModuleExport size_t RegisterMPCImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000957{
958 MagickInfo
959 *entry;
960
961 entry=SetMagickInfo("CACHE");
962 entry->description=ConstantString("Magick Persistent Cache image format");
963 entry->module=ConstantString("CACHE");
964 entry->stealth=MagickTrue;
965 (void) RegisterMagickInfo(entry);
966 entry=SetMagickInfo("MPC");
967 entry->decoder=(DecodeImageHandler *) ReadMPCImage;
968 entry->encoder=(EncodeImageHandler *) WriteMPCImage;
969 entry->magick=(IsImageFormatHandler *) IsMPC;
970 entry->description=ConstantString("Magick Persistent Cache image format");
971 entry->module=ConstantString("MPC");
972 (void) RegisterMagickInfo(entry);
973 return(MagickImageCoderSignature);
974}
975
976/*
977%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
978% %
979% %
980% %
981% U n r e g i s t e r M P C I m a g e %
982% %
983% %
984% %
985%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
986%
987% UnregisterMPCImage() removes format registrations made by the
988% MPC module from the list of supported formats.
989%
990% The format of the UnregisterMPCImage method is:
991%
992% UnregisterMPCImage(void)
993%
994*/
995ModuleExport void UnregisterMPCImage(void)
996{
997 (void) UnregisterMagickInfo("CACHE");
998 (void) UnregisterMagickInfo("MPC");
999}
1000
1001/*
1002%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1003% %
1004% %
1005% %
1006% W r i t e M P C I m a g e %
1007% %
1008% %
1009% %
1010%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1011%
1012% WriteMPCImage() writes an Magick Persistent Cache image to a file.
1013%
1014% The format of the WriteMPCImage method is:
1015%
1016% MagickBooleanType WriteMPCImage(const ImageInfo *image_info,Image *image)
1017%
1018% A description of each parameter follows:
1019%
1020% o image_info: the image info.
1021%
1022% o image: the image.
1023%
1024*/
1025static MagickBooleanType WriteMPCImage(const ImageInfo *image_info,Image *image)
1026{
1027 char
1028 buffer[MaxTextExtent],
1029 cache_filename[MaxTextExtent];
1030
1031 const char
1032 *property,
1033 *value;
1034
1035 MagickBooleanType
1036 status;
1037
1038 MagickOffsetType
1039 offset,
1040 scene;
1041
cristybb503372010-05-27 20:51:26 +00001042 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001043 i;
1044
cristybb503372010-05-27 20:51:26 +00001045 size_t
cristyeaedf062010-05-29 22:36:02 +00001046 depth,
1047 one;
cristy3ed852e2009-09-05 21:47:34 +00001048
1049 /*
1050 Open persistent cache.
1051 */
1052 assert(image_info != (const ImageInfo *) NULL);
1053 assert(image_info->signature == MagickSignature);
1054 assert(image != (Image *) NULL);
1055 assert(image->signature == MagickSignature);
1056 if (image->debug != MagickFalse)
1057 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1058 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1059 if (status == MagickFalse)
1060 return(status);
1061 (void) CopyMagickString(cache_filename,image->filename,MaxTextExtent);
1062 AppendImageFormat("cache",cache_filename);
1063 scene=0;
1064 offset=0;
cristyeaedf062010-05-29 22:36:02 +00001065 one=1;
cristy3ed852e2009-09-05 21:47:34 +00001066 do
1067 {
1068 /*
1069 Write persistent cache meta-information.
1070 */
1071 depth=GetImageQuantumDepth(image,MagickTrue);
1072 if ((image->storage_class == PseudoClass) &&
cristyeaedf062010-05-29 22:36:02 +00001073 (image->colors > (one << depth)))
cristy3ed852e2009-09-05 21:47:34 +00001074 image->storage_class=DirectClass;
1075 (void) WriteBlobString(image,"id=MagickCache\n");
1076 (void) FormatMagickString(buffer,MaxTextExtent,"quantum-depth=%d\n",
1077 MAGICKCORE_QUANTUM_DEPTH);
1078 (void) WriteBlobString(image,buffer);
1079 (void) FormatMagickString(buffer,MaxTextExtent,
cristy042ee782011-04-22 18:48:30 +00001080 "class=%s colors=%.20g matte=%s\n",CommandOptionToMnemonic(
cristye8c25f92010-06-03 00:53:06 +00001081 MagickClassOptions,image->storage_class),(double) image->colors,
cristy042ee782011-04-22 18:48:30 +00001082 CommandOptionToMnemonic(MagickBooleanOptions,(ssize_t) image->matte));
cristy3ed852e2009-09-05 21:47:34 +00001083 (void) WriteBlobString(image,buffer);
1084 (void) FormatMagickString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001085 "columns=%.20g rows=%.20g depth=%.20g\n",(double) image->columns,
1086 (double) image->rows,(double) image->depth);
cristy3ed852e2009-09-05 21:47:34 +00001087 (void) WriteBlobString(image,buffer);
cristy5f1c1ff2010-12-23 21:38:06 +00001088 if (image->type != UndefinedType)
cristy3ed852e2009-09-05 21:47:34 +00001089 {
1090 (void) FormatMagickString(buffer,MaxTextExtent,"type=%s\n",
cristy042ee782011-04-22 18:48:30 +00001091 CommandOptionToMnemonic(MagickTypeOptions,image->type));
cristy3ed852e2009-09-05 21:47:34 +00001092 (void) WriteBlobString(image,buffer);
1093 }
1094 if (image->colorspace != UndefinedColorspace)
1095 {
1096 (void) FormatMagickString(buffer,MaxTextExtent,"colorspace=%s\n",
cristy042ee782011-04-22 18:48:30 +00001097 CommandOptionToMnemonic(MagickColorspaceOptions,image->colorspace));
cristy3ed852e2009-09-05 21:47:34 +00001098 (void) WriteBlobString(image,buffer);
1099 }
1100 if (image->endian != UndefinedEndian)
1101 {
1102 (void) FormatMagickString(buffer,MaxTextExtent,"endian=%s\n",
cristy042ee782011-04-22 18:48:30 +00001103 CommandOptionToMnemonic(MagickEndianOptions,image->endian));
cristy3ed852e2009-09-05 21:47:34 +00001104 (void) WriteBlobString(image,buffer);
1105 }
1106 if (image->compression != UndefinedCompression)
1107 {
1108 (void) FormatMagickString(buffer,MaxTextExtent,
cristy042ee782011-04-22 18:48:30 +00001109 "compression=%s quality=%.20g\n",CommandOptionToMnemonic(
cristye8c25f92010-06-03 00:53:06 +00001110 MagickCompressOptions,image->compression),(double) image->quality);
cristy3ed852e2009-09-05 21:47:34 +00001111 (void) WriteBlobString(image,buffer);
1112 }
1113 if (image->units != UndefinedResolution)
1114 {
1115 (void) FormatMagickString(buffer,MaxTextExtent,"units=%s\n",
cristy042ee782011-04-22 18:48:30 +00001116 CommandOptionToMnemonic(MagickResolutionOptions,image->units));
cristy3ed852e2009-09-05 21:47:34 +00001117 (void) WriteBlobString(image,buffer);
1118 }
1119 if ((image->x_resolution != 0) || (image->y_resolution != 0))
1120 {
cristy8cd5b312010-01-07 01:10:24 +00001121 (void) FormatMagickString(buffer,MaxTextExtent,
cristye7f51092010-01-17 00:39:37 +00001122 "resolution=%gx%g\n",image->x_resolution,image->y_resolution);
cristy3ed852e2009-09-05 21:47:34 +00001123 (void) WriteBlobString(image,buffer);
1124 }
1125 if ((image->page.width != 0) || (image->page.height != 0))
1126 {
cristye8c25f92010-06-03 00:53:06 +00001127 (void) FormatMagickString(buffer,MaxTextExtent,
1128 "page=%.20gx%.20g%+.20g%+.20g\n",(double) image->page.width,(double)
1129 image->page.height,(double) image->page.x,(double) image->page.y);
cristy3ed852e2009-09-05 21:47:34 +00001130 (void) WriteBlobString(image,buffer);
1131 }
1132 else
1133 if ((image->page.x != 0) || (image->page.y != 0))
1134 {
1135 (void) FormatMagickString(buffer,MaxTextExtent,"page=%+ld%+ld\n",
cristyf2faecf2010-05-28 19:19:36 +00001136 (long) image->page.x,(long) image->page.y);
cristy3ed852e2009-09-05 21:47:34 +00001137 (void) WriteBlobString(image,buffer);
1138 }
1139 if ((image->page.x != 0) || (image->page.y != 0))
1140 {
1141 (void) FormatMagickString(buffer,MaxTextExtent,"tile-offset=%+ld%+ld\n",
cristyf2faecf2010-05-28 19:19:36 +00001142 (long) image->tile_offset.x,(long) image->tile_offset.y);
cristy3ed852e2009-09-05 21:47:34 +00001143 (void) WriteBlobString(image,buffer);
1144 }
1145 if ((GetNextImageInList(image) != (Image *) NULL) ||
1146 (GetPreviousImageInList(image) != (Image *) NULL))
1147 {
1148 if (image->scene == 0)
1149 (void) FormatMagickString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001150 "iterations=%.20g delay=%.20g ticks-per-second=%.20g\n",(double)
1151 image->iterations,(double) image->delay,(double)
cristyf2faecf2010-05-28 19:19:36 +00001152 image->ticks_per_second);
cristy3ed852e2009-09-05 21:47:34 +00001153 else
cristyaff6d802011-04-26 01:46:31 +00001154 (void) FormatMagickString(buffer,MaxTextExtent,"scene=%.20g "
1155 "iterations=%.20g delay=%.20g ticks-per-second=%.20g\n",
cristye8c25f92010-06-03 00:53:06 +00001156 (double) image->scene,(double) image->iterations,(double)
1157 image->delay,(double) image->ticks_per_second);
cristy3ed852e2009-09-05 21:47:34 +00001158 (void) WriteBlobString(image,buffer);
1159 }
1160 else
1161 {
1162 if (image->scene != 0)
1163 {
cristye8c25f92010-06-03 00:53:06 +00001164 (void) FormatMagickString(buffer,MaxTextExtent,"scene=%.20g\n",
1165 (double) image->scene);
cristy3ed852e2009-09-05 21:47:34 +00001166 (void) WriteBlobString(image,buffer);
1167 }
1168 if (image->iterations != 0)
1169 {
cristye8c25f92010-06-03 00:53:06 +00001170 (void) FormatMagickString(buffer,MaxTextExtent,"iterations=%.20g\n",
1171 (double) image->iterations);
cristy3ed852e2009-09-05 21:47:34 +00001172 (void) WriteBlobString(image,buffer);
1173 }
1174 if (image->delay != 0)
1175 {
cristye8c25f92010-06-03 00:53:06 +00001176 (void) FormatMagickString(buffer,MaxTextExtent,"delay=%.20g\n",
1177 (double) image->delay);
cristy3ed852e2009-09-05 21:47:34 +00001178 (void) WriteBlobString(image,buffer);
1179 }
1180 if (image->ticks_per_second != UndefinedTicksPerSecond)
1181 {
1182 (void) FormatMagickString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001183 "ticks-per-second=%.20g\n",(double) image->ticks_per_second);
cristy3ed852e2009-09-05 21:47:34 +00001184 (void) WriteBlobString(image,buffer);
1185 }
1186 }
1187 if (image->gravity != UndefinedGravity)
1188 {
1189 (void) FormatMagickString(buffer,MaxTextExtent,"gravity=%s\n",
cristy042ee782011-04-22 18:48:30 +00001190 CommandOptionToMnemonic(MagickGravityOptions,image->gravity));
cristy3ed852e2009-09-05 21:47:34 +00001191 (void) WriteBlobString(image,buffer);
1192 }
1193 if (image->dispose != UndefinedDispose)
1194 {
1195 (void) FormatMagickString(buffer,MaxTextExtent,"dispose=%s\n",
cristy042ee782011-04-22 18:48:30 +00001196 CommandOptionToMnemonic(MagickDisposeOptions,image->dispose));
cristy3ed852e2009-09-05 21:47:34 +00001197 (void) WriteBlobString(image,buffer);
1198 }
1199 if (image->rendering_intent != UndefinedIntent)
1200 {
1201 (void) FormatMagickString(buffer,MaxTextExtent,
cristyaff6d802011-04-26 01:46:31 +00001202 "rendering-intent=%s\n",CommandOptionToMnemonic(MagickIntentOptions,
1203 image->rendering_intent));
cristy3ed852e2009-09-05 21:47:34 +00001204 (void) WriteBlobString(image,buffer);
1205 }
1206 if (image->gamma != 0.0)
1207 {
cristye7f51092010-01-17 00:39:37 +00001208 (void) FormatMagickString(buffer,MaxTextExtent,"gamma=%g\n",
cristy3ed852e2009-09-05 21:47:34 +00001209 image->gamma);
1210 (void) WriteBlobString(image,buffer);
1211 }
1212 if (image->chromaticity.white_point.x != 0.0)
1213 {
1214 /*
1215 Note chomaticity points.
1216 */
cristy8cd5b312010-01-07 01:10:24 +00001217 (void) FormatMagickString(buffer,MaxTextExtent,"red-primary="
cristye7f51092010-01-17 00:39:37 +00001218 "%g,%g green-primary=%g,%g blue-primary=%g,%g\n",
cristy3ed852e2009-09-05 21:47:34 +00001219 image->chromaticity.red_primary.x,image->chromaticity.red_primary.y,
1220 image->chromaticity.green_primary.x,
1221 image->chromaticity.green_primary.y,
1222 image->chromaticity.blue_primary.x,
1223 image->chromaticity.blue_primary.y);
1224 (void) WriteBlobString(image,buffer);
cristy8cd5b312010-01-07 01:10:24 +00001225 (void) FormatMagickString(buffer,MaxTextExtent,
cristye7f51092010-01-17 00:39:37 +00001226 "white-point=%g,%g\n",image->chromaticity.white_point.x,
cristy8cd5b312010-01-07 01:10:24 +00001227 image->chromaticity.white_point.y);
cristy3ed852e2009-09-05 21:47:34 +00001228 (void) WriteBlobString(image,buffer);
1229 }
1230 if (image->orientation != UndefinedOrientation)
1231 {
1232 (void) FormatMagickString(buffer,MaxTextExtent,
cristy042ee782011-04-22 18:48:30 +00001233 "orientation=%s\n",CommandOptionToMnemonic(MagickOrientationOptions,
cristy3ed852e2009-09-05 21:47:34 +00001234 image->orientation));
1235 (void) WriteBlobString(image,buffer);
1236 }
1237 if (image->profiles != (void *) NULL)
1238 {
1239 const char
1240 *name;
1241
1242 const StringInfo
1243 *profile;
1244
1245 /*
1246 Generic profile.
1247 */
1248 ResetImageProfileIterator(image);
1249 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1250 {
1251 profile=GetImageProfile(image,name);
1252 if (profile != (StringInfo *) NULL)
1253 {
cristye8c25f92010-06-03 00:53:06 +00001254 (void) FormatMagickString(buffer,MaxTextExtent,
1255 "profile:%s=%.20g\n",name,(double)
1256 GetStringInfoLength(profile));
cristy3ed852e2009-09-05 21:47:34 +00001257 (void) WriteBlobString(image,buffer);
1258 }
1259 name=GetNextImageProfile(image);
1260 }
1261 }
1262 if (image->montage != (char *) NULL)
1263 {
1264 (void) FormatMagickString(buffer,MaxTextExtent,"montage=%s\n",
1265 image->montage);
1266 (void) WriteBlobString(image,buffer);
1267 }
1268 ResetImagePropertyIterator(image);
1269 property=GetNextImageProperty(image);
1270 while (property != (const char *) NULL)
1271 {
1272 (void) FormatMagickString(buffer,MaxTextExtent,"%s=",property);
1273 (void) WriteBlobString(image,buffer);
1274 value=GetImageProperty(image,property);
1275 if (value != (const char *) NULL)
1276 {
cristybb503372010-05-27 20:51:26 +00001277 for (i=0; i < (ssize_t) strlen(value); i++)
cristy3ed852e2009-09-05 21:47:34 +00001278 if (isspace((int) ((unsigned char) value[i])) != 0)
1279 break;
cristybb503372010-05-27 20:51:26 +00001280 if (i <= (ssize_t) strlen(value))
cristy3ed852e2009-09-05 21:47:34 +00001281 (void) WriteBlobByte(image,'{');
1282 (void) WriteBlob(image,strlen(value),(unsigned char *) value);
cristybb503372010-05-27 20:51:26 +00001283 if (i <= (ssize_t) strlen(value))
cristy3ed852e2009-09-05 21:47:34 +00001284 (void) WriteBlobByte(image,'}');
1285 }
1286 (void) WriteBlobByte(image,'\n');
1287 property=GetNextImageProperty(image);
1288 }
1289 ResetImageArtifactIterator(image);
1290 (void) WriteBlobString(image,"\f\n:\032");
1291 if (image->montage != (char *) NULL)
1292 {
1293 /*
1294 Write montage tile directory.
1295 */
1296 if (image->directory != (char *) NULL)
1297 (void) WriteBlobString(image,image->directory);
1298 (void) WriteBlobByte(image,'\0');
1299 }
1300 if (image->profiles != 0)
1301 {
1302 const char
1303 *name;
1304
1305 const StringInfo
1306 *profile;
1307
1308 /*
1309 Write image profiles.
1310 */
1311 ResetImageProfileIterator(image);
1312 name=GetNextImageProfile(image);
1313 while (name != (const char *) NULL)
1314 {
1315 profile=GetImageProfile(image,name);
1316 (void) WriteBlob(image,GetStringInfoLength(profile),
1317 GetStringInfoDatum(profile));
1318 name=GetNextImageProfile(image);
1319 }
1320 }
1321 if (image->storage_class == PseudoClass)
1322 {
1323 size_t
1324 packet_size;
1325
1326 unsigned char
1327 *colormap,
1328 *q;
1329
1330 /*
1331 Allocate colormap.
1332 */
1333 packet_size=(size_t) (3UL*depth/8UL);
1334 colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
1335 packet_size*sizeof(*colormap));
1336 if (colormap == (unsigned char *) NULL)
1337 return(MagickFalse);
1338 /*
1339 Write colormap to file.
1340 */
1341 q=colormap;
cristybb503372010-05-27 20:51:26 +00001342 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00001343 {
1344 switch (depth)
1345 {
1346 default:
1347 ThrowWriterException(CorruptImageError,"ImageDepthNotSupported");
1348 case 32:
1349 {
cristy4cb162a2010-05-30 03:04:47 +00001350 unsigned int
cristy3ed852e2009-09-05 21:47:34 +00001351 pixel;
1352
1353 pixel=ScaleQuantumToLong(image->colormap[i].red);
1354 q=PopLongPixel(MSBEndian,pixel,q);
1355 pixel=ScaleQuantumToLong(image->colormap[i].green);
1356 q=PopLongPixel(MSBEndian,pixel,q);
1357 pixel=ScaleQuantumToLong(image->colormap[i].blue);
1358 q=PopLongPixel(MSBEndian,pixel,q);
1359 }
1360 case 16:
1361 {
1362 unsigned short
1363 pixel;
1364
1365 pixel=ScaleQuantumToShort(image->colormap[i].red);
1366 q=PopShortPixel(MSBEndian,pixel,q);
1367 pixel=ScaleQuantumToShort(image->colormap[i].green);
1368 q=PopShortPixel(MSBEndian,pixel,q);
1369 pixel=ScaleQuantumToShort(image->colormap[i].blue);
1370 q=PopShortPixel(MSBEndian,pixel,q);
1371 break;
1372 }
1373 case 8:
1374 {
1375 unsigned char
1376 pixel;
1377
1378 pixel=(unsigned char) ScaleQuantumToChar(image->colormap[i].red);
1379 q=PopCharPixel(pixel,q);
1380 pixel=(unsigned char) ScaleQuantumToChar(
1381 image->colormap[i].green);
1382 q=PopCharPixel(pixel,q);
1383 pixel=(unsigned char) ScaleQuantumToChar(image->colormap[i].blue);
1384 q=PopCharPixel(pixel,q);
1385 break;
1386 }
1387 }
1388 }
1389 (void) WriteBlob(image,packet_size*image->colors,colormap);
1390 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1391 }
1392 /*
1393 Initialize persistent pixel cache.
1394 */
1395 status=PersistPixelCache(image,cache_filename,MagickFalse,&offset,
1396 &image->exception);
1397 if (status == MagickFalse)
1398 ThrowWriterException(CacheError,"UnableToPersistPixelCache");
1399 if (GetNextImageInList(image) == (Image *) NULL)
1400 break;
1401 image=SyncNextImageInList(image);
1402 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1403 {
1404 status=image->progress_monitor(SaveImagesTag,scene,
1405 GetImageListLength(image),image->client_data);
1406 if (status == MagickFalse)
1407 break;
1408 }
1409 scene++;
1410 } while (image_info->adjoin != MagickFalse);
1411 (void) CloseBlob(image);
1412 return(status);
1413}