blob: 4046d3e4a750064cef04a57e83dbac762b6b8bfe [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% %
cristy1454be72011-12-19 01:52:48 +000020% Copyright 1999-2012 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);
cristyb880ee82012-04-07 15:08:14 +0000246 if (c == (int) '\\')
247 c=ReadBlobByte(image);
248 else
249 if ((c == EOF) || (c == (int) '}'))
250 break;
cristy3ed852e2009-09-05 21:47:34 +0000251 if ((size_t) (p-comment+1) >= length)
252 {
253 *p='\0';
254 length<<=1;
255 comment=(char *) ResizeQuantumMemory(comment,length+
256 MaxTextExtent,sizeof(*comment));
257 if (comment == (char *) NULL)
258 break;
259 p=comment+strlen(comment);
260 }
261 *p=(char) c;
262 }
263 if (comment == (char *) NULL)
264 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
265 *p='\0';
cristyd15e6592011-10-15 00:13:06 +0000266 (void) SetImageProperty(image,"comment",comment,exception);
cristy3ed852e2009-09-05 21:47:34 +0000267 comment=DestroyString(comment);
268 c=ReadBlobByte(image);
269 }
270 else
271 if (isalnum(c) != MagickFalse)
272 {
273 /*
274 Get the keyword.
275 */
276 p=keyword;
277 do
278 {
cristy3ed852e2009-09-05 21:47:34 +0000279 if (c == (int) '=')
280 break;
281 if ((size_t) (p-keyword) < (MaxTextExtent-1))
282 *p++=(char) c;
283 c=ReadBlobByte(image);
284 } while (c != EOF);
285 *p='\0';
286 p=options;
287 while (isspace((int) ((unsigned char) c)) != 0)
288 c=ReadBlobByte(image);
289 if (c == (int) '=')
290 {
291 /*
292 Get the keyword value.
293 */
294 c=ReadBlobByte(image);
295 while ((c != (int) '}') && (c != EOF))
296 {
297 if ((size_t) (p-options+1) >= length)
298 {
299 *p='\0';
300 length<<=1;
301 options=(char *) ResizeQuantumMemory(options,length+
302 MaxTextExtent,sizeof(*options));
303 if (options == (char *) NULL)
304 break;
305 p=options+strlen(options);
306 }
307 if (options == (char *) NULL)
308 ThrowReaderException(ResourceLimitError,
309 "MemoryAllocationFailed");
310 *p++=(char) c;
311 c=ReadBlobByte(image);
cristyb880ee82012-04-07 15:08:14 +0000312 if (c == '\\')
313 {
314 c=ReadBlobByte(image);
315 if (c == (int) '}')
316 {
317 *p++=(char) c;
318 c=ReadBlobByte(image);
319 }
320 }
cristy3ed852e2009-09-05 21:47:34 +0000321 if (*options != '{')
322 if (isspace((int) ((unsigned char) c)) != 0)
323 break;
324 }
325 }
326 *p='\0';
327 if (*options == '{')
328 (void) CopyMagickString(options,options+1,MaxTextExtent);
329 /*
330 Assign a value to the specified keyword.
331 */
332 switch (*keyword)
333 {
334 case 'b':
335 case 'B':
336 {
337 if (LocaleCompare(keyword,"background-color") == 0)
338 {
cristy9950d572011-10-01 18:22:35 +0000339 (void) QueryColorCompliance(options,AllCompliance,
340 &image->background_color,exception);
cristy3ed852e2009-09-05 21:47:34 +0000341 break;
342 }
343 if (LocaleCompare(keyword,"blue-primary") == 0)
344 {
345 flags=ParseGeometry(options,&geometry_info);
346 image->chromaticity.blue_primary.x=geometry_info.rho;
347 image->chromaticity.blue_primary.y=geometry_info.sigma;
348 if ((flags & SigmaValue) == 0)
349 image->chromaticity.blue_primary.y=
350 image->chromaticity.blue_primary.x;
351 break;
352 }
353 if (LocaleCompare(keyword,"border-color") == 0)
354 {
cristy9950d572011-10-01 18:22:35 +0000355 (void) QueryColorCompliance(options,AllCompliance,
356 &image->border_color,exception);
cristy3ed852e2009-09-05 21:47:34 +0000357 break;
358 }
cristyd15e6592011-10-15 00:13:06 +0000359 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000360 break;
361 }
362 case 'c':
363 case 'C':
364 {
365 if (LocaleCompare(keyword,"class") == 0)
366 {
cristybb503372010-05-27 20:51:26 +0000367 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000368 storage_class;
369
cristy042ee782011-04-22 18:48:30 +0000370 storage_class=ParseCommandOption(MagickClassOptions,
cristy3ed852e2009-09-05 21:47:34 +0000371 MagickFalse,options);
372 if (storage_class < 0)
373 break;
374 image->storage_class=(ClassType) storage_class;
375 break;
376 }
377 if (LocaleCompare(keyword,"colors") == 0)
378 {
cristye27293e2009-12-18 02:53:20 +0000379 image->colors=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000380 break;
381 }
382 if (LocaleCompare(keyword,"colorspace") == 0)
383 {
cristybb503372010-05-27 20:51:26 +0000384 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000385 colorspace;
386
cristy042ee782011-04-22 18:48:30 +0000387 colorspace=ParseCommandOption(MagickColorspaceOptions,
cristy3ed852e2009-09-05 21:47:34 +0000388 MagickFalse,options);
389 if (colorspace < 0)
390 break;
391 image->colorspace=(ColorspaceType) colorspace;
392 break;
393 }
394 if (LocaleCompare(keyword,"compression") == 0)
395 {
cristybb503372010-05-27 20:51:26 +0000396 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000397 compression;
398
cristy042ee782011-04-22 18:48:30 +0000399 compression=ParseCommandOption(MagickCompressOptions,
cristy3ed852e2009-09-05 21:47:34 +0000400 MagickFalse,options);
401 if (compression < 0)
402 break;
403 image->compression=(CompressionType) compression;
404 break;
405 }
406 if (LocaleCompare(keyword,"columns") == 0)
407 {
cristye27293e2009-12-18 02:53:20 +0000408 image->columns=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000409 break;
410 }
cristyd15e6592011-10-15 00:13:06 +0000411 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000412 break;
413 }
414 case 'd':
415 case 'D':
416 {
417 if (LocaleCompare(keyword,"delay") == 0)
418 {
cristye27293e2009-12-18 02:53:20 +0000419 image->delay=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000420 break;
421 }
422 if (LocaleCompare(keyword,"depth") == 0)
423 {
cristye27293e2009-12-18 02:53:20 +0000424 image->depth=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000425 break;
426 }
427 if (LocaleCompare(keyword,"dispose") == 0)
428 {
cristybb503372010-05-27 20:51:26 +0000429 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000430 dispose;
431
cristy042ee782011-04-22 18:48:30 +0000432 dispose=ParseCommandOption(MagickDisposeOptions,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000433 options);
434 if (dispose < 0)
435 break;
436 image->dispose=(DisposeType) dispose;
437 break;
438 }
cristyd15e6592011-10-15 00:13:06 +0000439 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000440 break;
441 }
442 case 'e':
443 case 'E':
444 {
445 if (LocaleCompare(keyword,"endian") == 0)
446 {
cristybb503372010-05-27 20:51:26 +0000447 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000448 endian;
449
cristy042ee782011-04-22 18:48:30 +0000450 endian=ParseCommandOption(MagickEndianOptions,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000451 options);
452 if (endian < 0)
453 break;
454 image->endian=(EndianType) endian;
455 break;
456 }
457 if (LocaleCompare(keyword,"error") == 0)
458 {
cristy9b34e302011-11-05 02:15:45 +0000459 image->error.mean_error_per_pixel=StringToDouble(options,
460 (char **) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000461 break;
462 }
cristyd15e6592011-10-15 00:13:06 +0000463 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000464 break;
465 }
466 case 'g':
467 case 'G':
468 {
469 if (LocaleCompare(keyword,"gamma") == 0)
470 {
cristydbdd0e32011-11-04 23:29:40 +0000471 image->gamma=StringToDouble(options,(char **) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000472 break;
473 }
474 if (LocaleCompare(keyword,"green-primary") == 0)
475 {
476 flags=ParseGeometry(options,&geometry_info);
477 image->chromaticity.green_primary.x=geometry_info.rho;
478 image->chromaticity.green_primary.y=geometry_info.sigma;
479 if ((flags & SigmaValue) == 0)
480 image->chromaticity.green_primary.y=
481 image->chromaticity.green_primary.x;
482 break;
483 }
cristyd15e6592011-10-15 00:13:06 +0000484 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000485 break;
486 }
487 case 'i':
488 case 'I':
489 {
490 if (LocaleCompare(keyword,"id") == 0)
491 {
492 (void) CopyMagickString(id,options,MaxTextExtent);
493 break;
494 }
495 if (LocaleCompare(keyword,"iterations") == 0)
496 {
cristye27293e2009-12-18 02:53:20 +0000497 image->iterations=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000498 break;
499 }
cristyd15e6592011-10-15 00:13:06 +0000500 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000501 break;
502 }
503 case 'm':
504 case 'M':
505 {
506 if (LocaleCompare(keyword,"matte") == 0)
507 {
cristybb503372010-05-27 20:51:26 +0000508 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000509 matte;
510
cristy042ee782011-04-22 18:48:30 +0000511 matte=ParseCommandOption(MagickBooleanOptions,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000512 options);
513 if (matte < 0)
514 break;
515 image->matte=(MagickBooleanType) matte;
516 break;
517 }
518 if (LocaleCompare(keyword,"matte-color") == 0)
519 {
cristy9950d572011-10-01 18:22:35 +0000520 (void) QueryColorCompliance(options,AllCompliance,
521 &image->matte_color,exception);
cristy3ed852e2009-09-05 21:47:34 +0000522 break;
523 }
524 if (LocaleCompare(keyword,"maximum-error") == 0)
525 {
cristy9b34e302011-11-05 02:15:45 +0000526 image->error.normalized_maximum_error=StringToDouble(
527 options,(char **) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000528 break;
529 }
530 if (LocaleCompare(keyword,"mean-error") == 0)
531 {
cristy9b34e302011-11-05 02:15:45 +0000532 image->error.normalized_mean_error=StringToDouble(options,
533 (char **) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000534 break;
535 }
536 if (LocaleCompare(keyword,"montage") == 0)
537 {
538 (void) CloneString(&image->montage,options);
539 break;
540 }
cristyd15e6592011-10-15 00:13:06 +0000541 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000542 break;
543 }
544 case 'o':
545 case 'O':
546 {
547 if (LocaleCompare(keyword,"opaque") == 0)
548 {
cristybb503372010-05-27 20:51:26 +0000549 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000550 matte;
551
cristy042ee782011-04-22 18:48:30 +0000552 matte=ParseCommandOption(MagickBooleanOptions,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000553 options);
554 if (matte < 0)
555 break;
556 image->matte=(MagickBooleanType) matte;
557 break;
558 }
559 if (LocaleCompare(keyword,"orientation") == 0)
560 {
cristybb503372010-05-27 20:51:26 +0000561 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000562 orientation;
563
cristy042ee782011-04-22 18:48:30 +0000564 orientation=ParseCommandOption(MagickOrientationOptions,
cristy3ed852e2009-09-05 21:47:34 +0000565 MagickFalse,options);
566 if (orientation < 0)
567 break;
568 image->orientation=(OrientationType) orientation;
569 break;
570 }
cristyd15e6592011-10-15 00:13:06 +0000571 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000572 break;
573 }
574 case 'p':
575 case 'P':
576 {
577 if (LocaleCompare(keyword,"page") == 0)
578 {
579 char
580 *geometry;
581
582 geometry=GetPageGeometry(options);
583 (void) ParseAbsoluteGeometry(geometry,&image->page);
584 geometry=DestroyString(geometry);
585 break;
586 }
587 if ((LocaleNCompare(keyword,"profile:",8) == 0) ||
588 (LocaleNCompare(keyword,"profile-",8) == 0))
589 {
590 if (profiles == (LinkedListInfo *) NULL)
591 profiles=NewLinkedList(0);
592 (void) AppendValueToLinkedList(profiles,
593 AcquireString(keyword+8));
cristy07c9bd62011-09-01 13:41:23 +0000594 profile=BlobToStringInfo((const void *) NULL,(size_t)
595 StringToLong(options));
cristy0381c632011-09-01 18:02:13 +0000596 if (profile == (StringInfo *) NULL)
cristy07c9bd62011-09-01 13:41:23 +0000597 ThrowReaderException(ResourceLimitError,
598 "MemoryAllocationFailed");
cristyd15e6592011-10-15 00:13:06 +0000599 (void) SetImageProfile(image,keyword+8,profile,exception);
cristy3ed852e2009-09-05 21:47:34 +0000600 profile=DestroyStringInfo(profile);
601 break;
602 }
cristyd15e6592011-10-15 00:13:06 +0000603 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000604 break;
605 }
606 case 'q':
607 case 'Q':
608 {
609 if (LocaleCompare(keyword,"quality") == 0)
610 {
cristye27293e2009-12-18 02:53:20 +0000611 image->quality=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000612 break;
613 }
614 if (LocaleCompare(keyword,"quantum-depth") == 0)
615 {
cristye27293e2009-12-18 02:53:20 +0000616 quantum_depth=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000617 break;
618 }
cristyd15e6592011-10-15 00:13:06 +0000619 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000620 break;
621 }
622 case 'r':
623 case 'R':
624 {
625 if (LocaleCompare(keyword,"red-primary") == 0)
626 {
627 flags=ParseGeometry(options,&geometry_info);
628 image->chromaticity.red_primary.x=geometry_info.rho;
629 if ((flags & SigmaValue) != 0)
630 image->chromaticity.red_primary.y=geometry_info.sigma;
631 break;
632 }
633 if (LocaleCompare(keyword,"rendering-intent") == 0)
634 {
cristybb503372010-05-27 20:51:26 +0000635 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000636 rendering_intent;
637
cristy042ee782011-04-22 18:48:30 +0000638 rendering_intent=ParseCommandOption(MagickIntentOptions,
cristy3ed852e2009-09-05 21:47:34 +0000639 MagickFalse,options);
640 if (rendering_intent < 0)
641 break;
642 image->rendering_intent=(RenderingIntent) rendering_intent;
643 break;
644 }
645 if (LocaleCompare(keyword,"resolution") == 0)
646 {
647 flags=ParseGeometry(options,&geometry_info);
cristy2a11bef2011-10-28 18:33:11 +0000648 image->resolution.x=geometry_info.rho;
649 image->resolution.y=geometry_info.sigma;
cristy3ed852e2009-09-05 21:47:34 +0000650 if ((flags & SigmaValue) == 0)
cristy2a11bef2011-10-28 18:33:11 +0000651 image->resolution.y=image->resolution.x;
cristy3ed852e2009-09-05 21:47:34 +0000652 break;
653 }
654 if (LocaleCompare(keyword,"rows") == 0)
655 {
cristye27293e2009-12-18 02:53:20 +0000656 image->rows=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000657 break;
658 }
cristyd15e6592011-10-15 00:13:06 +0000659 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000660 break;
661 }
662 case 's':
663 case 'S':
664 {
665 if (LocaleCompare(keyword,"scene") == 0)
666 {
cristye27293e2009-12-18 02:53:20 +0000667 image->scene=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000668 break;
669 }
cristyd15e6592011-10-15 00:13:06 +0000670 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000671 break;
672 }
673 case 't':
674 case 'T':
675 {
676 if (LocaleCompare(keyword,"ticks-per-second") == 0)
677 {
cristybb503372010-05-27 20:51:26 +0000678 image->ticks_per_second=(ssize_t) StringToLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000679 break;
680 }
681 if (LocaleCompare(keyword,"tile-offset") == 0)
682 {
683 char
684 *geometry;
685
686 geometry=GetPageGeometry(options);
687 (void) ParseAbsoluteGeometry(geometry,&image->tile_offset);
688 geometry=DestroyString(geometry);
689 }
690 if (LocaleCompare(keyword,"type") == 0)
691 {
cristybb503372010-05-27 20:51:26 +0000692 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000693 type;
694
cristy042ee782011-04-22 18:48:30 +0000695 type=ParseCommandOption(MagickTypeOptions,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000696 options);
697 if (type < 0)
698 break;
699 image->type=(ImageType) type;
700 break;
701 }
cristyd15e6592011-10-15 00:13:06 +0000702 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000703 break;
704 }
705 case 'u':
706 case 'U':
707 {
708 if (LocaleCompare(keyword,"units") == 0)
709 {
cristybb503372010-05-27 20:51:26 +0000710 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000711 units;
712
cristyd15e6592011-10-15 00:13:06 +0000713 units=ParseCommandOption(MagickResolutionOptions,
714 MagickFalse,options);
cristy3ed852e2009-09-05 21:47:34 +0000715 if (units < 0)
716 break;
717 image->units=(ResolutionType) units;
718 break;
719 }
cristyd15e6592011-10-15 00:13:06 +0000720 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000721 break;
722 }
723 case 'w':
724 case 'W':
725 {
726 if (LocaleCompare(keyword,"white-point") == 0)
727 {
728 flags=ParseGeometry(options,&geometry_info);
729 image->chromaticity.white_point.x=geometry_info.rho;
730 image->chromaticity.white_point.y=geometry_info.sigma;
731 if ((flags & SigmaValue) == 0)
732 image->chromaticity.white_point.y=
733 image->chromaticity.white_point.x;
734 break;
735 }
cristyd15e6592011-10-15 00:13:06 +0000736 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000737 break;
738 }
739 default:
740 {
cristyd15e6592011-10-15 00:13:06 +0000741 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000742 break;
743 }
744 }
745 }
746 else
747 c=ReadBlobByte(image);
748 while (isspace((int) ((unsigned char) c)) != 0)
749 c=ReadBlobByte(image);
750 }
751 options=DestroyString(options);
752 (void) ReadBlobByte(image);
753 /*
754 Verify that required image information is defined.
755 */
756 if ((LocaleCompare(id,"MagickCache") != 0) ||
757 (image->storage_class == UndefinedClass) ||
758 (image->compression == UndefinedCompression) || (image->columns == 0) ||
759 (image->rows == 0))
760 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
761 if (quantum_depth != MAGICKCORE_QUANTUM_DEPTH)
762 ThrowReaderException(CacheError,"InconsistentPersistentCacheDepth");
763 if (image->montage != (char *) NULL)
764 {
765 register char
766 *p;
767
768 /*
769 Image directory.
770 */
771 length=MaxTextExtent;
772 image->directory=AcquireString((char *) NULL);
773 p=image->directory;
774 do
775 {
776 *p='\0';
777 if ((strlen(image->directory)+MaxTextExtent) >= length)
778 {
779 /*
780 Allocate more memory for the image directory.
781 */
782 length<<=1;
783 image->directory=(char *) ResizeQuantumMemory(image->directory,
784 length+MaxTextExtent,sizeof(*image->directory));
785 if (image->directory == (char *) NULL)
786 ThrowReaderException(CorruptImageError,"UnableToReadImageData");
787 p=image->directory+strlen(image->directory);
788 }
789 c=ReadBlobByte(image);
790 *p++=(char) c;
791 } while (c != (int) '\0');
792 }
793 if (profiles != (LinkedListInfo *) NULL)
794 {
795 const char
796 *name;
797
798 const StringInfo
799 *profile;
800
801 register unsigned char
802 *p;
803
804 /*
805 Read image profiles.
806 */
807 ResetLinkedListIterator(profiles);
808 name=(const char *) GetNextValueInLinkedList(profiles);
809 while (name != (const char *) NULL)
810 {
811 profile=GetImageProfile(image,name);
812 if (profile != (StringInfo *) NULL)
813 {
814 p=GetStringInfoDatum(profile);
815 count=ReadBlob(image,GetStringInfoLength(profile),p);
816 }
817 name=(const char *) GetNextValueInLinkedList(profiles);
818 }
819 profiles=DestroyLinkedList(profiles,RelinquishMagickMemory);
820 }
821 depth=GetImageQuantumDepth(image,MagickFalse);
822 if (image->storage_class == PseudoClass)
823 {
824 /*
825 Create image colormap.
826 */
cristy018f07f2011-09-04 21:15:19 +0000827 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000828 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
829 if (image->colors != 0)
830 {
831 size_t
832 packet_size;
833
834 unsigned char
835 *colormap;
836
837 /*
838 Read image colormap from file.
839 */
840 packet_size=(size_t) (3UL*depth/8UL);
841 colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
842 packet_size*sizeof(*colormap));
843 if (colormap == (unsigned char *) NULL)
844 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
845 count=ReadBlob(image,packet_size*image->colors,colormap);
846 if (count != (ssize_t) (packet_size*image->colors))
847 ThrowReaderException(CorruptImageError,
848 "InsufficientImageDataInFile");
849 p=colormap;
850 switch (depth)
851 {
852 default:
853 ThrowReaderException(CorruptImageError,
854 "ImageDepthNotSupported");
855 case 8:
856 {
857 unsigned char
858 pixel;
859
cristybb503372010-05-27 20:51:26 +0000860 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +0000861 {
862 p=PushCharPixel(p,&pixel);
863 image->colormap[i].red=ScaleCharToQuantum(pixel);
864 p=PushCharPixel(p,&pixel);
865 image->colormap[i].green=ScaleCharToQuantum(pixel);
866 p=PushCharPixel(p,&pixel);
867 image->colormap[i].blue=ScaleCharToQuantum(pixel);
868 }
869 break;
870 }
871 case 16:
872 {
873 unsigned short
874 pixel;
875
cristybb503372010-05-27 20:51:26 +0000876 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +0000877 {
878 p=PushShortPixel(MSBEndian,p,&pixel);
879 image->colormap[i].red=ScaleShortToQuantum(pixel);
880 p=PushShortPixel(MSBEndian,p,&pixel);
881 image->colormap[i].green=ScaleShortToQuantum(pixel);
882 p=PushShortPixel(MSBEndian,p,&pixel);
883 image->colormap[i].blue=ScaleShortToQuantum(pixel);
884 }
885 break;
886 }
887 case 32:
888 {
cristy4cb162a2010-05-30 03:04:47 +0000889 unsigned int
cristy3ed852e2009-09-05 21:47:34 +0000890 pixel;
891
cristybb503372010-05-27 20:51:26 +0000892 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +0000893 {
894 p=PushLongPixel(MSBEndian,p,&pixel);
895 image->colormap[i].red=ScaleLongToQuantum(pixel);
896 p=PushLongPixel(MSBEndian,p,&pixel);
897 image->colormap[i].green=ScaleLongToQuantum(pixel);
898 p=PushLongPixel(MSBEndian,p,&pixel);
899 image->colormap[i].blue=ScaleLongToQuantum(pixel);
900 }
901 break;
902 }
903 }
904 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
905 }
906 }
907 if (EOFBlob(image) != MagickFalse)
908 {
909 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
910 image->filename);
911 break;
912 }
913 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
914 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
915 break;
916 /*
917 Attach persistent pixel cache.
918 */
919 status=PersistPixelCache(image,cache_filename,MagickTrue,&offset,exception);
920 if (status == MagickFalse)
921 ThrowReaderException(CacheError,"UnableToPersistPixelCache");
922 /*
923 Proceed to next image.
924 */
925 do
926 {
927 c=ReadBlobByte(image);
928 } while ((isgraph(c) == MagickFalse) && (c != EOF));
929 if (c != EOF)
930 {
931 /*
932 Allocate next image structure.
933 */
cristy9950d572011-10-01 18:22:35 +0000934 AcquireNextImage(image_info,image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000935 if (GetNextImageInList(image) == (Image *) NULL)
936 {
937 image=DestroyImageList(image);
938 return((Image *) NULL);
939 }
940 image=SyncNextImageInList(image);
941 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
942 GetBlobSize(image));
943 if (status == MagickFalse)
944 break;
945 }
946 } while (c != EOF);
947 (void) CloseBlob(image);
948 return(GetFirstImageInList(image));
949}
950
951/*
952%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
953% %
954% %
955% %
956% R e g i s t e r M P C I m a g e %
957% %
958% %
959% %
960%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
961%
962% RegisterMPCImage() adds properties for the Cache image format to
963% the list of supported formats. The properties include the image format
964% tag, a method to read and/or write the format, whether the format
965% supports the saving of more than one frame to the same file or blob,
966% whether the format supports native in-memory I/O, and a brief
967% description of the format.
968%
969% The format of the RegisterMPCImage method is:
970%
cristybb503372010-05-27 20:51:26 +0000971% size_t RegisterMPCImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000972%
973*/
cristybb503372010-05-27 20:51:26 +0000974ModuleExport size_t RegisterMPCImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000975{
976 MagickInfo
977 *entry;
978
979 entry=SetMagickInfo("CACHE");
980 entry->description=ConstantString("Magick Persistent Cache image format");
981 entry->module=ConstantString("CACHE");
982 entry->stealth=MagickTrue;
983 (void) RegisterMagickInfo(entry);
984 entry=SetMagickInfo("MPC");
985 entry->decoder=(DecodeImageHandler *) ReadMPCImage;
986 entry->encoder=(EncodeImageHandler *) WriteMPCImage;
987 entry->magick=(IsImageFormatHandler *) IsMPC;
988 entry->description=ConstantString("Magick Persistent Cache image format");
989 entry->module=ConstantString("MPC");
990 (void) RegisterMagickInfo(entry);
991 return(MagickImageCoderSignature);
992}
993
994/*
995%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
996% %
997% %
998% %
999% U n r e g i s t e r M P C I m a g e %
1000% %
1001% %
1002% %
1003%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1004%
1005% UnregisterMPCImage() removes format registrations made by the
1006% MPC module from the list of supported formats.
1007%
1008% The format of the UnregisterMPCImage method is:
1009%
1010% UnregisterMPCImage(void)
1011%
1012*/
1013ModuleExport void UnregisterMPCImage(void)
1014{
1015 (void) UnregisterMagickInfo("CACHE");
1016 (void) UnregisterMagickInfo("MPC");
1017}
1018
1019/*
1020%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1021% %
1022% %
1023% %
1024% W r i t e M P C I m a g e %
1025% %
1026% %
1027% %
1028%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1029%
1030% WriteMPCImage() writes an Magick Persistent Cache image to a file.
1031%
1032% The format of the WriteMPCImage method is:
1033%
cristy1e178e72011-08-28 19:44:34 +00001034% MagickBooleanType WriteMPCImage(const ImageInfo *image_info,
1035% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001036%
1037% A description of each parameter follows:
1038%
1039% o image_info: the image info.
1040%
1041% o image: the image.
1042%
cristy1e178e72011-08-28 19:44:34 +00001043% o exception: return any errors or warnings in this structure.
1044%
cristy3ed852e2009-09-05 21:47:34 +00001045*/
cristy1e178e72011-08-28 19:44:34 +00001046static MagickBooleanType WriteMPCImage(const ImageInfo *image_info,Image *image,
1047 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001048{
1049 char
1050 buffer[MaxTextExtent],
1051 cache_filename[MaxTextExtent];
1052
1053 const char
1054 *property,
1055 *value;
1056
1057 MagickBooleanType
1058 status;
1059
1060 MagickOffsetType
1061 offset,
1062 scene;
1063
cristybb503372010-05-27 20:51:26 +00001064 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001065 i;
1066
cristybb503372010-05-27 20:51:26 +00001067 size_t
cristyeaedf062010-05-29 22:36:02 +00001068 depth,
1069 one;
cristy3ed852e2009-09-05 21:47:34 +00001070
1071 /*
1072 Open persistent cache.
1073 */
1074 assert(image_info != (const ImageInfo *) NULL);
1075 assert(image_info->signature == MagickSignature);
1076 assert(image != (Image *) NULL);
1077 assert(image->signature == MagickSignature);
1078 if (image->debug != MagickFalse)
1079 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy3a37efd2011-08-28 20:31:03 +00001080 assert(exception != (ExceptionInfo *) NULL);
1081 assert(exception->signature == MagickSignature);
cristy1e178e72011-08-28 19:44:34 +00001082 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00001083 if (status == MagickFalse)
1084 return(status);
1085 (void) CopyMagickString(cache_filename,image->filename,MaxTextExtent);
1086 AppendImageFormat("cache",cache_filename);
1087 scene=0;
1088 offset=0;
cristyeaedf062010-05-29 22:36:02 +00001089 one=1;
cristy3ed852e2009-09-05 21:47:34 +00001090 do
1091 {
1092 /*
1093 Write persistent cache meta-information.
1094 */
1095 depth=GetImageQuantumDepth(image,MagickTrue);
1096 if ((image->storage_class == PseudoClass) &&
cristyeaedf062010-05-29 22:36:02 +00001097 (image->colors > (one << depth)))
cristy3ed852e2009-09-05 21:47:34 +00001098 image->storage_class=DirectClass;
1099 (void) WriteBlobString(image,"id=MagickCache\n");
cristyb51dff52011-05-19 16:55:47 +00001100 (void) FormatLocaleString(buffer,MaxTextExtent,"quantum-depth=%d\n",
cristy3ed852e2009-09-05 21:47:34 +00001101 MAGICKCORE_QUANTUM_DEPTH);
1102 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00001103 (void) FormatLocaleString(buffer,MaxTextExtent,
cristy042ee782011-04-22 18:48:30 +00001104 "class=%s colors=%.20g matte=%s\n",CommandOptionToMnemonic(
cristye8c25f92010-06-03 00:53:06 +00001105 MagickClassOptions,image->storage_class),(double) image->colors,
cristy042ee782011-04-22 18:48:30 +00001106 CommandOptionToMnemonic(MagickBooleanOptions,(ssize_t) image->matte));
cristy3ed852e2009-09-05 21:47:34 +00001107 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00001108 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001109 "columns=%.20g rows=%.20g depth=%.20g\n",(double) image->columns,
1110 (double) image->rows,(double) image->depth);
cristy3ed852e2009-09-05 21:47:34 +00001111 (void) WriteBlobString(image,buffer);
cristy5f1c1ff2010-12-23 21:38:06 +00001112 if (image->type != UndefinedType)
cristy3ed852e2009-09-05 21:47:34 +00001113 {
cristyb51dff52011-05-19 16:55:47 +00001114 (void) FormatLocaleString(buffer,MaxTextExtent,"type=%s\n",
cristy042ee782011-04-22 18:48:30 +00001115 CommandOptionToMnemonic(MagickTypeOptions,image->type));
cristy3ed852e2009-09-05 21:47:34 +00001116 (void) WriteBlobString(image,buffer);
1117 }
1118 if (image->colorspace != UndefinedColorspace)
1119 {
cristyb51dff52011-05-19 16:55:47 +00001120 (void) FormatLocaleString(buffer,MaxTextExtent,"colorspace=%s\n",
cristy042ee782011-04-22 18:48:30 +00001121 CommandOptionToMnemonic(MagickColorspaceOptions,image->colorspace));
cristy3ed852e2009-09-05 21:47:34 +00001122 (void) WriteBlobString(image,buffer);
1123 }
1124 if (image->endian != UndefinedEndian)
1125 {
cristyb51dff52011-05-19 16:55:47 +00001126 (void) FormatLocaleString(buffer,MaxTextExtent,"endian=%s\n",
cristy042ee782011-04-22 18:48:30 +00001127 CommandOptionToMnemonic(MagickEndianOptions,image->endian));
cristy3ed852e2009-09-05 21:47:34 +00001128 (void) WriteBlobString(image,buffer);
1129 }
1130 if (image->compression != UndefinedCompression)
1131 {
cristyb51dff52011-05-19 16:55:47 +00001132 (void) FormatLocaleString(buffer,MaxTextExtent,
cristy042ee782011-04-22 18:48:30 +00001133 "compression=%s quality=%.20g\n",CommandOptionToMnemonic(
cristye8c25f92010-06-03 00:53:06 +00001134 MagickCompressOptions,image->compression),(double) image->quality);
cristy3ed852e2009-09-05 21:47:34 +00001135 (void) WriteBlobString(image,buffer);
1136 }
1137 if (image->units != UndefinedResolution)
1138 {
cristyb51dff52011-05-19 16:55:47 +00001139 (void) FormatLocaleString(buffer,MaxTextExtent,"units=%s\n",
cristy042ee782011-04-22 18:48:30 +00001140 CommandOptionToMnemonic(MagickResolutionOptions,image->units));
cristy3ed852e2009-09-05 21:47:34 +00001141 (void) WriteBlobString(image,buffer);
1142 }
cristy2a11bef2011-10-28 18:33:11 +00001143 if ((image->resolution.x != 0) || (image->resolution.y != 0))
cristy3ed852e2009-09-05 21:47:34 +00001144 {
cristyb51dff52011-05-19 16:55:47 +00001145 (void) FormatLocaleString(buffer,MaxTextExtent,
cristy2a11bef2011-10-28 18:33:11 +00001146 "resolution=%gx%g\n",image->resolution.x,image->resolution.y);
cristy3ed852e2009-09-05 21:47:34 +00001147 (void) WriteBlobString(image,buffer);
1148 }
1149 if ((image->page.width != 0) || (image->page.height != 0))
1150 {
cristyb51dff52011-05-19 16:55:47 +00001151 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001152 "page=%.20gx%.20g%+.20g%+.20g\n",(double) image->page.width,(double)
1153 image->page.height,(double) image->page.x,(double) image->page.y);
cristy3ed852e2009-09-05 21:47:34 +00001154 (void) WriteBlobString(image,buffer);
1155 }
1156 else
1157 if ((image->page.x != 0) || (image->page.y != 0))
1158 {
cristyb51dff52011-05-19 16:55:47 +00001159 (void) FormatLocaleString(buffer,MaxTextExtent,"page=%+ld%+ld\n",
cristyf2faecf2010-05-28 19:19:36 +00001160 (long) image->page.x,(long) image->page.y);
cristy3ed852e2009-09-05 21:47:34 +00001161 (void) WriteBlobString(image,buffer);
1162 }
1163 if ((image->page.x != 0) || (image->page.y != 0))
1164 {
cristyb51dff52011-05-19 16:55:47 +00001165 (void) FormatLocaleString(buffer,MaxTextExtent,"tile-offset=%+ld%+ld\n",
cristyf2faecf2010-05-28 19:19:36 +00001166 (long) image->tile_offset.x,(long) image->tile_offset.y);
cristy3ed852e2009-09-05 21:47:34 +00001167 (void) WriteBlobString(image,buffer);
1168 }
1169 if ((GetNextImageInList(image) != (Image *) NULL) ||
1170 (GetPreviousImageInList(image) != (Image *) NULL))
1171 {
1172 if (image->scene == 0)
cristyb51dff52011-05-19 16:55:47 +00001173 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001174 "iterations=%.20g delay=%.20g ticks-per-second=%.20g\n",(double)
1175 image->iterations,(double) image->delay,(double)
cristyf2faecf2010-05-28 19:19:36 +00001176 image->ticks_per_second);
cristy3ed852e2009-09-05 21:47:34 +00001177 else
cristyb51dff52011-05-19 16:55:47 +00001178 (void) FormatLocaleString(buffer,MaxTextExtent,"scene=%.20g "
cristyaff6d802011-04-26 01:46:31 +00001179 "iterations=%.20g delay=%.20g ticks-per-second=%.20g\n",
cristye8c25f92010-06-03 00:53:06 +00001180 (double) image->scene,(double) image->iterations,(double)
1181 image->delay,(double) image->ticks_per_second);
cristy3ed852e2009-09-05 21:47:34 +00001182 (void) WriteBlobString(image,buffer);
1183 }
1184 else
1185 {
1186 if (image->scene != 0)
1187 {
cristyb51dff52011-05-19 16:55:47 +00001188 (void) FormatLocaleString(buffer,MaxTextExtent,"scene=%.20g\n",
cristye8c25f92010-06-03 00:53:06 +00001189 (double) image->scene);
cristy3ed852e2009-09-05 21:47:34 +00001190 (void) WriteBlobString(image,buffer);
1191 }
1192 if (image->iterations != 0)
1193 {
cristyb51dff52011-05-19 16:55:47 +00001194 (void) FormatLocaleString(buffer,MaxTextExtent,"iterations=%.20g\n",
cristye8c25f92010-06-03 00:53:06 +00001195 (double) image->iterations);
cristy3ed852e2009-09-05 21:47:34 +00001196 (void) WriteBlobString(image,buffer);
1197 }
1198 if (image->delay != 0)
1199 {
cristyb51dff52011-05-19 16:55:47 +00001200 (void) FormatLocaleString(buffer,MaxTextExtent,"delay=%.20g\n",
cristye8c25f92010-06-03 00:53:06 +00001201 (double) image->delay);
cristy3ed852e2009-09-05 21:47:34 +00001202 (void) WriteBlobString(image,buffer);
1203 }
1204 if (image->ticks_per_second != UndefinedTicksPerSecond)
1205 {
cristyb51dff52011-05-19 16:55:47 +00001206 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001207 "ticks-per-second=%.20g\n",(double) image->ticks_per_second);
cristy3ed852e2009-09-05 21:47:34 +00001208 (void) WriteBlobString(image,buffer);
1209 }
1210 }
1211 if (image->gravity != UndefinedGravity)
1212 {
cristyb51dff52011-05-19 16:55:47 +00001213 (void) FormatLocaleString(buffer,MaxTextExtent,"gravity=%s\n",
cristy042ee782011-04-22 18:48:30 +00001214 CommandOptionToMnemonic(MagickGravityOptions,image->gravity));
cristy3ed852e2009-09-05 21:47:34 +00001215 (void) WriteBlobString(image,buffer);
1216 }
1217 if (image->dispose != UndefinedDispose)
1218 {
cristyb51dff52011-05-19 16:55:47 +00001219 (void) FormatLocaleString(buffer,MaxTextExtent,"dispose=%s\n",
cristy042ee782011-04-22 18:48:30 +00001220 CommandOptionToMnemonic(MagickDisposeOptions,image->dispose));
cristy3ed852e2009-09-05 21:47:34 +00001221 (void) WriteBlobString(image,buffer);
1222 }
1223 if (image->rendering_intent != UndefinedIntent)
1224 {
cristyb51dff52011-05-19 16:55:47 +00001225 (void) FormatLocaleString(buffer,MaxTextExtent,
cristyaff6d802011-04-26 01:46:31 +00001226 "rendering-intent=%s\n",CommandOptionToMnemonic(MagickIntentOptions,
1227 image->rendering_intent));
cristy3ed852e2009-09-05 21:47:34 +00001228 (void) WriteBlobString(image,buffer);
1229 }
1230 if (image->gamma != 0.0)
1231 {
cristyb51dff52011-05-19 16:55:47 +00001232 (void) FormatLocaleString(buffer,MaxTextExtent,"gamma=%g\n",
cristy3ed852e2009-09-05 21:47:34 +00001233 image->gamma);
1234 (void) WriteBlobString(image,buffer);
1235 }
1236 if (image->chromaticity.white_point.x != 0.0)
1237 {
1238 /*
1239 Note chomaticity points.
1240 */
cristyb51dff52011-05-19 16:55:47 +00001241 (void) FormatLocaleString(buffer,MaxTextExtent,"red-primary="
cristye7f51092010-01-17 00:39:37 +00001242 "%g,%g green-primary=%g,%g blue-primary=%g,%g\n",
cristy3ed852e2009-09-05 21:47:34 +00001243 image->chromaticity.red_primary.x,image->chromaticity.red_primary.y,
1244 image->chromaticity.green_primary.x,
1245 image->chromaticity.green_primary.y,
1246 image->chromaticity.blue_primary.x,
1247 image->chromaticity.blue_primary.y);
1248 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00001249 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye7f51092010-01-17 00:39:37 +00001250 "white-point=%g,%g\n",image->chromaticity.white_point.x,
cristy8cd5b312010-01-07 01:10:24 +00001251 image->chromaticity.white_point.y);
cristy3ed852e2009-09-05 21:47:34 +00001252 (void) WriteBlobString(image,buffer);
1253 }
1254 if (image->orientation != UndefinedOrientation)
1255 {
cristyb51dff52011-05-19 16:55:47 +00001256 (void) FormatLocaleString(buffer,MaxTextExtent,
cristy042ee782011-04-22 18:48:30 +00001257 "orientation=%s\n",CommandOptionToMnemonic(MagickOrientationOptions,
cristy3ed852e2009-09-05 21:47:34 +00001258 image->orientation));
1259 (void) WriteBlobString(image,buffer);
1260 }
1261 if (image->profiles != (void *) NULL)
1262 {
1263 const char
1264 *name;
1265
1266 const StringInfo
1267 *profile;
1268
1269 /*
1270 Generic profile.
1271 */
1272 ResetImageProfileIterator(image);
1273 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1274 {
1275 profile=GetImageProfile(image,name);
1276 if (profile != (StringInfo *) NULL)
1277 {
cristyb51dff52011-05-19 16:55:47 +00001278 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001279 "profile:%s=%.20g\n",name,(double)
1280 GetStringInfoLength(profile));
cristy3ed852e2009-09-05 21:47:34 +00001281 (void) WriteBlobString(image,buffer);
1282 }
1283 name=GetNextImageProfile(image);
1284 }
1285 }
1286 if (image->montage != (char *) NULL)
1287 {
cristyb51dff52011-05-19 16:55:47 +00001288 (void) FormatLocaleString(buffer,MaxTextExtent,"montage=%s\n",
cristy3ed852e2009-09-05 21:47:34 +00001289 image->montage);
1290 (void) WriteBlobString(image,buffer);
1291 }
1292 ResetImagePropertyIterator(image);
1293 property=GetNextImageProperty(image);
1294 while (property != (const char *) NULL)
1295 {
cristyb51dff52011-05-19 16:55:47 +00001296 (void) FormatLocaleString(buffer,MaxTextExtent,"%s=",property);
cristy3ed852e2009-09-05 21:47:34 +00001297 (void) WriteBlobString(image,buffer);
cristyd15e6592011-10-15 00:13:06 +00001298 value=GetImageProperty(image,property,exception);
cristy3ed852e2009-09-05 21:47:34 +00001299 if (value != (const char *) NULL)
1300 {
cristybb503372010-05-27 20:51:26 +00001301 for (i=0; i < (ssize_t) strlen(value); i++)
cristy3ed852e2009-09-05 21:47:34 +00001302 if (isspace((int) ((unsigned char) value[i])) != 0)
1303 break;
cristyb880ee82012-04-07 15:08:14 +00001304 if (i == (ssize_t) strlen(value))
1305 (void) WriteBlob(image,strlen(value),(const unsigned char *) value);
1306 else
1307 {
1308 (void) WriteBlobByte(image,'{');
1309 for (i=0; i < (ssize_t) strlen(value); i++)
1310 {
1311 if (value[i] == (int) '}')
1312 (void) WriteBlobByte(image,'\\');
1313 (void) WriteBlobByte(image,value[i]);
1314 }
1315 (void) WriteBlobByte(image,'}');
1316 }
cristy3ed852e2009-09-05 21:47:34 +00001317 }
1318 (void) WriteBlobByte(image,'\n');
1319 property=GetNextImageProperty(image);
1320 }
1321 ResetImageArtifactIterator(image);
1322 (void) WriteBlobString(image,"\f\n:\032");
1323 if (image->montage != (char *) NULL)
1324 {
1325 /*
1326 Write montage tile directory.
1327 */
1328 if (image->directory != (char *) NULL)
1329 (void) WriteBlobString(image,image->directory);
1330 (void) WriteBlobByte(image,'\0');
1331 }
1332 if (image->profiles != 0)
1333 {
1334 const char
1335 *name;
1336
1337 const StringInfo
1338 *profile;
1339
1340 /*
1341 Write image profiles.
1342 */
1343 ResetImageProfileIterator(image);
1344 name=GetNextImageProfile(image);
1345 while (name != (const char *) NULL)
1346 {
1347 profile=GetImageProfile(image,name);
1348 (void) WriteBlob(image,GetStringInfoLength(profile),
1349 GetStringInfoDatum(profile));
1350 name=GetNextImageProfile(image);
1351 }
1352 }
1353 if (image->storage_class == PseudoClass)
1354 {
1355 size_t
1356 packet_size;
1357
1358 unsigned char
1359 *colormap,
1360 *q;
1361
1362 /*
1363 Allocate colormap.
1364 */
1365 packet_size=(size_t) (3UL*depth/8UL);
1366 colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
1367 packet_size*sizeof(*colormap));
1368 if (colormap == (unsigned char *) NULL)
1369 return(MagickFalse);
1370 /*
1371 Write colormap to file.
1372 */
1373 q=colormap;
cristybb503372010-05-27 20:51:26 +00001374 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00001375 {
1376 switch (depth)
1377 {
1378 default:
1379 ThrowWriterException(CorruptImageError,"ImageDepthNotSupported");
1380 case 32:
1381 {
cristy4cb162a2010-05-30 03:04:47 +00001382 unsigned int
cristy3ed852e2009-09-05 21:47:34 +00001383 pixel;
1384
1385 pixel=ScaleQuantumToLong(image->colormap[i].red);
1386 q=PopLongPixel(MSBEndian,pixel,q);
1387 pixel=ScaleQuantumToLong(image->colormap[i].green);
1388 q=PopLongPixel(MSBEndian,pixel,q);
1389 pixel=ScaleQuantumToLong(image->colormap[i].blue);
1390 q=PopLongPixel(MSBEndian,pixel,q);
1391 }
1392 case 16:
1393 {
1394 unsigned short
1395 pixel;
1396
1397 pixel=ScaleQuantumToShort(image->colormap[i].red);
1398 q=PopShortPixel(MSBEndian,pixel,q);
1399 pixel=ScaleQuantumToShort(image->colormap[i].green);
1400 q=PopShortPixel(MSBEndian,pixel,q);
1401 pixel=ScaleQuantumToShort(image->colormap[i].blue);
1402 q=PopShortPixel(MSBEndian,pixel,q);
1403 break;
1404 }
1405 case 8:
1406 {
1407 unsigned char
1408 pixel;
1409
1410 pixel=(unsigned char) ScaleQuantumToChar(image->colormap[i].red);
1411 q=PopCharPixel(pixel,q);
1412 pixel=(unsigned char) ScaleQuantumToChar(
1413 image->colormap[i].green);
1414 q=PopCharPixel(pixel,q);
1415 pixel=(unsigned char) ScaleQuantumToChar(image->colormap[i].blue);
1416 q=PopCharPixel(pixel,q);
1417 break;
1418 }
1419 }
1420 }
1421 (void) WriteBlob(image,packet_size*image->colors,colormap);
1422 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1423 }
1424 /*
1425 Initialize persistent pixel cache.
1426 */
1427 status=PersistPixelCache(image,cache_filename,MagickFalse,&offset,
cristy1e178e72011-08-28 19:44:34 +00001428 exception);
cristy3ed852e2009-09-05 21:47:34 +00001429 if (status == MagickFalse)
1430 ThrowWriterException(CacheError,"UnableToPersistPixelCache");
1431 if (GetNextImageInList(image) == (Image *) NULL)
1432 break;
1433 image=SyncNextImageInList(image);
1434 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1435 {
1436 status=image->progress_monitor(SaveImagesTag,scene,
1437 GetImageListLength(image),image->client_data);
1438 if (status == MagickFalse)
1439 break;
1440 }
1441 scene++;
1442 } while (image_info->adjoin != MagickFalse);
1443 (void) CloseBlob(image);
1444 return(status);
1445}