blob: 88ffa2d8f603bc902964c6f7955e06680a9b2c4a [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% %
cristy45ef08f2012-12-07 13:13:34 +000020% Copyright 1999-2013 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 == '{')
cristy01cd7302012-10-05 16:02:03 +0000328 (void) CopyMagickString(options,options+1,strlen(options));
cristy3ed852e2009-09-05 21:47:34 +0000329 /*
330 Assign a value to the specified keyword.
331 */
332 switch (*keyword)
333 {
cristy8a46d822012-08-28 23:32:39 +0000334 case 'a':
335 case 'A':
336 {
337 if (LocaleCompare(keyword,"alpha-trait") == 0)
338 {
339 ssize_t
340 alpha_trait;
341
342 alpha_trait=ParseCommandOption(MagickPixelTraitOptions,
343 MagickFalse,options);
344 if (alpha_trait < 0)
345 break;
346 image->alpha_trait=(PixelTrait) alpha_trait;
347 break;
348 }
349 (void) SetImageProperty(image,keyword,options,exception);
350 break;
351 }
cristy3ed852e2009-09-05 21:47:34 +0000352 case 'b':
353 case 'B':
354 {
355 if (LocaleCompare(keyword,"background-color") == 0)
356 {
cristy9950d572011-10-01 18:22:35 +0000357 (void) QueryColorCompliance(options,AllCompliance,
358 &image->background_color,exception);
cristy3ed852e2009-09-05 21:47:34 +0000359 break;
360 }
361 if (LocaleCompare(keyword,"blue-primary") == 0)
362 {
363 flags=ParseGeometry(options,&geometry_info);
364 image->chromaticity.blue_primary.x=geometry_info.rho;
365 image->chromaticity.blue_primary.y=geometry_info.sigma;
366 if ((flags & SigmaValue) == 0)
367 image->chromaticity.blue_primary.y=
368 image->chromaticity.blue_primary.x;
369 break;
370 }
371 if (LocaleCompare(keyword,"border-color") == 0)
372 {
cristy9950d572011-10-01 18:22:35 +0000373 (void) QueryColorCompliance(options,AllCompliance,
374 &image->border_color,exception);
cristy3ed852e2009-09-05 21:47:34 +0000375 break;
376 }
cristyd15e6592011-10-15 00:13:06 +0000377 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000378 break;
379 }
380 case 'c':
381 case 'C':
382 {
383 if (LocaleCompare(keyword,"class") == 0)
384 {
cristybb503372010-05-27 20:51:26 +0000385 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000386 storage_class;
387
cristy042ee782011-04-22 18:48:30 +0000388 storage_class=ParseCommandOption(MagickClassOptions,
cristy3ed852e2009-09-05 21:47:34 +0000389 MagickFalse,options);
390 if (storage_class < 0)
391 break;
392 image->storage_class=(ClassType) storage_class;
393 break;
394 }
395 if (LocaleCompare(keyword,"colors") == 0)
396 {
cristye27293e2009-12-18 02:53:20 +0000397 image->colors=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000398 break;
399 }
400 if (LocaleCompare(keyword,"colorspace") == 0)
401 {
cristybb503372010-05-27 20:51:26 +0000402 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000403 colorspace;
404
cristy042ee782011-04-22 18:48:30 +0000405 colorspace=ParseCommandOption(MagickColorspaceOptions,
cristy3ed852e2009-09-05 21:47:34 +0000406 MagickFalse,options);
407 if (colorspace < 0)
408 break;
cristy176b29a2012-06-21 13:35:15 +0000409 (void) SetImageColorspace(image,(ColorspaceType) colorspace, exception);
cristy3ed852e2009-09-05 21:47:34 +0000410 break;
411 }
412 if (LocaleCompare(keyword,"compression") == 0)
413 {
cristybb503372010-05-27 20:51:26 +0000414 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000415 compression;
416
cristy042ee782011-04-22 18:48:30 +0000417 compression=ParseCommandOption(MagickCompressOptions,
cristy3ed852e2009-09-05 21:47:34 +0000418 MagickFalse,options);
419 if (compression < 0)
420 break;
421 image->compression=(CompressionType) compression;
422 break;
423 }
424 if (LocaleCompare(keyword,"columns") == 0)
425 {
cristye27293e2009-12-18 02:53:20 +0000426 image->columns=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000427 break;
428 }
cristyd15e6592011-10-15 00:13:06 +0000429 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000430 break;
431 }
432 case 'd':
433 case 'D':
434 {
435 if (LocaleCompare(keyword,"delay") == 0)
436 {
cristye27293e2009-12-18 02:53:20 +0000437 image->delay=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000438 break;
439 }
440 if (LocaleCompare(keyword,"depth") == 0)
441 {
cristye27293e2009-12-18 02:53:20 +0000442 image->depth=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000443 break;
444 }
445 if (LocaleCompare(keyword,"dispose") == 0)
446 {
cristybb503372010-05-27 20:51:26 +0000447 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000448 dispose;
449
cristy042ee782011-04-22 18:48:30 +0000450 dispose=ParseCommandOption(MagickDisposeOptions,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000451 options);
452 if (dispose < 0)
453 break;
454 image->dispose=(DisposeType) dispose;
455 break;
456 }
cristyd15e6592011-10-15 00:13:06 +0000457 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000458 break;
459 }
460 case 'e':
461 case 'E':
462 {
463 if (LocaleCompare(keyword,"endian") == 0)
464 {
cristybb503372010-05-27 20:51:26 +0000465 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000466 endian;
467
cristy042ee782011-04-22 18:48:30 +0000468 endian=ParseCommandOption(MagickEndianOptions,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000469 options);
470 if (endian < 0)
471 break;
472 image->endian=(EndianType) endian;
473 break;
474 }
475 if (LocaleCompare(keyword,"error") == 0)
476 {
cristy9b34e302011-11-05 02:15:45 +0000477 image->error.mean_error_per_pixel=StringToDouble(options,
478 (char **) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000479 break;
480 }
cristyd15e6592011-10-15 00:13:06 +0000481 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000482 break;
483 }
484 case 'g':
485 case 'G':
486 {
487 if (LocaleCompare(keyword,"gamma") == 0)
488 {
cristydbdd0e32011-11-04 23:29:40 +0000489 image->gamma=StringToDouble(options,(char **) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000490 break;
491 }
492 if (LocaleCompare(keyword,"green-primary") == 0)
493 {
494 flags=ParseGeometry(options,&geometry_info);
495 image->chromaticity.green_primary.x=geometry_info.rho;
496 image->chromaticity.green_primary.y=geometry_info.sigma;
497 if ((flags & SigmaValue) == 0)
498 image->chromaticity.green_primary.y=
499 image->chromaticity.green_primary.x;
500 break;
501 }
cristyd15e6592011-10-15 00:13:06 +0000502 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000503 break;
504 }
505 case 'i':
506 case 'I':
507 {
508 if (LocaleCompare(keyword,"id") == 0)
509 {
510 (void) CopyMagickString(id,options,MaxTextExtent);
511 break;
512 }
513 if (LocaleCompare(keyword,"iterations") == 0)
514 {
cristye27293e2009-12-18 02:53:20 +0000515 image->iterations=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000516 break;
517 }
cristyd15e6592011-10-15 00:13:06 +0000518 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000519 break;
520 }
521 case 'm':
522 case 'M':
523 {
cristy3ed852e2009-09-05 21:47:34 +0000524 if (LocaleCompare(keyword,"matte-color") == 0)
525 {
cristy9950d572011-10-01 18:22:35 +0000526 (void) QueryColorCompliance(options,AllCompliance,
527 &image->matte_color,exception);
cristy3ed852e2009-09-05 21:47:34 +0000528 break;
529 }
530 if (LocaleCompare(keyword,"maximum-error") == 0)
531 {
cristy9b34e302011-11-05 02:15:45 +0000532 image->error.normalized_maximum_error=StringToDouble(
533 options,(char **) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000534 break;
535 }
536 if (LocaleCompare(keyword,"mean-error") == 0)
537 {
cristy9b34e302011-11-05 02:15:45 +0000538 image->error.normalized_mean_error=StringToDouble(options,
539 (char **) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000540 break;
541 }
542 if (LocaleCompare(keyword,"montage") == 0)
543 {
544 (void) CloneString(&image->montage,options);
545 break;
546 }
cristyd15e6592011-10-15 00:13:06 +0000547 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000548 break;
549 }
550 case 'o':
551 case 'O':
552 {
cristy3ed852e2009-09-05 21:47:34 +0000553 if (LocaleCompare(keyword,"orientation") == 0)
554 {
cristybb503372010-05-27 20:51:26 +0000555 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000556 orientation;
557
cristy042ee782011-04-22 18:48:30 +0000558 orientation=ParseCommandOption(MagickOrientationOptions,
cristy3ed852e2009-09-05 21:47:34 +0000559 MagickFalse,options);
560 if (orientation < 0)
561 break;
562 image->orientation=(OrientationType) orientation;
563 break;
564 }
cristyd15e6592011-10-15 00:13:06 +0000565 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000566 break;
567 }
568 case 'p':
569 case 'P':
570 {
571 if (LocaleCompare(keyword,"page") == 0)
572 {
573 char
574 *geometry;
575
576 geometry=GetPageGeometry(options);
577 (void) ParseAbsoluteGeometry(geometry,&image->page);
578 geometry=DestroyString(geometry);
579 break;
580 }
581 if ((LocaleNCompare(keyword,"profile:",8) == 0) ||
582 (LocaleNCompare(keyword,"profile-",8) == 0))
583 {
584 if (profiles == (LinkedListInfo *) NULL)
585 profiles=NewLinkedList(0);
586 (void) AppendValueToLinkedList(profiles,
587 AcquireString(keyword+8));
cristy07c9bd62011-09-01 13:41:23 +0000588 profile=BlobToStringInfo((const void *) NULL,(size_t)
589 StringToLong(options));
cristy0381c632011-09-01 18:02:13 +0000590 if (profile == (StringInfo *) NULL)
cristy07c9bd62011-09-01 13:41:23 +0000591 ThrowReaderException(ResourceLimitError,
592 "MemoryAllocationFailed");
cristyd15e6592011-10-15 00:13:06 +0000593 (void) SetImageProfile(image,keyword+8,profile,exception);
cristy3ed852e2009-09-05 21:47:34 +0000594 profile=DestroyStringInfo(profile);
595 break;
596 }
cristyd15e6592011-10-15 00:13:06 +0000597 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000598 break;
599 }
600 case 'q':
601 case 'Q':
602 {
603 if (LocaleCompare(keyword,"quality") == 0)
604 {
cristye27293e2009-12-18 02:53:20 +0000605 image->quality=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000606 break;
607 }
608 if (LocaleCompare(keyword,"quantum-depth") == 0)
609 {
cristye27293e2009-12-18 02:53:20 +0000610 quantum_depth=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000611 break;
612 }
cristyd15e6592011-10-15 00:13:06 +0000613 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000614 break;
615 }
616 case 'r':
617 case 'R':
618 {
619 if (LocaleCompare(keyword,"red-primary") == 0)
620 {
621 flags=ParseGeometry(options,&geometry_info);
622 image->chromaticity.red_primary.x=geometry_info.rho;
623 if ((flags & SigmaValue) != 0)
624 image->chromaticity.red_primary.y=geometry_info.sigma;
625 break;
626 }
627 if (LocaleCompare(keyword,"rendering-intent") == 0)
628 {
cristybb503372010-05-27 20:51:26 +0000629 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000630 rendering_intent;
631
cristy042ee782011-04-22 18:48:30 +0000632 rendering_intent=ParseCommandOption(MagickIntentOptions,
cristy3ed852e2009-09-05 21:47:34 +0000633 MagickFalse,options);
634 if (rendering_intent < 0)
635 break;
636 image->rendering_intent=(RenderingIntent) rendering_intent;
637 break;
638 }
639 if (LocaleCompare(keyword,"resolution") == 0)
640 {
641 flags=ParseGeometry(options,&geometry_info);
cristy2a11bef2011-10-28 18:33:11 +0000642 image->resolution.x=geometry_info.rho;
643 image->resolution.y=geometry_info.sigma;
cristy3ed852e2009-09-05 21:47:34 +0000644 if ((flags & SigmaValue) == 0)
cristy2a11bef2011-10-28 18:33:11 +0000645 image->resolution.y=image->resolution.x;
cristy3ed852e2009-09-05 21:47:34 +0000646 break;
647 }
648 if (LocaleCompare(keyword,"rows") == 0)
649 {
cristye27293e2009-12-18 02:53:20 +0000650 image->rows=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000651 break;
652 }
cristyd15e6592011-10-15 00:13:06 +0000653 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000654 break;
655 }
656 case 's':
657 case 'S':
658 {
659 if (LocaleCompare(keyword,"scene") == 0)
660 {
cristye27293e2009-12-18 02:53:20 +0000661 image->scene=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000662 break;
663 }
cristyd15e6592011-10-15 00:13:06 +0000664 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000665 break;
666 }
667 case 't':
668 case 'T':
669 {
670 if (LocaleCompare(keyword,"ticks-per-second") == 0)
671 {
cristybb503372010-05-27 20:51:26 +0000672 image->ticks_per_second=(ssize_t) StringToLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000673 break;
674 }
675 if (LocaleCompare(keyword,"tile-offset") == 0)
676 {
677 char
678 *geometry;
679
680 geometry=GetPageGeometry(options);
681 (void) ParseAbsoluteGeometry(geometry,&image->tile_offset);
682 geometry=DestroyString(geometry);
683 }
684 if (LocaleCompare(keyword,"type") == 0)
685 {
cristybb503372010-05-27 20:51:26 +0000686 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000687 type;
688
cristy042ee782011-04-22 18:48:30 +0000689 type=ParseCommandOption(MagickTypeOptions,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000690 options);
691 if (type < 0)
692 break;
693 image->type=(ImageType) type;
694 break;
695 }
cristyd15e6592011-10-15 00:13:06 +0000696 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000697 break;
698 }
699 case 'u':
700 case 'U':
701 {
702 if (LocaleCompare(keyword,"units") == 0)
703 {
cristybb503372010-05-27 20:51:26 +0000704 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000705 units;
706
cristyd15e6592011-10-15 00:13:06 +0000707 units=ParseCommandOption(MagickResolutionOptions,
708 MagickFalse,options);
cristy3ed852e2009-09-05 21:47:34 +0000709 if (units < 0)
710 break;
711 image->units=(ResolutionType) units;
712 break;
713 }
cristyd15e6592011-10-15 00:13:06 +0000714 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000715 break;
716 }
717 case 'w':
718 case 'W':
719 {
720 if (LocaleCompare(keyword,"white-point") == 0)
721 {
722 flags=ParseGeometry(options,&geometry_info);
723 image->chromaticity.white_point.x=geometry_info.rho;
724 image->chromaticity.white_point.y=geometry_info.sigma;
725 if ((flags & SigmaValue) == 0)
726 image->chromaticity.white_point.y=
727 image->chromaticity.white_point.x;
728 break;
729 }
cristyd15e6592011-10-15 00:13:06 +0000730 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000731 break;
732 }
733 default:
734 {
cristyd15e6592011-10-15 00:13:06 +0000735 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000736 break;
737 }
738 }
739 }
740 else
741 c=ReadBlobByte(image);
742 while (isspace((int) ((unsigned char) c)) != 0)
743 c=ReadBlobByte(image);
744 }
745 options=DestroyString(options);
746 (void) ReadBlobByte(image);
747 /*
748 Verify that required image information is defined.
749 */
750 if ((LocaleCompare(id,"MagickCache") != 0) ||
751 (image->storage_class == UndefinedClass) ||
752 (image->compression == UndefinedCompression) || (image->columns == 0) ||
753 (image->rows == 0))
754 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
755 if (quantum_depth != MAGICKCORE_QUANTUM_DEPTH)
756 ThrowReaderException(CacheError,"InconsistentPersistentCacheDepth");
757 if (image->montage != (char *) NULL)
758 {
759 register char
760 *p;
761
762 /*
763 Image directory.
764 */
765 length=MaxTextExtent;
766 image->directory=AcquireString((char *) NULL);
767 p=image->directory;
768 do
769 {
770 *p='\0';
771 if ((strlen(image->directory)+MaxTextExtent) >= length)
772 {
773 /*
774 Allocate more memory for the image directory.
775 */
776 length<<=1;
777 image->directory=(char *) ResizeQuantumMemory(image->directory,
778 length+MaxTextExtent,sizeof(*image->directory));
779 if (image->directory == (char *) NULL)
780 ThrowReaderException(CorruptImageError,"UnableToReadImageData");
781 p=image->directory+strlen(image->directory);
782 }
783 c=ReadBlobByte(image);
784 *p++=(char) c;
785 } while (c != (int) '\0');
786 }
787 if (profiles != (LinkedListInfo *) NULL)
788 {
789 const char
790 *name;
791
792 const StringInfo
793 *profile;
794
795 register unsigned char
796 *p;
797
798 /*
799 Read image profiles.
800 */
801 ResetLinkedListIterator(profiles);
802 name=(const char *) GetNextValueInLinkedList(profiles);
803 while (name != (const char *) NULL)
804 {
805 profile=GetImageProfile(image,name);
806 if (profile != (StringInfo *) NULL)
807 {
808 p=GetStringInfoDatum(profile);
809 count=ReadBlob(image,GetStringInfoLength(profile),p);
810 }
811 name=(const char *) GetNextValueInLinkedList(profiles);
812 }
813 profiles=DestroyLinkedList(profiles,RelinquishMagickMemory);
814 }
815 depth=GetImageQuantumDepth(image,MagickFalse);
816 if (image->storage_class == PseudoClass)
817 {
818 /*
819 Create image colormap.
820 */
cristy018f07f2011-09-04 21:15:19 +0000821 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000822 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
823 if (image->colors != 0)
824 {
825 size_t
826 packet_size;
827
828 unsigned char
829 *colormap;
830
831 /*
832 Read image colormap from file.
833 */
834 packet_size=(size_t) (3UL*depth/8UL);
835 colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
836 packet_size*sizeof(*colormap));
837 if (colormap == (unsigned char *) NULL)
838 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
839 count=ReadBlob(image,packet_size*image->colors,colormap);
840 if (count != (ssize_t) (packet_size*image->colors))
841 ThrowReaderException(CorruptImageError,
842 "InsufficientImageDataInFile");
843 p=colormap;
844 switch (depth)
845 {
846 default:
847 ThrowReaderException(CorruptImageError,
848 "ImageDepthNotSupported");
849 case 8:
850 {
851 unsigned char
852 pixel;
853
cristybb503372010-05-27 20:51:26 +0000854 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +0000855 {
856 p=PushCharPixel(p,&pixel);
857 image->colormap[i].red=ScaleCharToQuantum(pixel);
858 p=PushCharPixel(p,&pixel);
859 image->colormap[i].green=ScaleCharToQuantum(pixel);
860 p=PushCharPixel(p,&pixel);
861 image->colormap[i].blue=ScaleCharToQuantum(pixel);
862 }
863 break;
864 }
865 case 16:
866 {
867 unsigned short
868 pixel;
869
cristybb503372010-05-27 20:51:26 +0000870 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +0000871 {
872 p=PushShortPixel(MSBEndian,p,&pixel);
873 image->colormap[i].red=ScaleShortToQuantum(pixel);
874 p=PushShortPixel(MSBEndian,p,&pixel);
875 image->colormap[i].green=ScaleShortToQuantum(pixel);
876 p=PushShortPixel(MSBEndian,p,&pixel);
877 image->colormap[i].blue=ScaleShortToQuantum(pixel);
878 }
879 break;
880 }
881 case 32:
882 {
cristy4cb162a2010-05-30 03:04:47 +0000883 unsigned int
cristy3ed852e2009-09-05 21:47:34 +0000884 pixel;
885
cristybb503372010-05-27 20:51:26 +0000886 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +0000887 {
888 p=PushLongPixel(MSBEndian,p,&pixel);
889 image->colormap[i].red=ScaleLongToQuantum(pixel);
890 p=PushLongPixel(MSBEndian,p,&pixel);
891 image->colormap[i].green=ScaleLongToQuantum(pixel);
892 p=PushLongPixel(MSBEndian,p,&pixel);
893 image->colormap[i].blue=ScaleLongToQuantum(pixel);
894 }
895 break;
896 }
897 }
898 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
899 }
900 }
901 if (EOFBlob(image) != MagickFalse)
902 {
903 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
904 image->filename);
905 break;
906 }
907 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
908 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
909 break;
910 /*
911 Attach persistent pixel cache.
912 */
913 status=PersistPixelCache(image,cache_filename,MagickTrue,&offset,exception);
914 if (status == MagickFalse)
915 ThrowReaderException(CacheError,"UnableToPersistPixelCache");
916 /*
917 Proceed to next image.
918 */
919 do
920 {
921 c=ReadBlobByte(image);
922 } while ((isgraph(c) == MagickFalse) && (c != EOF));
923 if (c != EOF)
924 {
925 /*
926 Allocate next image structure.
927 */
cristy9950d572011-10-01 18:22:35 +0000928 AcquireNextImage(image_info,image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000929 if (GetNextImageInList(image) == (Image *) NULL)
930 {
931 image=DestroyImageList(image);
932 return((Image *) NULL);
933 }
934 image=SyncNextImageInList(image);
935 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
936 GetBlobSize(image));
937 if (status == MagickFalse)
938 break;
939 }
940 } while (c != EOF);
941 (void) CloseBlob(image);
942 return(GetFirstImageInList(image));
943}
944
945/*
946%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
947% %
948% %
949% %
950% R e g i s t e r M P C I m a g e %
951% %
952% %
953% %
954%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
955%
956% RegisterMPCImage() adds properties for the Cache image format to
957% the list of supported formats. The properties include the image format
958% tag, a method to read and/or write the format, whether the format
959% supports the saving of more than one frame to the same file or blob,
960% whether the format supports native in-memory I/O, and a brief
961% description of the format.
962%
963% The format of the RegisterMPCImage method is:
964%
cristybb503372010-05-27 20:51:26 +0000965% size_t RegisterMPCImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000966%
967*/
cristybb503372010-05-27 20:51:26 +0000968ModuleExport size_t RegisterMPCImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000969{
970 MagickInfo
971 *entry;
972
973 entry=SetMagickInfo("CACHE");
974 entry->description=ConstantString("Magick Persistent Cache image format");
975 entry->module=ConstantString("CACHE");
976 entry->stealth=MagickTrue;
977 (void) RegisterMagickInfo(entry);
978 entry=SetMagickInfo("MPC");
979 entry->decoder=(DecodeImageHandler *) ReadMPCImage;
980 entry->encoder=(EncodeImageHandler *) WriteMPCImage;
981 entry->magick=(IsImageFormatHandler *) IsMPC;
982 entry->description=ConstantString("Magick Persistent Cache image format");
983 entry->module=ConstantString("MPC");
984 (void) RegisterMagickInfo(entry);
985 return(MagickImageCoderSignature);
986}
987
988/*
989%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
990% %
991% %
992% %
993% U n r e g i s t e r M P C I m a g e %
994% %
995% %
996% %
997%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
998%
999% UnregisterMPCImage() removes format registrations made by the
1000% MPC module from the list of supported formats.
1001%
1002% The format of the UnregisterMPCImage method is:
1003%
1004% UnregisterMPCImage(void)
1005%
1006*/
1007ModuleExport void UnregisterMPCImage(void)
1008{
1009 (void) UnregisterMagickInfo("CACHE");
1010 (void) UnregisterMagickInfo("MPC");
1011}
1012
1013/*
1014%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1015% %
1016% %
1017% %
1018% W r i t e M P C I m a g e %
1019% %
1020% %
1021% %
1022%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1023%
1024% WriteMPCImage() writes an Magick Persistent Cache image to a file.
1025%
1026% The format of the WriteMPCImage method is:
1027%
cristy1e178e72011-08-28 19:44:34 +00001028% MagickBooleanType WriteMPCImage(const ImageInfo *image_info,
1029% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001030%
1031% A description of each parameter follows:
1032%
1033% o image_info: the image info.
1034%
1035% o image: the image.
1036%
cristy1e178e72011-08-28 19:44:34 +00001037% o exception: return any errors or warnings in this structure.
1038%
cristy3ed852e2009-09-05 21:47:34 +00001039*/
cristy1e178e72011-08-28 19:44:34 +00001040static MagickBooleanType WriteMPCImage(const ImageInfo *image_info,Image *image,
1041 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001042{
1043 char
1044 buffer[MaxTextExtent],
1045 cache_filename[MaxTextExtent];
1046
1047 const char
1048 *property,
1049 *value;
1050
1051 MagickBooleanType
1052 status;
1053
1054 MagickOffsetType
1055 offset,
1056 scene;
1057
cristybb503372010-05-27 20:51:26 +00001058 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001059 i;
1060
cristybb503372010-05-27 20:51:26 +00001061 size_t
cristyeaedf062010-05-29 22:36:02 +00001062 depth,
1063 one;
cristy3ed852e2009-09-05 21:47:34 +00001064
1065 /*
1066 Open persistent cache.
1067 */
1068 assert(image_info != (const ImageInfo *) NULL);
1069 assert(image_info->signature == MagickSignature);
1070 assert(image != (Image *) NULL);
1071 assert(image->signature == MagickSignature);
1072 if (image->debug != MagickFalse)
1073 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy3a37efd2011-08-28 20:31:03 +00001074 assert(exception != (ExceptionInfo *) NULL);
1075 assert(exception->signature == MagickSignature);
cristy1e178e72011-08-28 19:44:34 +00001076 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00001077 if (status == MagickFalse)
1078 return(status);
1079 (void) CopyMagickString(cache_filename,image->filename,MaxTextExtent);
1080 AppendImageFormat("cache",cache_filename);
1081 scene=0;
1082 offset=0;
cristyeaedf062010-05-29 22:36:02 +00001083 one=1;
cristy3ed852e2009-09-05 21:47:34 +00001084 do
1085 {
1086 /*
1087 Write persistent cache meta-information.
1088 */
1089 depth=GetImageQuantumDepth(image,MagickTrue);
1090 if ((image->storage_class == PseudoClass) &&
cristyeaedf062010-05-29 22:36:02 +00001091 (image->colors > (one << depth)))
cristy3ed852e2009-09-05 21:47:34 +00001092 image->storage_class=DirectClass;
1093 (void) WriteBlobString(image,"id=MagickCache\n");
cristyb51dff52011-05-19 16:55:47 +00001094 (void) FormatLocaleString(buffer,MaxTextExtent,"quantum-depth=%d\n",
cristy3ed852e2009-09-05 21:47:34 +00001095 MAGICKCORE_QUANTUM_DEPTH);
1096 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00001097 (void) FormatLocaleString(buffer,MaxTextExtent,
cristy8a46d822012-08-28 23:32:39 +00001098 "class=%s colors=%.20g alpha-trait=%s\n",CommandOptionToMnemonic(
cristye8c25f92010-06-03 00:53:06 +00001099 MagickClassOptions,image->storage_class),(double) image->colors,
cristy8a46d822012-08-28 23:32:39 +00001100 CommandOptionToMnemonic(MagickPixelTraitOptions,(ssize_t)
1101 image->alpha_trait));
cristy3ed852e2009-09-05 21:47:34 +00001102 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00001103 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001104 "columns=%.20g rows=%.20g depth=%.20g\n",(double) image->columns,
1105 (double) image->rows,(double) image->depth);
cristy3ed852e2009-09-05 21:47:34 +00001106 (void) WriteBlobString(image,buffer);
cristy5f1c1ff2010-12-23 21:38:06 +00001107 if (image->type != UndefinedType)
cristy3ed852e2009-09-05 21:47:34 +00001108 {
cristyb51dff52011-05-19 16:55:47 +00001109 (void) FormatLocaleString(buffer,MaxTextExtent,"type=%s\n",
cristy042ee782011-04-22 18:48:30 +00001110 CommandOptionToMnemonic(MagickTypeOptions,image->type));
cristy3ed852e2009-09-05 21:47:34 +00001111 (void) WriteBlobString(image,buffer);
1112 }
1113 if (image->colorspace != UndefinedColorspace)
1114 {
cristyb51dff52011-05-19 16:55:47 +00001115 (void) FormatLocaleString(buffer,MaxTextExtent,"colorspace=%s\n",
cristy042ee782011-04-22 18:48:30 +00001116 CommandOptionToMnemonic(MagickColorspaceOptions,image->colorspace));
cristy3ed852e2009-09-05 21:47:34 +00001117 (void) WriteBlobString(image,buffer);
1118 }
1119 if (image->endian != UndefinedEndian)
1120 {
cristyb51dff52011-05-19 16:55:47 +00001121 (void) FormatLocaleString(buffer,MaxTextExtent,"endian=%s\n",
cristy042ee782011-04-22 18:48:30 +00001122 CommandOptionToMnemonic(MagickEndianOptions,image->endian));
cristy3ed852e2009-09-05 21:47:34 +00001123 (void) WriteBlobString(image,buffer);
1124 }
1125 if (image->compression != UndefinedCompression)
1126 {
cristyb51dff52011-05-19 16:55:47 +00001127 (void) FormatLocaleString(buffer,MaxTextExtent,
cristy042ee782011-04-22 18:48:30 +00001128 "compression=%s quality=%.20g\n",CommandOptionToMnemonic(
cristye8c25f92010-06-03 00:53:06 +00001129 MagickCompressOptions,image->compression),(double) image->quality);
cristy3ed852e2009-09-05 21:47:34 +00001130 (void) WriteBlobString(image,buffer);
1131 }
1132 if (image->units != UndefinedResolution)
1133 {
cristyb51dff52011-05-19 16:55:47 +00001134 (void) FormatLocaleString(buffer,MaxTextExtent,"units=%s\n",
cristy042ee782011-04-22 18:48:30 +00001135 CommandOptionToMnemonic(MagickResolutionOptions,image->units));
cristy3ed852e2009-09-05 21:47:34 +00001136 (void) WriteBlobString(image,buffer);
1137 }
cristy2a11bef2011-10-28 18:33:11 +00001138 if ((image->resolution.x != 0) || (image->resolution.y != 0))
cristy3ed852e2009-09-05 21:47:34 +00001139 {
cristyb51dff52011-05-19 16:55:47 +00001140 (void) FormatLocaleString(buffer,MaxTextExtent,
cristy2a11bef2011-10-28 18:33:11 +00001141 "resolution=%gx%g\n",image->resolution.x,image->resolution.y);
cristy3ed852e2009-09-05 21:47:34 +00001142 (void) WriteBlobString(image,buffer);
1143 }
1144 if ((image->page.width != 0) || (image->page.height != 0))
1145 {
cristyb51dff52011-05-19 16:55:47 +00001146 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001147 "page=%.20gx%.20g%+.20g%+.20g\n",(double) image->page.width,(double)
1148 image->page.height,(double) image->page.x,(double) image->page.y);
cristy3ed852e2009-09-05 21:47:34 +00001149 (void) WriteBlobString(image,buffer);
1150 }
1151 else
1152 if ((image->page.x != 0) || (image->page.y != 0))
1153 {
cristyb51dff52011-05-19 16:55:47 +00001154 (void) FormatLocaleString(buffer,MaxTextExtent,"page=%+ld%+ld\n",
cristyf2faecf2010-05-28 19:19:36 +00001155 (long) image->page.x,(long) image->page.y);
cristy3ed852e2009-09-05 21:47:34 +00001156 (void) WriteBlobString(image,buffer);
1157 }
1158 if ((image->page.x != 0) || (image->page.y != 0))
1159 {
cristyb51dff52011-05-19 16:55:47 +00001160 (void) FormatLocaleString(buffer,MaxTextExtent,"tile-offset=%+ld%+ld\n",
cristyf2faecf2010-05-28 19:19:36 +00001161 (long) image->tile_offset.x,(long) image->tile_offset.y);
cristy3ed852e2009-09-05 21:47:34 +00001162 (void) WriteBlobString(image,buffer);
1163 }
1164 if ((GetNextImageInList(image) != (Image *) NULL) ||
1165 (GetPreviousImageInList(image) != (Image *) NULL))
1166 {
1167 if (image->scene == 0)
cristyb51dff52011-05-19 16:55:47 +00001168 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001169 "iterations=%.20g delay=%.20g ticks-per-second=%.20g\n",(double)
1170 image->iterations,(double) image->delay,(double)
cristyf2faecf2010-05-28 19:19:36 +00001171 image->ticks_per_second);
cristy3ed852e2009-09-05 21:47:34 +00001172 else
cristyb51dff52011-05-19 16:55:47 +00001173 (void) FormatLocaleString(buffer,MaxTextExtent,"scene=%.20g "
cristyaff6d802011-04-26 01:46:31 +00001174 "iterations=%.20g delay=%.20g ticks-per-second=%.20g\n",
cristye8c25f92010-06-03 00:53:06 +00001175 (double) image->scene,(double) image->iterations,(double)
1176 image->delay,(double) image->ticks_per_second);
cristy3ed852e2009-09-05 21:47:34 +00001177 (void) WriteBlobString(image,buffer);
1178 }
1179 else
1180 {
1181 if (image->scene != 0)
1182 {
cristyb51dff52011-05-19 16:55:47 +00001183 (void) FormatLocaleString(buffer,MaxTextExtent,"scene=%.20g\n",
cristye8c25f92010-06-03 00:53:06 +00001184 (double) image->scene);
cristy3ed852e2009-09-05 21:47:34 +00001185 (void) WriteBlobString(image,buffer);
1186 }
1187 if (image->iterations != 0)
1188 {
cristyb51dff52011-05-19 16:55:47 +00001189 (void) FormatLocaleString(buffer,MaxTextExtent,"iterations=%.20g\n",
cristye8c25f92010-06-03 00:53:06 +00001190 (double) image->iterations);
cristy3ed852e2009-09-05 21:47:34 +00001191 (void) WriteBlobString(image,buffer);
1192 }
1193 if (image->delay != 0)
1194 {
cristyb51dff52011-05-19 16:55:47 +00001195 (void) FormatLocaleString(buffer,MaxTextExtent,"delay=%.20g\n",
cristye8c25f92010-06-03 00:53:06 +00001196 (double) image->delay);
cristy3ed852e2009-09-05 21:47:34 +00001197 (void) WriteBlobString(image,buffer);
1198 }
1199 if (image->ticks_per_second != UndefinedTicksPerSecond)
1200 {
cristyb51dff52011-05-19 16:55:47 +00001201 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001202 "ticks-per-second=%.20g\n",(double) image->ticks_per_second);
cristy3ed852e2009-09-05 21:47:34 +00001203 (void) WriteBlobString(image,buffer);
1204 }
1205 }
1206 if (image->gravity != UndefinedGravity)
1207 {
cristyb51dff52011-05-19 16:55:47 +00001208 (void) FormatLocaleString(buffer,MaxTextExtent,"gravity=%s\n",
cristy042ee782011-04-22 18:48:30 +00001209 CommandOptionToMnemonic(MagickGravityOptions,image->gravity));
cristy3ed852e2009-09-05 21:47:34 +00001210 (void) WriteBlobString(image,buffer);
1211 }
1212 if (image->dispose != UndefinedDispose)
1213 {
cristyb51dff52011-05-19 16:55:47 +00001214 (void) FormatLocaleString(buffer,MaxTextExtent,"dispose=%s\n",
cristy042ee782011-04-22 18:48:30 +00001215 CommandOptionToMnemonic(MagickDisposeOptions,image->dispose));
cristy3ed852e2009-09-05 21:47:34 +00001216 (void) WriteBlobString(image,buffer);
1217 }
1218 if (image->rendering_intent != UndefinedIntent)
1219 {
cristyb51dff52011-05-19 16:55:47 +00001220 (void) FormatLocaleString(buffer,MaxTextExtent,
cristyaff6d802011-04-26 01:46:31 +00001221 "rendering-intent=%s\n",CommandOptionToMnemonic(MagickIntentOptions,
1222 image->rendering_intent));
cristy3ed852e2009-09-05 21:47:34 +00001223 (void) WriteBlobString(image,buffer);
1224 }
1225 if (image->gamma != 0.0)
1226 {
cristyb51dff52011-05-19 16:55:47 +00001227 (void) FormatLocaleString(buffer,MaxTextExtent,"gamma=%g\n",
cristy3ed852e2009-09-05 21:47:34 +00001228 image->gamma);
1229 (void) WriteBlobString(image,buffer);
1230 }
1231 if (image->chromaticity.white_point.x != 0.0)
1232 {
1233 /*
1234 Note chomaticity points.
1235 */
cristyb51dff52011-05-19 16:55:47 +00001236 (void) FormatLocaleString(buffer,MaxTextExtent,"red-primary="
cristye7f51092010-01-17 00:39:37 +00001237 "%g,%g green-primary=%g,%g blue-primary=%g,%g\n",
cristy3ed852e2009-09-05 21:47:34 +00001238 image->chromaticity.red_primary.x,image->chromaticity.red_primary.y,
1239 image->chromaticity.green_primary.x,
1240 image->chromaticity.green_primary.y,
1241 image->chromaticity.blue_primary.x,
1242 image->chromaticity.blue_primary.y);
1243 (void) WriteBlobString(image,buffer);
cristyb51dff52011-05-19 16:55:47 +00001244 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye7f51092010-01-17 00:39:37 +00001245 "white-point=%g,%g\n",image->chromaticity.white_point.x,
cristy8cd5b312010-01-07 01:10:24 +00001246 image->chromaticity.white_point.y);
cristy3ed852e2009-09-05 21:47:34 +00001247 (void) WriteBlobString(image,buffer);
1248 }
1249 if (image->orientation != UndefinedOrientation)
1250 {
cristyb51dff52011-05-19 16:55:47 +00001251 (void) FormatLocaleString(buffer,MaxTextExtent,
cristy042ee782011-04-22 18:48:30 +00001252 "orientation=%s\n",CommandOptionToMnemonic(MagickOrientationOptions,
cristy3ed852e2009-09-05 21:47:34 +00001253 image->orientation));
1254 (void) WriteBlobString(image,buffer);
1255 }
1256 if (image->profiles != (void *) NULL)
1257 {
1258 const char
1259 *name;
1260
1261 const StringInfo
1262 *profile;
1263
1264 /*
1265 Generic profile.
1266 */
1267 ResetImageProfileIterator(image);
1268 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1269 {
1270 profile=GetImageProfile(image,name);
1271 if (profile != (StringInfo *) NULL)
1272 {
cristyb51dff52011-05-19 16:55:47 +00001273 (void) FormatLocaleString(buffer,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00001274 "profile:%s=%.20g\n",name,(double)
1275 GetStringInfoLength(profile));
cristy3ed852e2009-09-05 21:47:34 +00001276 (void) WriteBlobString(image,buffer);
1277 }
1278 name=GetNextImageProfile(image);
1279 }
1280 }
1281 if (image->montage != (char *) NULL)
1282 {
cristyb51dff52011-05-19 16:55:47 +00001283 (void) FormatLocaleString(buffer,MaxTextExtent,"montage=%s\n",
cristy3ed852e2009-09-05 21:47:34 +00001284 image->montage);
1285 (void) WriteBlobString(image,buffer);
1286 }
1287 ResetImagePropertyIterator(image);
1288 property=GetNextImageProperty(image);
1289 while (property != (const char *) NULL)
1290 {
cristyb51dff52011-05-19 16:55:47 +00001291 (void) FormatLocaleString(buffer,MaxTextExtent,"%s=",property);
cristy3ed852e2009-09-05 21:47:34 +00001292 (void) WriteBlobString(image,buffer);
cristyd15e6592011-10-15 00:13:06 +00001293 value=GetImageProperty(image,property,exception);
cristy3ed852e2009-09-05 21:47:34 +00001294 if (value != (const char *) NULL)
1295 {
cristyd76ed5d2012-05-20 16:15:57 +00001296 size_t
1297 length;
1298
cristy181c99c2012-05-20 16:14:14 +00001299 length=strlen(value);
1300 for (i=0; i < (ssize_t) length; i++)
cristy3ed852e2009-09-05 21:47:34 +00001301 if (isspace((int) ((unsigned char) value[i])) != 0)
1302 break;
cristy181c99c2012-05-20 16:14:14 +00001303 if (i == (ssize_t) length)
1304 (void) WriteBlob(image,length,(const unsigned char *) value);
cristyb880ee82012-04-07 15:08:14 +00001305 else
1306 {
1307 (void) WriteBlobByte(image,'{');
cristy181c99c2012-05-20 16:14:14 +00001308 if (strchr(value,'}') == (char *) NULL)
1309 (void) WriteBlob(image,length,(const unsigned char *) value);
1310 else
1311 for (i=0; i < (ssize_t) length; i++)
1312 {
1313 if (value[i] == (int) '}')
1314 (void) WriteBlobByte(image,'\\');
1315 (void) WriteBlobByte(image,value[i]);
1316 }
cristyb880ee82012-04-07 15:08:14 +00001317 (void) WriteBlobByte(image,'}');
1318 }
cristy3ed852e2009-09-05 21:47:34 +00001319 }
1320 (void) WriteBlobByte(image,'\n');
1321 property=GetNextImageProperty(image);
1322 }
1323 ResetImageArtifactIterator(image);
1324 (void) WriteBlobString(image,"\f\n:\032");
1325 if (image->montage != (char *) NULL)
1326 {
1327 /*
1328 Write montage tile directory.
1329 */
1330 if (image->directory != (char *) NULL)
1331 (void) WriteBlobString(image,image->directory);
1332 (void) WriteBlobByte(image,'\0');
1333 }
1334 if (image->profiles != 0)
1335 {
1336 const char
1337 *name;
1338
1339 const StringInfo
1340 *profile;
1341
1342 /*
1343 Write image profiles.
1344 */
1345 ResetImageProfileIterator(image);
1346 name=GetNextImageProfile(image);
1347 while (name != (const char *) NULL)
1348 {
1349 profile=GetImageProfile(image,name);
1350 (void) WriteBlob(image,GetStringInfoLength(profile),
1351 GetStringInfoDatum(profile));
1352 name=GetNextImageProfile(image);
1353 }
1354 }
1355 if (image->storage_class == PseudoClass)
1356 {
1357 size_t
1358 packet_size;
1359
1360 unsigned char
1361 *colormap,
1362 *q;
1363
1364 /*
1365 Allocate colormap.
1366 */
1367 packet_size=(size_t) (3UL*depth/8UL);
1368 colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
1369 packet_size*sizeof(*colormap));
1370 if (colormap == (unsigned char *) NULL)
1371 return(MagickFalse);
1372 /*
1373 Write colormap to file.
1374 */
1375 q=colormap;
cristybb503372010-05-27 20:51:26 +00001376 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00001377 {
1378 switch (depth)
1379 {
1380 default:
1381 ThrowWriterException(CorruptImageError,"ImageDepthNotSupported");
1382 case 32:
1383 {
cristy4cb162a2010-05-30 03:04:47 +00001384 unsigned int
cristy3ed852e2009-09-05 21:47:34 +00001385 pixel;
1386
1387 pixel=ScaleQuantumToLong(image->colormap[i].red);
1388 q=PopLongPixel(MSBEndian,pixel,q);
1389 pixel=ScaleQuantumToLong(image->colormap[i].green);
1390 q=PopLongPixel(MSBEndian,pixel,q);
1391 pixel=ScaleQuantumToLong(image->colormap[i].blue);
1392 q=PopLongPixel(MSBEndian,pixel,q);
1393 }
1394 case 16:
1395 {
1396 unsigned short
1397 pixel;
1398
1399 pixel=ScaleQuantumToShort(image->colormap[i].red);
1400 q=PopShortPixel(MSBEndian,pixel,q);
1401 pixel=ScaleQuantumToShort(image->colormap[i].green);
1402 q=PopShortPixel(MSBEndian,pixel,q);
1403 pixel=ScaleQuantumToShort(image->colormap[i].blue);
1404 q=PopShortPixel(MSBEndian,pixel,q);
1405 break;
1406 }
1407 case 8:
1408 {
1409 unsigned char
1410 pixel;
1411
1412 pixel=(unsigned char) ScaleQuantumToChar(image->colormap[i].red);
1413 q=PopCharPixel(pixel,q);
1414 pixel=(unsigned char) ScaleQuantumToChar(
1415 image->colormap[i].green);
1416 q=PopCharPixel(pixel,q);
1417 pixel=(unsigned char) ScaleQuantumToChar(image->colormap[i].blue);
1418 q=PopCharPixel(pixel,q);
1419 break;
1420 }
1421 }
1422 }
1423 (void) WriteBlob(image,packet_size*image->colors,colormap);
1424 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1425 }
1426 /*
1427 Initialize persistent pixel cache.
1428 */
1429 status=PersistPixelCache(image,cache_filename,MagickFalse,&offset,
cristy1e178e72011-08-28 19:44:34 +00001430 exception);
cristy3ed852e2009-09-05 21:47:34 +00001431 if (status == MagickFalse)
1432 ThrowWriterException(CacheError,"UnableToPersistPixelCache");
1433 if (GetNextImageInList(image) == (Image *) NULL)
1434 break;
1435 image=SyncNextImageInList(image);
1436 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1437 {
1438 status=image->progress_monitor(SaveImagesTag,scene,
1439 GetImageListLength(image),image->client_data);
1440 if (status == MagickFalse)
1441 break;
1442 }
1443 scene++;
1444 } while (image_info->adjoin != MagickFalse);
1445 (void) CloseBlob(image);
1446 return(status);
1447}