blob: c2d17a28066b98aed66f647a93ce2fbb60e1e208 [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*/
cristy4c08aed2011-07-01 19:47:50 +000043#include "MagickCore/studio.h"
44#include "MagickCore/artifact.h"
45#include "MagickCore/attribute.h"
46#include "MagickCore/blob.h"
47#include "MagickCore/blob-private.h"
48#include "MagickCore/cache.h"
49#include "MagickCore/color.h"
50#include "MagickCore/color-private.h"
51#include "MagickCore/colormap.h"
52#include "MagickCore/constitute.h"
53#include "MagickCore/exception.h"
54#include "MagickCore/exception-private.h"
55#include "MagickCore/geometry.h"
56#include "MagickCore/hashmap.h"
57#include "MagickCore/image.h"
58#include "MagickCore/image-private.h"
59#include "MagickCore/list.h"
60#include "MagickCore/magick.h"
61#include "MagickCore/memory_.h"
62#include "MagickCore/module.h"
63#include "MagickCore/monitor.h"
64#include "MagickCore/monitor-private.h"
65#include "MagickCore/option.h"
66#include "MagickCore/profile.h"
67#include "MagickCore/property.h"
68#include "MagickCore/quantum-private.h"
69#include "MagickCore/static.h"
70#include "MagickCore/statistic.h"
71#include "MagickCore/string_.h"
72#include "MagickCore/string-private.h"
73#include "MagickCore/utility.h"
cristy3ed852e2009-09-05 21:47:34 +000074
75/*
76 Forward declarations.
77*/
78static MagickBooleanType
cristy1e178e72011-08-28 19:44:34 +000079 WriteMPCImage(const ImageInfo *,Image *,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +000080
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);
cristy9950d572011-10-01 18:22:35 +0000199 image=AcquireImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +0000200 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 {
cristy9950d572011-10-01 18:22:35 +0000327 (void) QueryColorCompliance(options,AllCompliance,
328 &image->background_color,exception);
cristy3ed852e2009-09-05 21:47:34 +0000329 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 {
cristy9950d572011-10-01 18:22:35 +0000343 (void) QueryColorCompliance(options,AllCompliance,
344 &image->border_color,exception);
cristy3ed852e2009-09-05 21:47:34 +0000345 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 {
cristyc1acd842011-05-19 23:05:47 +0000447 image->error.mean_error_per_pixel=InterpretLocaleValue(
448 options,(char **) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000449 break;
450 }
451 (void) SetImageProperty(image,keyword,options);
452 break;
453 }
454 case 'g':
455 case 'G':
456 {
457 if (LocaleCompare(keyword,"gamma") == 0)
458 {
cristyc1acd842011-05-19 23:05:47 +0000459 image->gamma=InterpretLocaleValue(options,(char **) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000460 break;
461 }
462 if (LocaleCompare(keyword,"green-primary") == 0)
463 {
464 flags=ParseGeometry(options,&geometry_info);
465 image->chromaticity.green_primary.x=geometry_info.rho;
466 image->chromaticity.green_primary.y=geometry_info.sigma;
467 if ((flags & SigmaValue) == 0)
468 image->chromaticity.green_primary.y=
469 image->chromaticity.green_primary.x;
470 break;
471 }
472 (void) SetImageProperty(image,keyword,options);
473 break;
474 }
475 case 'i':
476 case 'I':
477 {
478 if (LocaleCompare(keyword,"id") == 0)
479 {
480 (void) CopyMagickString(id,options,MaxTextExtent);
481 break;
482 }
483 if (LocaleCompare(keyword,"iterations") == 0)
484 {
cristye27293e2009-12-18 02:53:20 +0000485 image->iterations=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000486 break;
487 }
488 (void) SetImageProperty(image,keyword,options);
489 break;
490 }
491 case 'm':
492 case 'M':
493 {
494 if (LocaleCompare(keyword,"matte") == 0)
495 {
cristybb503372010-05-27 20:51:26 +0000496 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000497 matte;
498
cristy042ee782011-04-22 18:48:30 +0000499 matte=ParseCommandOption(MagickBooleanOptions,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000500 options);
501 if (matte < 0)
502 break;
503 image->matte=(MagickBooleanType) matte;
504 break;
505 }
506 if (LocaleCompare(keyword,"matte-color") == 0)
507 {
cristy9950d572011-10-01 18:22:35 +0000508 (void) QueryColorCompliance(options,AllCompliance,
509 &image->matte_color,exception);
cristy3ed852e2009-09-05 21:47:34 +0000510 break;
511 }
512 if (LocaleCompare(keyword,"maximum-error") == 0)
513 {
cristyaff6d802011-04-26 01:46:31 +0000514 image->error.normalized_maximum_error=
cristyc1acd842011-05-19 23:05:47 +0000515 InterpretLocaleValue(options,(char **) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000516 break;
517 }
518 if (LocaleCompare(keyword,"mean-error") == 0)
519 {
cristyc1acd842011-05-19 23:05:47 +0000520 image->error.normalized_mean_error=InterpretLocaleValue(
521 options,(char **) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000522 break;
523 }
524 if (LocaleCompare(keyword,"montage") == 0)
525 {
526 (void) CloneString(&image->montage,options);
527 break;
528 }
529 (void) SetImageProperty(image,keyword,options);
530 break;
531 }
532 case 'o':
533 case 'O':
534 {
535 if (LocaleCompare(keyword,"opaque") == 0)
536 {
cristybb503372010-05-27 20:51:26 +0000537 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000538 matte;
539
cristy042ee782011-04-22 18:48:30 +0000540 matte=ParseCommandOption(MagickBooleanOptions,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000541 options);
542 if (matte < 0)
543 break;
544 image->matte=(MagickBooleanType) matte;
545 break;
546 }
547 if (LocaleCompare(keyword,"orientation") == 0)
548 {
cristybb503372010-05-27 20:51:26 +0000549 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000550 orientation;
551
cristy042ee782011-04-22 18:48:30 +0000552 orientation=ParseCommandOption(MagickOrientationOptions,
cristy3ed852e2009-09-05 21:47:34 +0000553 MagickFalse,options);
554 if (orientation < 0)
555 break;
556 image->orientation=(OrientationType) orientation;
557 break;
558 }
559 (void) SetImageProperty(image,keyword,options);
560 break;
561 }
562 case 'p':
563 case 'P':
564 {
565 if (LocaleCompare(keyword,"page") == 0)
566 {
567 char
568 *geometry;
569
570 geometry=GetPageGeometry(options);
571 (void) ParseAbsoluteGeometry(geometry,&image->page);
572 geometry=DestroyString(geometry);
573 break;
574 }
575 if ((LocaleNCompare(keyword,"profile:",8) == 0) ||
576 (LocaleNCompare(keyword,"profile-",8) == 0))
577 {
578 if (profiles == (LinkedListInfo *) NULL)
579 profiles=NewLinkedList(0);
580 (void) AppendValueToLinkedList(profiles,
581 AcquireString(keyword+8));
cristy07c9bd62011-09-01 13:41:23 +0000582 profile=BlobToStringInfo((const void *) NULL,(size_t)
583 StringToLong(options));
cristy0381c632011-09-01 18:02:13 +0000584 if (profile == (StringInfo *) NULL)
cristy07c9bd62011-09-01 13:41:23 +0000585 ThrowReaderException(ResourceLimitError,
586 "MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000587 (void) SetImageProfile(image,keyword+8,profile);
588 profile=DestroyStringInfo(profile);
589 break;
590 }
591 (void) SetImageProperty(image,keyword,options);
592 break;
593 }
594 case 'q':
595 case 'Q':
596 {
597 if (LocaleCompare(keyword,"quality") == 0)
598 {
cristye27293e2009-12-18 02:53:20 +0000599 image->quality=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000600 break;
601 }
602 if (LocaleCompare(keyword,"quantum-depth") == 0)
603 {
cristye27293e2009-12-18 02:53:20 +0000604 quantum_depth=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000605 break;
606 }
607 (void) SetImageProperty(image,keyword,options);
608 break;
609 }
610 case 'r':
611 case 'R':
612 {
613 if (LocaleCompare(keyword,"red-primary") == 0)
614 {
615 flags=ParseGeometry(options,&geometry_info);
616 image->chromaticity.red_primary.x=geometry_info.rho;
617 if ((flags & SigmaValue) != 0)
618 image->chromaticity.red_primary.y=geometry_info.sigma;
619 break;
620 }
621 if (LocaleCompare(keyword,"rendering-intent") == 0)
622 {
cristybb503372010-05-27 20:51:26 +0000623 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000624 rendering_intent;
625
cristy042ee782011-04-22 18:48:30 +0000626 rendering_intent=ParseCommandOption(MagickIntentOptions,
cristy3ed852e2009-09-05 21:47:34 +0000627 MagickFalse,options);
628 if (rendering_intent < 0)
629 break;
630 image->rendering_intent=(RenderingIntent) rendering_intent;
631 break;
632 }
633 if (LocaleCompare(keyword,"resolution") == 0)
634 {
635 flags=ParseGeometry(options,&geometry_info);
636 image->x_resolution=geometry_info.rho;
637 image->y_resolution=geometry_info.sigma;
638 if ((flags & SigmaValue) == 0)
639 image->y_resolution=image->x_resolution;
640 break;
641 }
642 if (LocaleCompare(keyword,"rows") == 0)
643 {
cristye27293e2009-12-18 02:53:20 +0000644 image->rows=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000645 break;
646 }
647 (void) SetImageProperty(image,keyword,options);
648 break;
649 }
650 case 's':
651 case 'S':
652 {
653 if (LocaleCompare(keyword,"scene") == 0)
654 {
cristye27293e2009-12-18 02:53:20 +0000655 image->scene=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000656 break;
657 }
658 (void) SetImageProperty(image,keyword,options);
659 break;
660 }
661 case 't':
662 case 'T':
663 {
664 if (LocaleCompare(keyword,"ticks-per-second") == 0)
665 {
cristybb503372010-05-27 20:51:26 +0000666 image->ticks_per_second=(ssize_t) StringToLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000667 break;
668 }
669 if (LocaleCompare(keyword,"tile-offset") == 0)
670 {
671 char
672 *geometry;
673
674 geometry=GetPageGeometry(options);
675 (void) ParseAbsoluteGeometry(geometry,&image->tile_offset);
676 geometry=DestroyString(geometry);
677 }
678 if (LocaleCompare(keyword,"type") == 0)
679 {
cristybb503372010-05-27 20:51:26 +0000680 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000681 type;
682
cristy042ee782011-04-22 18:48:30 +0000683 type=ParseCommandOption(MagickTypeOptions,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000684 options);
685 if (type < 0)
686 break;
687 image->type=(ImageType) type;
688 break;
689 }
690 (void) SetImageProperty(image,keyword,options);
691 break;
692 }
693 case 'u':
694 case 'U':
695 {
696 if (LocaleCompare(keyword,"units") == 0)
697 {
cristybb503372010-05-27 20:51:26 +0000698 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000699 units;
700
cristy042ee782011-04-22 18:48:30 +0000701 units=ParseCommandOption(MagickResolutionOptions,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000702 options);
703 if (units < 0)
704 break;
705 image->units=(ResolutionType) units;
706 break;
707 }
708 (void) SetImageProperty(image,keyword,options);
709 break;
710 }
711 case 'w':
712 case 'W':
713 {
714 if (LocaleCompare(keyword,"white-point") == 0)
715 {
716 flags=ParseGeometry(options,&geometry_info);
717 image->chromaticity.white_point.x=geometry_info.rho;
718 image->chromaticity.white_point.y=geometry_info.sigma;
719 if ((flags & SigmaValue) == 0)
720 image->chromaticity.white_point.y=
721 image->chromaticity.white_point.x;
722 break;
723 }
724 (void) SetImageProperty(image,keyword,options);
725 break;
726 }
727 default:
728 {
729 (void) SetImageProperty(image,keyword,options);
730 break;
731 }
732 }
733 }
734 else
735 c=ReadBlobByte(image);
736 while (isspace((int) ((unsigned char) c)) != 0)
737 c=ReadBlobByte(image);
738 }
739 options=DestroyString(options);
740 (void) ReadBlobByte(image);
741 /*
742 Verify that required image information is defined.
743 */
744 if ((LocaleCompare(id,"MagickCache") != 0) ||
745 (image->storage_class == UndefinedClass) ||
746 (image->compression == UndefinedCompression) || (image->columns == 0) ||
747 (image->rows == 0))
748 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
749 if (quantum_depth != MAGICKCORE_QUANTUM_DEPTH)
750 ThrowReaderException(CacheError,"InconsistentPersistentCacheDepth");
751 if (image->montage != (char *) NULL)
752 {
753 register char
754 *p;
755
756 /*
757 Image directory.
758 */
759 length=MaxTextExtent;
760 image->directory=AcquireString((char *) NULL);
761 p=image->directory;
762 do
763 {
764 *p='\0';
765 if ((strlen(image->directory)+MaxTextExtent) >= length)
766 {
767 /*
768 Allocate more memory for the image directory.
769 */
770 length<<=1;
771 image->directory=(char *) ResizeQuantumMemory(image->directory,
772 length+MaxTextExtent,sizeof(*image->directory));
773 if (image->directory == (char *) NULL)
774 ThrowReaderException(CorruptImageError,"UnableToReadImageData");
775 p=image->directory+strlen(image->directory);
776 }
777 c=ReadBlobByte(image);
778 *p++=(char) c;
779 } while (c != (int) '\0');
780 }
781 if (profiles != (LinkedListInfo *) NULL)
782 {
783 const char
784 *name;
785
786 const StringInfo
787 *profile;
788
789 register unsigned char
790 *p;
791
792 /*
793 Read image profiles.
794 */
795 ResetLinkedListIterator(profiles);
796 name=(const char *) GetNextValueInLinkedList(profiles);
797 while (name != (const char *) NULL)
798 {
799 profile=GetImageProfile(image,name);
800 if (profile != (StringInfo *) NULL)
801 {
802 p=GetStringInfoDatum(profile);
803 count=ReadBlob(image,GetStringInfoLength(profile),p);
804 }
805 name=(const char *) GetNextValueInLinkedList(profiles);
806 }
807 profiles=DestroyLinkedList(profiles,RelinquishMagickMemory);
808 }
809 depth=GetImageQuantumDepth(image,MagickFalse);
810 if (image->storage_class == PseudoClass)
811 {
812 /*
813 Create image colormap.
814 */
cristy018f07f2011-09-04 21:15:19 +0000815 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000816 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
817 if (image->colors != 0)
818 {
819 size_t
820 packet_size;
821
822 unsigned char
823 *colormap;
824
825 /*
826 Read image colormap from file.
827 */
828 packet_size=(size_t) (3UL*depth/8UL);
829 colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
830 packet_size*sizeof(*colormap));
831 if (colormap == (unsigned char *) NULL)
832 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
833 count=ReadBlob(image,packet_size*image->colors,colormap);
834 if (count != (ssize_t) (packet_size*image->colors))
835 ThrowReaderException(CorruptImageError,
836 "InsufficientImageDataInFile");
837 p=colormap;
838 switch (depth)
839 {
840 default:
841 ThrowReaderException(CorruptImageError,
842 "ImageDepthNotSupported");
843 case 8:
844 {
845 unsigned char
846 pixel;
847
cristybb503372010-05-27 20:51:26 +0000848 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +0000849 {
850 p=PushCharPixel(p,&pixel);
851 image->colormap[i].red=ScaleCharToQuantum(pixel);
852 p=PushCharPixel(p,&pixel);
853 image->colormap[i].green=ScaleCharToQuantum(pixel);
854 p=PushCharPixel(p,&pixel);
855 image->colormap[i].blue=ScaleCharToQuantum(pixel);
856 }
857 break;
858 }
859 case 16:
860 {
861 unsigned short
862 pixel;
863
cristybb503372010-05-27 20:51:26 +0000864 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +0000865 {
866 p=PushShortPixel(MSBEndian,p,&pixel);
867 image->colormap[i].red=ScaleShortToQuantum(pixel);
868 p=PushShortPixel(MSBEndian,p,&pixel);
869 image->colormap[i].green=ScaleShortToQuantum(pixel);
870 p=PushShortPixel(MSBEndian,p,&pixel);
871 image->colormap[i].blue=ScaleShortToQuantum(pixel);
872 }
873 break;
874 }
875 case 32:
876 {
cristy4cb162a2010-05-30 03:04:47 +0000877 unsigned int
cristy3ed852e2009-09-05 21:47:34 +0000878 pixel;
879
cristybb503372010-05-27 20:51:26 +0000880 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +0000881 {
882 p=PushLongPixel(MSBEndian,p,&pixel);
883 image->colormap[i].red=ScaleLongToQuantum(pixel);
884 p=PushLongPixel(MSBEndian,p,&pixel);
885 image->colormap[i].green=ScaleLongToQuantum(pixel);
886 p=PushLongPixel(MSBEndian,p,&pixel);
887 image->colormap[i].blue=ScaleLongToQuantum(pixel);
888 }
889 break;
890 }
891 }
892 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
893 }
894 }
895 if (EOFBlob(image) != MagickFalse)
896 {
897 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
898 image->filename);
899 break;
900 }
901 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
902 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
903 break;
904 /*
905 Attach persistent pixel cache.
906 */
907 status=PersistPixelCache(image,cache_filename,MagickTrue,&offset,exception);
908 if (status == MagickFalse)
909 ThrowReaderException(CacheError,"UnableToPersistPixelCache");
910 /*
911 Proceed to next image.
912 */
913 do
914 {
915 c=ReadBlobByte(image);
916 } while ((isgraph(c) == MagickFalse) && (c != EOF));
917 if (c != EOF)
918 {
919 /*
920 Allocate next image structure.
921 */
cristy9950d572011-10-01 18:22:35 +0000922 AcquireNextImage(image_info,image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000923 if (GetNextImageInList(image) == (Image *) NULL)
924 {
925 image=DestroyImageList(image);
926 return((Image *) NULL);
927 }
928 image=SyncNextImageInList(image);
929 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
930 GetBlobSize(image));
931 if (status == MagickFalse)
932 break;
933 }
934 } while (c != EOF);
935 (void) CloseBlob(image);
936 return(GetFirstImageInList(image));
937}
938
939/*
940%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
941% %
942% %
943% %
944% R e g i s t e r M P C I m a g e %
945% %
946% %
947% %
948%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
949%
950% RegisterMPCImage() adds properties for the Cache image format to
951% the list of supported formats. The properties include the image format
952% tag, a method to read and/or write the format, whether the format
953% supports the saving of more than one frame to the same file or blob,
954% whether the format supports native in-memory I/O, and a brief
955% description of the format.
956%
957% The format of the RegisterMPCImage method is:
958%
cristybb503372010-05-27 20:51:26 +0000959% size_t RegisterMPCImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000960%
961*/
cristybb503372010-05-27 20:51:26 +0000962ModuleExport size_t RegisterMPCImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000963{
964 MagickInfo
965 *entry;
966
967 entry=SetMagickInfo("CACHE");
968 entry->description=ConstantString("Magick Persistent Cache image format");
969 entry->module=ConstantString("CACHE");
970 entry->stealth=MagickTrue;
971 (void) RegisterMagickInfo(entry);
972 entry=SetMagickInfo("MPC");
973 entry->decoder=(DecodeImageHandler *) ReadMPCImage;
974 entry->encoder=(EncodeImageHandler *) WriteMPCImage;
975 entry->magick=(IsImageFormatHandler *) IsMPC;
976 entry->description=ConstantString("Magick Persistent Cache image format");
977 entry->module=ConstantString("MPC");
978 (void) RegisterMagickInfo(entry);
979 return(MagickImageCoderSignature);
980}
981
982/*
983%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
984% %
985% %
986% %
987% U n r e g i s t e r M P C I m a g e %
988% %
989% %
990% %
991%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
992%
993% UnregisterMPCImage() removes format registrations made by the
994% MPC module from the list of supported formats.
995%
996% The format of the UnregisterMPCImage method is:
997%
998% UnregisterMPCImage(void)
999%
1000*/
1001ModuleExport void UnregisterMPCImage(void)
1002{
1003 (void) UnregisterMagickInfo("CACHE");
1004 (void) UnregisterMagickInfo("MPC");
1005}
1006
1007/*
1008%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1009% %
1010% %
1011% %
1012% W r i t e M P C I m a g e %
1013% %
1014% %
1015% %
1016%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1017%
1018% WriteMPCImage() writes an Magick Persistent Cache image to a file.
1019%
1020% The format of the WriteMPCImage method is:
1021%
cristy1e178e72011-08-28 19:44:34 +00001022% MagickBooleanType WriteMPCImage(const ImageInfo *image_info,
1023% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001024%
1025% A description of each parameter follows:
1026%
1027% o image_info: the image info.
1028%
1029% o image: the image.
1030%
cristy1e178e72011-08-28 19:44:34 +00001031% o exception: return any errors or warnings in this structure.
1032%
cristy3ed852e2009-09-05 21:47:34 +00001033*/
cristy1e178e72011-08-28 19:44:34 +00001034static MagickBooleanType WriteMPCImage(const ImageInfo *image_info,Image *image,
1035 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001036{
1037 char
1038 buffer[MaxTextExtent],
1039 cache_filename[MaxTextExtent];
1040
1041 const char
1042 *property,
1043 *value;
1044
1045 MagickBooleanType
1046 status;
1047
1048 MagickOffsetType
1049 offset,
1050 scene;
1051
cristybb503372010-05-27 20:51:26 +00001052 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001053 i;
1054
cristybb503372010-05-27 20:51:26 +00001055 size_t
cristyeaedf062010-05-29 22:36:02 +00001056 depth,
1057 one;
cristy3ed852e2009-09-05 21:47:34 +00001058
1059 /*
1060 Open persistent cache.
1061 */
1062 assert(image_info != (const ImageInfo *) NULL);
1063 assert(image_info->signature == MagickSignature);
1064 assert(image != (Image *) NULL);
1065 assert(image->signature == MagickSignature);
1066 if (image->debug != MagickFalse)
1067 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy3a37efd2011-08-28 20:31:03 +00001068 assert(exception != (ExceptionInfo *) NULL);
1069 assert(exception->signature == MagickSignature);
cristy1e178e72011-08-28 19:44:34 +00001070 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00001071 if (status == MagickFalse)
1072 return(status);
1073 (void) CopyMagickString(cache_filename,image->filename,MaxTextExtent);
1074 AppendImageFormat("cache",cache_filename);
1075 scene=0;
1076 offset=0;
cristyeaedf062010-05-29 22:36:02 +00001077 one=1;
cristy3ed852e2009-09-05 21:47:34 +00001078 do
1079 {
1080 /*
1081 Write persistent cache meta-information.
1082 */
1083 depth=GetImageQuantumDepth(image,MagickTrue);
1084 if ((image->storage_class == PseudoClass) &&
cristyeaedf062010-05-29 22:36:02 +00001085 (image->colors > (one << depth)))
cristy3ed852e2009-09-05 21:47:34 +00001086 image->storage_class=DirectClass;
1087 (void) WriteBlobString(image,"id=MagickCache\n");
cristyb51dff52011-05-19 16:55:47 +00001088 (void) FormatLocaleString(buffer,MaxTextExtent,"quantum-depth=%d\n",
cristy3ed852e2009-09-05 21:47:34 +00001089 MAGICKCORE_QUANTUM_DEPTH);
1090 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00001091 (void) FormatLocaleString(buffer,MaxTextExtent,
cristy042ee782011-04-22 18:48:30 +00001092 "class=%s colors=%.20g matte=%s\n",CommandOptionToMnemonic(
cristye8c25f92010-06-03 00:53:06 +00001093 MagickClassOptions,image->storage_class),(double) image->colors,
cristy042ee782011-04-22 18:48:30 +00001094 CommandOptionToMnemonic(MagickBooleanOptions,(ssize_t) image->matte));
cristy3ed852e2009-09-05 21:47:34 +00001095 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00001096 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001097 "columns=%.20g rows=%.20g depth=%.20g\n",(double) image->columns,
1098 (double) image->rows,(double) image->depth);
cristy3ed852e2009-09-05 21:47:34 +00001099 (void) WriteBlobString(image,buffer);
cristy5f1c1ff2010-12-23 21:38:06 +00001100 if (image->type != UndefinedType)
cristy3ed852e2009-09-05 21:47:34 +00001101 {
cristyb51dff52011-05-19 16:55:47 +00001102 (void) FormatLocaleString(buffer,MaxTextExtent,"type=%s\n",
cristy042ee782011-04-22 18:48:30 +00001103 CommandOptionToMnemonic(MagickTypeOptions,image->type));
cristy3ed852e2009-09-05 21:47:34 +00001104 (void) WriteBlobString(image,buffer);
1105 }
1106 if (image->colorspace != UndefinedColorspace)
1107 {
cristyb51dff52011-05-19 16:55:47 +00001108 (void) FormatLocaleString(buffer,MaxTextExtent,"colorspace=%s\n",
cristy042ee782011-04-22 18:48:30 +00001109 CommandOptionToMnemonic(MagickColorspaceOptions,image->colorspace));
cristy3ed852e2009-09-05 21:47:34 +00001110 (void) WriteBlobString(image,buffer);
1111 }
1112 if (image->endian != UndefinedEndian)
1113 {
cristyb51dff52011-05-19 16:55:47 +00001114 (void) FormatLocaleString(buffer,MaxTextExtent,"endian=%s\n",
cristy042ee782011-04-22 18:48:30 +00001115 CommandOptionToMnemonic(MagickEndianOptions,image->endian));
cristy3ed852e2009-09-05 21:47:34 +00001116 (void) WriteBlobString(image,buffer);
1117 }
1118 if (image->compression != UndefinedCompression)
1119 {
cristyb51dff52011-05-19 16:55:47 +00001120 (void) FormatLocaleString(buffer,MaxTextExtent,
cristy042ee782011-04-22 18:48:30 +00001121 "compression=%s quality=%.20g\n",CommandOptionToMnemonic(
cristye8c25f92010-06-03 00:53:06 +00001122 MagickCompressOptions,image->compression),(double) image->quality);
cristy3ed852e2009-09-05 21:47:34 +00001123 (void) WriteBlobString(image,buffer);
1124 }
1125 if (image->units != UndefinedResolution)
1126 {
cristyb51dff52011-05-19 16:55:47 +00001127 (void) FormatLocaleString(buffer,MaxTextExtent,"units=%s\n",
cristy042ee782011-04-22 18:48:30 +00001128 CommandOptionToMnemonic(MagickResolutionOptions,image->units));
cristy3ed852e2009-09-05 21:47:34 +00001129 (void) WriteBlobString(image,buffer);
1130 }
1131 if ((image->x_resolution != 0) || (image->y_resolution != 0))
1132 {
cristyb51dff52011-05-19 16:55:47 +00001133 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye7f51092010-01-17 00:39:37 +00001134 "resolution=%gx%g\n",image->x_resolution,image->y_resolution);
cristy3ed852e2009-09-05 21:47:34 +00001135 (void) WriteBlobString(image,buffer);
1136 }
1137 if ((image->page.width != 0) || (image->page.height != 0))
1138 {
cristyb51dff52011-05-19 16:55:47 +00001139 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001140 "page=%.20gx%.20g%+.20g%+.20g\n",(double) image->page.width,(double)
1141 image->page.height,(double) image->page.x,(double) image->page.y);
cristy3ed852e2009-09-05 21:47:34 +00001142 (void) WriteBlobString(image,buffer);
1143 }
1144 else
1145 if ((image->page.x != 0) || (image->page.y != 0))
1146 {
cristyb51dff52011-05-19 16:55:47 +00001147 (void) FormatLocaleString(buffer,MaxTextExtent,"page=%+ld%+ld\n",
cristyf2faecf2010-05-28 19:19:36 +00001148 (long) image->page.x,(long) image->page.y);
cristy3ed852e2009-09-05 21:47:34 +00001149 (void) WriteBlobString(image,buffer);
1150 }
1151 if ((image->page.x != 0) || (image->page.y != 0))
1152 {
cristyb51dff52011-05-19 16:55:47 +00001153 (void) FormatLocaleString(buffer,MaxTextExtent,"tile-offset=%+ld%+ld\n",
cristyf2faecf2010-05-28 19:19:36 +00001154 (long) image->tile_offset.x,(long) image->tile_offset.y);
cristy3ed852e2009-09-05 21:47:34 +00001155 (void) WriteBlobString(image,buffer);
1156 }
1157 if ((GetNextImageInList(image) != (Image *) NULL) ||
1158 (GetPreviousImageInList(image) != (Image *) NULL))
1159 {
1160 if (image->scene == 0)
cristyb51dff52011-05-19 16:55:47 +00001161 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001162 "iterations=%.20g delay=%.20g ticks-per-second=%.20g\n",(double)
1163 image->iterations,(double) image->delay,(double)
cristyf2faecf2010-05-28 19:19:36 +00001164 image->ticks_per_second);
cristy3ed852e2009-09-05 21:47:34 +00001165 else
cristyb51dff52011-05-19 16:55:47 +00001166 (void) FormatLocaleString(buffer,MaxTextExtent,"scene=%.20g "
cristyaff6d802011-04-26 01:46:31 +00001167 "iterations=%.20g delay=%.20g ticks-per-second=%.20g\n",
cristye8c25f92010-06-03 00:53:06 +00001168 (double) image->scene,(double) image->iterations,(double)
1169 image->delay,(double) image->ticks_per_second);
cristy3ed852e2009-09-05 21:47:34 +00001170 (void) WriteBlobString(image,buffer);
1171 }
1172 else
1173 {
1174 if (image->scene != 0)
1175 {
cristyb51dff52011-05-19 16:55:47 +00001176 (void) FormatLocaleString(buffer,MaxTextExtent,"scene=%.20g\n",
cristye8c25f92010-06-03 00:53:06 +00001177 (double) image->scene);
cristy3ed852e2009-09-05 21:47:34 +00001178 (void) WriteBlobString(image,buffer);
1179 }
1180 if (image->iterations != 0)
1181 {
cristyb51dff52011-05-19 16:55:47 +00001182 (void) FormatLocaleString(buffer,MaxTextExtent,"iterations=%.20g\n",
cristye8c25f92010-06-03 00:53:06 +00001183 (double) image->iterations);
cristy3ed852e2009-09-05 21:47:34 +00001184 (void) WriteBlobString(image,buffer);
1185 }
1186 if (image->delay != 0)
1187 {
cristyb51dff52011-05-19 16:55:47 +00001188 (void) FormatLocaleString(buffer,MaxTextExtent,"delay=%.20g\n",
cristye8c25f92010-06-03 00:53:06 +00001189 (double) image->delay);
cristy3ed852e2009-09-05 21:47:34 +00001190 (void) WriteBlobString(image,buffer);
1191 }
1192 if (image->ticks_per_second != UndefinedTicksPerSecond)
1193 {
cristyb51dff52011-05-19 16:55:47 +00001194 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001195 "ticks-per-second=%.20g\n",(double) image->ticks_per_second);
cristy3ed852e2009-09-05 21:47:34 +00001196 (void) WriteBlobString(image,buffer);
1197 }
1198 }
1199 if (image->gravity != UndefinedGravity)
1200 {
cristyb51dff52011-05-19 16:55:47 +00001201 (void) FormatLocaleString(buffer,MaxTextExtent,"gravity=%s\n",
cristy042ee782011-04-22 18:48:30 +00001202 CommandOptionToMnemonic(MagickGravityOptions,image->gravity));
cristy3ed852e2009-09-05 21:47:34 +00001203 (void) WriteBlobString(image,buffer);
1204 }
1205 if (image->dispose != UndefinedDispose)
1206 {
cristyb51dff52011-05-19 16:55:47 +00001207 (void) FormatLocaleString(buffer,MaxTextExtent,"dispose=%s\n",
cristy042ee782011-04-22 18:48:30 +00001208 CommandOptionToMnemonic(MagickDisposeOptions,image->dispose));
cristy3ed852e2009-09-05 21:47:34 +00001209 (void) WriteBlobString(image,buffer);
1210 }
1211 if (image->rendering_intent != UndefinedIntent)
1212 {
cristyb51dff52011-05-19 16:55:47 +00001213 (void) FormatLocaleString(buffer,MaxTextExtent,
cristyaff6d802011-04-26 01:46:31 +00001214 "rendering-intent=%s\n",CommandOptionToMnemonic(MagickIntentOptions,
1215 image->rendering_intent));
cristy3ed852e2009-09-05 21:47:34 +00001216 (void) WriteBlobString(image,buffer);
1217 }
1218 if (image->gamma != 0.0)
1219 {
cristyb51dff52011-05-19 16:55:47 +00001220 (void) FormatLocaleString(buffer,MaxTextExtent,"gamma=%g\n",
cristy3ed852e2009-09-05 21:47:34 +00001221 image->gamma);
1222 (void) WriteBlobString(image,buffer);
1223 }
1224 if (image->chromaticity.white_point.x != 0.0)
1225 {
1226 /*
1227 Note chomaticity points.
1228 */
cristyb51dff52011-05-19 16:55:47 +00001229 (void) FormatLocaleString(buffer,MaxTextExtent,"red-primary="
cristye7f51092010-01-17 00:39:37 +00001230 "%g,%g green-primary=%g,%g blue-primary=%g,%g\n",
cristy3ed852e2009-09-05 21:47:34 +00001231 image->chromaticity.red_primary.x,image->chromaticity.red_primary.y,
1232 image->chromaticity.green_primary.x,
1233 image->chromaticity.green_primary.y,
1234 image->chromaticity.blue_primary.x,
1235 image->chromaticity.blue_primary.y);
1236 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00001237 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye7f51092010-01-17 00:39:37 +00001238 "white-point=%g,%g\n",image->chromaticity.white_point.x,
cristy8cd5b312010-01-07 01:10:24 +00001239 image->chromaticity.white_point.y);
cristy3ed852e2009-09-05 21:47:34 +00001240 (void) WriteBlobString(image,buffer);
1241 }
1242 if (image->orientation != UndefinedOrientation)
1243 {
cristyb51dff52011-05-19 16:55:47 +00001244 (void) FormatLocaleString(buffer,MaxTextExtent,
cristy042ee782011-04-22 18:48:30 +00001245 "orientation=%s\n",CommandOptionToMnemonic(MagickOrientationOptions,
cristy3ed852e2009-09-05 21:47:34 +00001246 image->orientation));
1247 (void) WriteBlobString(image,buffer);
1248 }
1249 if (image->profiles != (void *) NULL)
1250 {
1251 const char
1252 *name;
1253
1254 const StringInfo
1255 *profile;
1256
1257 /*
1258 Generic profile.
1259 */
1260 ResetImageProfileIterator(image);
1261 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1262 {
1263 profile=GetImageProfile(image,name);
1264 if (profile != (StringInfo *) NULL)
1265 {
cristyb51dff52011-05-19 16:55:47 +00001266 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001267 "profile:%s=%.20g\n",name,(double)
1268 GetStringInfoLength(profile));
cristy3ed852e2009-09-05 21:47:34 +00001269 (void) WriteBlobString(image,buffer);
1270 }
1271 name=GetNextImageProfile(image);
1272 }
1273 }
1274 if (image->montage != (char *) NULL)
1275 {
cristyb51dff52011-05-19 16:55:47 +00001276 (void) FormatLocaleString(buffer,MaxTextExtent,"montage=%s\n",
cristy3ed852e2009-09-05 21:47:34 +00001277 image->montage);
1278 (void) WriteBlobString(image,buffer);
1279 }
1280 ResetImagePropertyIterator(image);
1281 property=GetNextImageProperty(image);
1282 while (property != (const char *) NULL)
1283 {
cristyb51dff52011-05-19 16:55:47 +00001284 (void) FormatLocaleString(buffer,MaxTextExtent,"%s=",property);
cristy3ed852e2009-09-05 21:47:34 +00001285 (void) WriteBlobString(image,buffer);
1286 value=GetImageProperty(image,property);
1287 if (value != (const char *) NULL)
1288 {
cristybb503372010-05-27 20:51:26 +00001289 for (i=0; i < (ssize_t) strlen(value); i++)
cristy3ed852e2009-09-05 21:47:34 +00001290 if (isspace((int) ((unsigned char) value[i])) != 0)
1291 break;
cristybb503372010-05-27 20:51:26 +00001292 if (i <= (ssize_t) strlen(value))
cristy3ed852e2009-09-05 21:47:34 +00001293 (void) WriteBlobByte(image,'{');
1294 (void) WriteBlob(image,strlen(value),(unsigned char *) value);
cristybb503372010-05-27 20:51:26 +00001295 if (i <= (ssize_t) strlen(value))
cristy3ed852e2009-09-05 21:47:34 +00001296 (void) WriteBlobByte(image,'}');
1297 }
1298 (void) WriteBlobByte(image,'\n');
1299 property=GetNextImageProperty(image);
1300 }
1301 ResetImageArtifactIterator(image);
1302 (void) WriteBlobString(image,"\f\n:\032");
1303 if (image->montage != (char *) NULL)
1304 {
1305 /*
1306 Write montage tile directory.
1307 */
1308 if (image->directory != (char *) NULL)
1309 (void) WriteBlobString(image,image->directory);
1310 (void) WriteBlobByte(image,'\0');
1311 }
1312 if (image->profiles != 0)
1313 {
1314 const char
1315 *name;
1316
1317 const StringInfo
1318 *profile;
1319
1320 /*
1321 Write image profiles.
1322 */
1323 ResetImageProfileIterator(image);
1324 name=GetNextImageProfile(image);
1325 while (name != (const char *) NULL)
1326 {
1327 profile=GetImageProfile(image,name);
1328 (void) WriteBlob(image,GetStringInfoLength(profile),
1329 GetStringInfoDatum(profile));
1330 name=GetNextImageProfile(image);
1331 }
1332 }
1333 if (image->storage_class == PseudoClass)
1334 {
1335 size_t
1336 packet_size;
1337
1338 unsigned char
1339 *colormap,
1340 *q;
1341
1342 /*
1343 Allocate colormap.
1344 */
1345 packet_size=(size_t) (3UL*depth/8UL);
1346 colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
1347 packet_size*sizeof(*colormap));
1348 if (colormap == (unsigned char *) NULL)
1349 return(MagickFalse);
1350 /*
1351 Write colormap to file.
1352 */
1353 q=colormap;
cristybb503372010-05-27 20:51:26 +00001354 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00001355 {
1356 switch (depth)
1357 {
1358 default:
1359 ThrowWriterException(CorruptImageError,"ImageDepthNotSupported");
1360 case 32:
1361 {
cristy4cb162a2010-05-30 03:04:47 +00001362 unsigned int
cristy3ed852e2009-09-05 21:47:34 +00001363 pixel;
1364
1365 pixel=ScaleQuantumToLong(image->colormap[i].red);
1366 q=PopLongPixel(MSBEndian,pixel,q);
1367 pixel=ScaleQuantumToLong(image->colormap[i].green);
1368 q=PopLongPixel(MSBEndian,pixel,q);
1369 pixel=ScaleQuantumToLong(image->colormap[i].blue);
1370 q=PopLongPixel(MSBEndian,pixel,q);
1371 }
1372 case 16:
1373 {
1374 unsigned short
1375 pixel;
1376
1377 pixel=ScaleQuantumToShort(image->colormap[i].red);
1378 q=PopShortPixel(MSBEndian,pixel,q);
1379 pixel=ScaleQuantumToShort(image->colormap[i].green);
1380 q=PopShortPixel(MSBEndian,pixel,q);
1381 pixel=ScaleQuantumToShort(image->colormap[i].blue);
1382 q=PopShortPixel(MSBEndian,pixel,q);
1383 break;
1384 }
1385 case 8:
1386 {
1387 unsigned char
1388 pixel;
1389
1390 pixel=(unsigned char) ScaleQuantumToChar(image->colormap[i].red);
1391 q=PopCharPixel(pixel,q);
1392 pixel=(unsigned char) ScaleQuantumToChar(
1393 image->colormap[i].green);
1394 q=PopCharPixel(pixel,q);
1395 pixel=(unsigned char) ScaleQuantumToChar(image->colormap[i].blue);
1396 q=PopCharPixel(pixel,q);
1397 break;
1398 }
1399 }
1400 }
1401 (void) WriteBlob(image,packet_size*image->colors,colormap);
1402 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1403 }
1404 /*
1405 Initialize persistent pixel cache.
1406 */
1407 status=PersistPixelCache(image,cache_filename,MagickFalse,&offset,
cristy1e178e72011-08-28 19:44:34 +00001408 exception);
cristy3ed852e2009-09-05 21:47:34 +00001409 if (status == MagickFalse)
1410 ThrowWriterException(CacheError,"UnableToPersistPixelCache");
1411 if (GetNextImageInList(image) == (Image *) NULL)
1412 break;
1413 image=SyncNextImageInList(image);
1414 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1415 {
1416 status=image->progress_monitor(SaveImagesTag,scene,
1417 GetImageListLength(image),image->client_data);
1418 if (status == MagickFalse)
1419 break;
1420 }
1421 scene++;
1422 } while (image_info->adjoin != MagickFalse);
1423 (void) CloseBlob(image);
1424 return(status);
1425}