blob: 7e99669cc0098ebf369c4a3a0b9e0ac6edd2a5d2 [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 %
cristyde984cd2013-12-01 14:49:27 +000016% Cristy %
cristy3ed852e2009-09-05 21:47:34 +000017% March 2000 %
18% %
19% %
cristyb56bb242014-11-25 17:12:48 +000020% Copyright 1999-2015 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"
cristya371edf2013-02-06 13:42:17 +000074#include "MagickCore/version-private.h"
cristy3ed852e2009-09-05 21:47:34 +000075
76/*
77 Forward declarations.
78*/
79static MagickBooleanType
cristy1e178e72011-08-28 19:44:34 +000080 WriteMPCImage(const ImageInfo *,Image *,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +000081
82/*
83%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
84% %
85% %
86% %
87% I s M P C %
88% %
89% %
90% %
91%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
92%
93% IsMPC() returns MagickTrue if the image format type, identified by the
94% magick string, is an Magick Persistent Cache image.
95%
96% The format of the IsMPC method is:
97%
98% MagickBooleanType IsMPC(const unsigned char *magick,const size_t length)
99%
100% A description of each parameter follows:
101%
102% o magick: compare image format pattern against these bytes.
103%
104% o length: Specifies the length of the magick string.
105%
106*/
107static MagickBooleanType IsMPC(const unsigned char *magick,const size_t length)
108{
109 if (length < 14)
110 return(MagickFalse);
111 if (LocaleNCompare((const char *) magick,"id=MagickCache",14) == 0)
112 return(MagickTrue);
113 return(MagickFalse);
114}
115
116/*
117%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
118% %
119% %
120% %
121% R e a d C A C H E I m a g e %
122% %
123% %
124% %
125%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
126%
127% ReadMPCImage() reads an Magick Persistent Cache image file and returns
128% it. It allocates the memory necessary for the new Image structure and
129% returns a pointer to the new image.
130%
131% The format of the ReadMPCImage method is:
132%
133% Image *ReadMPCImage(const ImageInfo *image_info,ExceptionInfo *exception)
134%
135% Decompression code contributed by Kyle Shorter.
136%
137% A description of each parameter follows:
138%
139% o image_info: the image info.
140%
141% o exception: return any errors or warnings in this structure.
142%
143*/
144static Image *ReadMPCImage(const ImageInfo *image_info,ExceptionInfo *exception)
145{
146 char
cristy151b66d2015-04-15 10:50:31 +0000147 cache_filename[MagickPathExtent],
148 id[MagickPathExtent],
149 keyword[MagickPathExtent],
cristy3ed852e2009-09-05 21:47:34 +0000150 *options;
151
152 const unsigned char
153 *p;
154
155 GeometryInfo
156 geometry_info;
157
158 Image
159 *image;
160
161 int
162 c;
163
164 LinkedListInfo
165 *profiles;
166
167 MagickBooleanType
168 status;
169
170 MagickOffsetType
171 offset;
172
173 MagickStatusType
174 flags;
175
cristybb503372010-05-27 20:51:26 +0000176 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000177 i;
178
179 size_t
cristyaff6d802011-04-26 01:46:31 +0000180 depth,
cristy6e323672013-02-05 18:44:04 +0000181 length;
cristy3ed852e2009-09-05 21:47:34 +0000182
183 ssize_t
184 count;
185
186 StringInfo
187 *profile;
188
cristy6e323672013-02-05 18:44:04 +0000189 unsigned int
190 signature;
191
cristy3ed852e2009-09-05 21:47:34 +0000192 /*
193 Open image file.
194 */
195 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000196 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000197 if (image_info->debug != MagickFalse)
198 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
199 image_info->filename);
200 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000201 assert(exception->signature == MagickCoreSignature);
cristy9950d572011-10-01 18:22:35 +0000202 image=AcquireImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +0000203 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
204 if (status == MagickFalse)
205 {
206 image=DestroyImageList(image);
207 return((Image *) NULL);
208 }
cristy151b66d2015-04-15 10:50:31 +0000209 (void) CopyMagickString(cache_filename,image->filename,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000210 AppendImageFormat("cache",cache_filename);
211 c=ReadBlobByte(image);
212 if (c == EOF)
213 {
214 image=DestroyImage(image);
215 return((Image *) NULL);
216 }
217 *id='\0';
218 (void) ResetMagickMemory(keyword,0,sizeof(keyword));
219 offset=0;
220 do
221 {
222 /*
223 Decode image header; header terminates one character beyond a ':'.
224 */
225 profiles=(LinkedListInfo *) NULL;
cristy151b66d2015-04-15 10:50:31 +0000226 length=MagickPathExtent;
cristy3ed852e2009-09-05 21:47:34 +0000227 options=AcquireString((char *) NULL);
cristy6e323672013-02-05 18:44:04 +0000228 signature=GetMagickSignature((const StringInfo *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000229 image->depth=8;
230 image->compression=NoCompression;
231 while ((isgraph(c) != MagickFalse) && (c != (int) ':'))
232 {
233 register char
234 *p;
235
236 if (c == (int) '{')
237 {
238 char
239 *comment;
240
241 /*
242 Read comment-- any text between { }.
243 */
cristy151b66d2015-04-15 10:50:31 +0000244 length=MagickPathExtent;
cristy3ed852e2009-09-05 21:47:34 +0000245 comment=AcquireString((char *) NULL);
246 for (p=comment; comment != (char *) NULL; p++)
247 {
248 c=ReadBlobByte(image);
cristyb880ee82012-04-07 15:08:14 +0000249 if (c == (int) '\\')
250 c=ReadBlobByte(image);
251 else
252 if ((c == EOF) || (c == (int) '}'))
253 break;
cristy3ed852e2009-09-05 21:47:34 +0000254 if ((size_t) (p-comment+1) >= length)
255 {
256 *p='\0';
257 length<<=1;
258 comment=(char *) ResizeQuantumMemory(comment,length+
cristy151b66d2015-04-15 10:50:31 +0000259 MagickPathExtent,sizeof(*comment));
cristy3ed852e2009-09-05 21:47:34 +0000260 if (comment == (char *) NULL)
261 break;
262 p=comment+strlen(comment);
263 }
264 *p=(char) c;
265 }
266 if (comment == (char *) NULL)
267 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
268 *p='\0';
cristyd15e6592011-10-15 00:13:06 +0000269 (void) SetImageProperty(image,"comment",comment,exception);
cristy3ed852e2009-09-05 21:47:34 +0000270 comment=DestroyString(comment);
271 c=ReadBlobByte(image);
272 }
273 else
274 if (isalnum(c) != MagickFalse)
275 {
276 /*
277 Get the keyword.
278 */
cristy151b66d2015-04-15 10:50:31 +0000279 length=MagickPathExtent;
cristy3ed852e2009-09-05 21:47:34 +0000280 p=keyword;
281 do
282 {
cristy3ed852e2009-09-05 21:47:34 +0000283 if (c == (int) '=')
284 break;
cristy151b66d2015-04-15 10:50:31 +0000285 if ((size_t) (p-keyword) < (MagickPathExtent-1))
cristy3ed852e2009-09-05 21:47:34 +0000286 *p++=(char) c;
287 c=ReadBlobByte(image);
288 } while (c != EOF);
289 *p='\0';
290 p=options;
291 while (isspace((int) ((unsigned char) c)) != 0)
292 c=ReadBlobByte(image);
293 if (c == (int) '=')
294 {
295 /*
296 Get the keyword value.
297 */
298 c=ReadBlobByte(image);
299 while ((c != (int) '}') && (c != EOF))
300 {
301 if ((size_t) (p-options+1) >= length)
302 {
303 *p='\0';
304 length<<=1;
305 options=(char *) ResizeQuantumMemory(options,length+
cristy151b66d2015-04-15 10:50:31 +0000306 MagickPathExtent,sizeof(*options));
cristy3ed852e2009-09-05 21:47:34 +0000307 if (options == (char *) NULL)
308 break;
309 p=options+strlen(options);
310 }
cristy3ed852e2009-09-05 21:47:34 +0000311 *p++=(char) c;
312 c=ReadBlobByte(image);
cristyb880ee82012-04-07 15:08:14 +0000313 if (c == '\\')
314 {
315 c=ReadBlobByte(image);
316 if (c == (int) '}')
317 {
318 *p++=(char) c;
319 c=ReadBlobByte(image);
320 }
321 }
cristy3ed852e2009-09-05 21:47:34 +0000322 if (*options != '{')
323 if (isspace((int) ((unsigned char) c)) != 0)
324 break;
325 }
cristy37889762015-01-07 12:20:18 +0000326 if (options == (char *) NULL)
327 ThrowReaderException(ResourceLimitError,
328 "MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000329 }
330 *p='\0';
331 if (*options == '{')
cristy01cd7302012-10-05 16:02:03 +0000332 (void) CopyMagickString(options,options+1,strlen(options));
cristy3ed852e2009-09-05 21:47:34 +0000333 /*
334 Assign a value to the specified keyword.
335 */
336 switch (*keyword)
337 {
cristy8a46d822012-08-28 23:32:39 +0000338 case 'a':
339 case 'A':
340 {
341 if (LocaleCompare(keyword,"alpha-trait") == 0)
342 {
343 ssize_t
344 alpha_trait;
345
346 alpha_trait=ParseCommandOption(MagickPixelTraitOptions,
347 MagickFalse,options);
348 if (alpha_trait < 0)
349 break;
350 image->alpha_trait=(PixelTrait) alpha_trait;
351 break;
352 }
353 (void) SetImageProperty(image,keyword,options,exception);
354 break;
355 }
cristy3ed852e2009-09-05 21:47:34 +0000356 case 'b':
357 case 'B':
358 {
359 if (LocaleCompare(keyword,"background-color") == 0)
360 {
cristy9950d572011-10-01 18:22:35 +0000361 (void) QueryColorCompliance(options,AllCompliance,
362 &image->background_color,exception);
cristy3ed852e2009-09-05 21:47:34 +0000363 break;
364 }
365 if (LocaleCompare(keyword,"blue-primary") == 0)
366 {
367 flags=ParseGeometry(options,&geometry_info);
368 image->chromaticity.blue_primary.x=geometry_info.rho;
369 image->chromaticity.blue_primary.y=geometry_info.sigma;
370 if ((flags & SigmaValue) == 0)
371 image->chromaticity.blue_primary.y=
372 image->chromaticity.blue_primary.x;
373 break;
374 }
375 if (LocaleCompare(keyword,"border-color") == 0)
376 {
cristy9950d572011-10-01 18:22:35 +0000377 (void) QueryColorCompliance(options,AllCompliance,
378 &image->border_color,exception);
cristy3ed852e2009-09-05 21:47:34 +0000379 break;
380 }
cristyd15e6592011-10-15 00:13:06 +0000381 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000382 break;
383 }
384 case 'c':
385 case 'C':
386 {
387 if (LocaleCompare(keyword,"class") == 0)
388 {
cristybb503372010-05-27 20:51:26 +0000389 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000390 storage_class;
391
cristy042ee782011-04-22 18:48:30 +0000392 storage_class=ParseCommandOption(MagickClassOptions,
cristy3ed852e2009-09-05 21:47:34 +0000393 MagickFalse,options);
394 if (storage_class < 0)
395 break;
396 image->storage_class=(ClassType) storage_class;
397 break;
398 }
399 if (LocaleCompare(keyword,"colors") == 0)
400 {
cristye27293e2009-12-18 02:53:20 +0000401 image->colors=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000402 break;
403 }
404 if (LocaleCompare(keyword,"colorspace") == 0)
405 {
cristybb503372010-05-27 20:51:26 +0000406 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000407 colorspace;
408
cristy042ee782011-04-22 18:48:30 +0000409 colorspace=ParseCommandOption(MagickColorspaceOptions,
cristy3ed852e2009-09-05 21:47:34 +0000410 MagickFalse,options);
411 if (colorspace < 0)
412 break;
cristy02a27d52013-03-05 01:06:21 +0000413 image->colorspace=(ColorspaceType) colorspace;
cristy3ed852e2009-09-05 21:47:34 +0000414 break;
415 }
416 if (LocaleCompare(keyword,"compression") == 0)
417 {
cristybb503372010-05-27 20:51:26 +0000418 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000419 compression;
420
cristy042ee782011-04-22 18:48:30 +0000421 compression=ParseCommandOption(MagickCompressOptions,
cristy3ed852e2009-09-05 21:47:34 +0000422 MagickFalse,options);
423 if (compression < 0)
424 break;
425 image->compression=(CompressionType) compression;
426 break;
427 }
428 if (LocaleCompare(keyword,"columns") == 0)
429 {
cristye27293e2009-12-18 02:53:20 +0000430 image->columns=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000431 break;
432 }
cristyd15e6592011-10-15 00:13:06 +0000433 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000434 break;
435 }
436 case 'd':
437 case 'D':
438 {
439 if (LocaleCompare(keyword,"delay") == 0)
440 {
cristye27293e2009-12-18 02:53:20 +0000441 image->delay=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000442 break;
443 }
444 if (LocaleCompare(keyword,"depth") == 0)
445 {
cristye27293e2009-12-18 02:53:20 +0000446 image->depth=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000447 break;
448 }
449 if (LocaleCompare(keyword,"dispose") == 0)
450 {
cristybb503372010-05-27 20:51:26 +0000451 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000452 dispose;
453
cristy042ee782011-04-22 18:48:30 +0000454 dispose=ParseCommandOption(MagickDisposeOptions,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000455 options);
456 if (dispose < 0)
457 break;
458 image->dispose=(DisposeType) dispose;
459 break;
460 }
cristyd15e6592011-10-15 00:13:06 +0000461 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000462 break;
463 }
464 case 'e':
465 case 'E':
466 {
467 if (LocaleCompare(keyword,"endian") == 0)
468 {
cristybb503372010-05-27 20:51:26 +0000469 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000470 endian;
471
cristy042ee782011-04-22 18:48:30 +0000472 endian=ParseCommandOption(MagickEndianOptions,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000473 options);
474 if (endian < 0)
475 break;
476 image->endian=(EndianType) endian;
477 break;
478 }
479 if (LocaleCompare(keyword,"error") == 0)
480 {
cristy9b34e302011-11-05 02:15:45 +0000481 image->error.mean_error_per_pixel=StringToDouble(options,
482 (char **) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000483 break;
484 }
cristyd15e6592011-10-15 00:13:06 +0000485 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000486 break;
487 }
488 case 'g':
489 case 'G':
490 {
491 if (LocaleCompare(keyword,"gamma") == 0)
492 {
cristydbdd0e32011-11-04 23:29:40 +0000493 image->gamma=StringToDouble(options,(char **) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000494 break;
495 }
496 if (LocaleCompare(keyword,"green-primary") == 0)
497 {
498 flags=ParseGeometry(options,&geometry_info);
499 image->chromaticity.green_primary.x=geometry_info.rho;
500 image->chromaticity.green_primary.y=geometry_info.sigma;
501 if ((flags & SigmaValue) == 0)
502 image->chromaticity.green_primary.y=
503 image->chromaticity.green_primary.x;
504 break;
505 }
cristyd15e6592011-10-15 00:13:06 +0000506 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000507 break;
508 }
509 case 'i':
510 case 'I':
511 {
512 if (LocaleCompare(keyword,"id") == 0)
513 {
cristy151b66d2015-04-15 10:50:31 +0000514 (void) CopyMagickString(id,options,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000515 break;
516 }
517 if (LocaleCompare(keyword,"iterations") == 0)
518 {
cristye27293e2009-12-18 02:53:20 +0000519 image->iterations=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000520 break;
521 }
cristyd15e6592011-10-15 00:13:06 +0000522 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000523 break;
524 }
525 case 'm':
526 case 'M':
527 {
cristy240e8252013-02-06 15:00:04 +0000528 if (LocaleCompare(keyword,"magick-signature") == 0)
529 {
530 signature=(unsigned int) StringToUnsignedLong(options);
531 break;
532 }
cristy3ed852e2009-09-05 21:47:34 +0000533 if (LocaleCompare(keyword,"matte-color") == 0)
534 {
cristy9950d572011-10-01 18:22:35 +0000535 (void) QueryColorCompliance(options,AllCompliance,
536 &image->matte_color,exception);
cristy3ed852e2009-09-05 21:47:34 +0000537 break;
538 }
539 if (LocaleCompare(keyword,"maximum-error") == 0)
540 {
cristy9b34e302011-11-05 02:15:45 +0000541 image->error.normalized_maximum_error=StringToDouble(
542 options,(char **) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000543 break;
544 }
545 if (LocaleCompare(keyword,"mean-error") == 0)
546 {
cristy9b34e302011-11-05 02:15:45 +0000547 image->error.normalized_mean_error=StringToDouble(options,
548 (char **) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000549 break;
550 }
551 if (LocaleCompare(keyword,"montage") == 0)
552 {
553 (void) CloneString(&image->montage,options);
554 break;
555 }
cristyd15e6592011-10-15 00:13:06 +0000556 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000557 break;
558 }
559 case 'o':
560 case 'O':
561 {
cristy3ed852e2009-09-05 21:47:34 +0000562 if (LocaleCompare(keyword,"orientation") == 0)
563 {
cristybb503372010-05-27 20:51:26 +0000564 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000565 orientation;
566
cristy042ee782011-04-22 18:48:30 +0000567 orientation=ParseCommandOption(MagickOrientationOptions,
cristy3ed852e2009-09-05 21:47:34 +0000568 MagickFalse,options);
569 if (orientation < 0)
570 break;
571 image->orientation=(OrientationType) orientation;
572 break;
573 }
cristyd15e6592011-10-15 00:13:06 +0000574 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000575 break;
576 }
577 case 'p':
578 case 'P':
579 {
580 if (LocaleCompare(keyword,"page") == 0)
581 {
582 char
583 *geometry;
584
585 geometry=GetPageGeometry(options);
586 (void) ParseAbsoluteGeometry(geometry,&image->page);
587 geometry=DestroyString(geometry);
588 break;
589 }
cristy3e4e9f42013-04-06 22:29:40 +0000590 if (LocaleCompare(keyword,"pixel-intensity") == 0)
591 {
592 ssize_t
593 intensity;
594
595 intensity=ParseCommandOption(MagickPixelIntensityOptions,
596 MagickFalse,options);
597 if (intensity < 0)
598 break;
599 image->intensity=(PixelIntensityMethod) intensity;
600 break;
601 }
cristy3ed852e2009-09-05 21:47:34 +0000602 if ((LocaleNCompare(keyword,"profile:",8) == 0) ||
603 (LocaleNCompare(keyword,"profile-",8) == 0))
604 {
605 if (profiles == (LinkedListInfo *) NULL)
606 profiles=NewLinkedList(0);
607 (void) AppendValueToLinkedList(profiles,
608 AcquireString(keyword+8));
cristy07c9bd62011-09-01 13:41:23 +0000609 profile=BlobToStringInfo((const void *) NULL,(size_t)
610 StringToLong(options));
cristy0381c632011-09-01 18:02:13 +0000611 if (profile == (StringInfo *) NULL)
cristy07c9bd62011-09-01 13:41:23 +0000612 ThrowReaderException(ResourceLimitError,
613 "MemoryAllocationFailed");
cristyd15e6592011-10-15 00:13:06 +0000614 (void) SetImageProfile(image,keyword+8,profile,exception);
cristy3ed852e2009-09-05 21:47:34 +0000615 profile=DestroyStringInfo(profile);
616 break;
617 }
cristyd15e6592011-10-15 00:13:06 +0000618 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000619 break;
620 }
621 case 'q':
622 case 'Q':
623 {
624 if (LocaleCompare(keyword,"quality") == 0)
625 {
cristye27293e2009-12-18 02:53:20 +0000626 image->quality=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000627 break;
628 }
cristyd15e6592011-10-15 00:13:06 +0000629 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000630 break;
631 }
632 case 'r':
633 case 'R':
634 {
635 if (LocaleCompare(keyword,"red-primary") == 0)
636 {
637 flags=ParseGeometry(options,&geometry_info);
638 image->chromaticity.red_primary.x=geometry_info.rho;
639 if ((flags & SigmaValue) != 0)
640 image->chromaticity.red_primary.y=geometry_info.sigma;
641 break;
642 }
643 if (LocaleCompare(keyword,"rendering-intent") == 0)
644 {
cristybb503372010-05-27 20:51:26 +0000645 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000646 rendering_intent;
647
cristy042ee782011-04-22 18:48:30 +0000648 rendering_intent=ParseCommandOption(MagickIntentOptions,
cristy3ed852e2009-09-05 21:47:34 +0000649 MagickFalse,options);
650 if (rendering_intent < 0)
651 break;
652 image->rendering_intent=(RenderingIntent) rendering_intent;
653 break;
654 }
655 if (LocaleCompare(keyword,"resolution") == 0)
656 {
657 flags=ParseGeometry(options,&geometry_info);
cristy2a11bef2011-10-28 18:33:11 +0000658 image->resolution.x=geometry_info.rho;
659 image->resolution.y=geometry_info.sigma;
cristy3ed852e2009-09-05 21:47:34 +0000660 if ((flags & SigmaValue) == 0)
cristy2a11bef2011-10-28 18:33:11 +0000661 image->resolution.y=image->resolution.x;
cristy3ed852e2009-09-05 21:47:34 +0000662 break;
663 }
664 if (LocaleCompare(keyword,"rows") == 0)
665 {
cristye27293e2009-12-18 02:53:20 +0000666 image->rows=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000667 break;
668 }
cristyd15e6592011-10-15 00:13:06 +0000669 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000670 break;
671 }
672 case 's':
673 case 'S':
674 {
675 if (LocaleCompare(keyword,"scene") == 0)
676 {
cristye27293e2009-12-18 02:53:20 +0000677 image->scene=StringToUnsignedLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000678 break;
679 }
cristyd15e6592011-10-15 00:13:06 +0000680 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000681 break;
682 }
683 case 't':
684 case 'T':
685 {
686 if (LocaleCompare(keyword,"ticks-per-second") == 0)
687 {
cristybb503372010-05-27 20:51:26 +0000688 image->ticks_per_second=(ssize_t) StringToLong(options);
cristy3ed852e2009-09-05 21:47:34 +0000689 break;
690 }
691 if (LocaleCompare(keyword,"tile-offset") == 0)
692 {
693 char
694 *geometry;
695
696 geometry=GetPageGeometry(options);
697 (void) ParseAbsoluteGeometry(geometry,&image->tile_offset);
698 geometry=DestroyString(geometry);
699 }
700 if (LocaleCompare(keyword,"type") == 0)
701 {
cristybb503372010-05-27 20:51:26 +0000702 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000703 type;
704
cristy042ee782011-04-22 18:48:30 +0000705 type=ParseCommandOption(MagickTypeOptions,MagickFalse,
cristy3ed852e2009-09-05 21:47:34 +0000706 options);
707 if (type < 0)
708 break;
709 image->type=(ImageType) type;
710 break;
711 }
cristyd15e6592011-10-15 00:13:06 +0000712 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000713 break;
714 }
715 case 'u':
716 case 'U':
717 {
718 if (LocaleCompare(keyword,"units") == 0)
719 {
cristybb503372010-05-27 20:51:26 +0000720 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000721 units;
722
cristyd15e6592011-10-15 00:13:06 +0000723 units=ParseCommandOption(MagickResolutionOptions,
724 MagickFalse,options);
cristy3ed852e2009-09-05 21:47:34 +0000725 if (units < 0)
726 break;
727 image->units=(ResolutionType) units;
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 case 'w':
734 case 'W':
735 {
736 if (LocaleCompare(keyword,"white-point") == 0)
737 {
738 flags=ParseGeometry(options,&geometry_info);
739 image->chromaticity.white_point.x=geometry_info.rho;
740 image->chromaticity.white_point.y=geometry_info.sigma;
741 if ((flags & SigmaValue) == 0)
742 image->chromaticity.white_point.y=
743 image->chromaticity.white_point.x;
744 break;
745 }
cristyd15e6592011-10-15 00:13:06 +0000746 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000747 break;
748 }
749 default:
750 {
cristyd15e6592011-10-15 00:13:06 +0000751 (void) SetImageProperty(image,keyword,options,exception);
cristy3ed852e2009-09-05 21:47:34 +0000752 break;
753 }
754 }
755 }
756 else
757 c=ReadBlobByte(image);
758 while (isspace((int) ((unsigned char) c)) != 0)
759 c=ReadBlobByte(image);
760 }
761 options=DestroyString(options);
762 (void) ReadBlobByte(image);
763 /*
764 Verify that required image information is defined.
765 */
766 if ((LocaleCompare(id,"MagickCache") != 0) ||
767 (image->storage_class == UndefinedClass) ||
768 (image->compression == UndefinedCompression) || (image->columns == 0) ||
769 (image->rows == 0))
770 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
cristy6e323672013-02-05 18:44:04 +0000771 if (signature != GetMagickSignature((const StringInfo *) NULL))
772 ThrowReaderException(CacheError,"IncompatibleAPI");
cristy3ed852e2009-09-05 21:47:34 +0000773 if (image->montage != (char *) NULL)
774 {
775 register char
776 *p;
777
778 /*
779 Image directory.
780 */
cristy151b66d2015-04-15 10:50:31 +0000781 length=MagickPathExtent;
cristy3ed852e2009-09-05 21:47:34 +0000782 image->directory=AcquireString((char *) NULL);
783 p=image->directory;
784 do
785 {
786 *p='\0';
cristy151b66d2015-04-15 10:50:31 +0000787 if ((strlen(image->directory)+MagickPathExtent) >= length)
cristy3ed852e2009-09-05 21:47:34 +0000788 {
789 /*
790 Allocate more memory for the image directory.
791 */
792 length<<=1;
793 image->directory=(char *) ResizeQuantumMemory(image->directory,
cristy151b66d2015-04-15 10:50:31 +0000794 length+MagickPathExtent,sizeof(*image->directory));
cristy3ed852e2009-09-05 21:47:34 +0000795 if (image->directory == (char *) NULL)
796 ThrowReaderException(CorruptImageError,"UnableToReadImageData");
797 p=image->directory+strlen(image->directory);
798 }
799 c=ReadBlobByte(image);
800 *p++=(char) c;
801 } while (c != (int) '\0');
802 }
803 if (profiles != (LinkedListInfo *) NULL)
804 {
805 const char
806 *name;
807
808 const StringInfo
809 *profile;
810
811 register unsigned char
812 *p;
813
814 /*
815 Read image profiles.
816 */
817 ResetLinkedListIterator(profiles);
818 name=(const char *) GetNextValueInLinkedList(profiles);
819 while (name != (const char *) NULL)
820 {
821 profile=GetImageProfile(image,name);
822 if (profile != (StringInfo *) NULL)
823 {
824 p=GetStringInfoDatum(profile);
825 count=ReadBlob(image,GetStringInfoLength(profile),p);
826 }
827 name=(const char *) GetNextValueInLinkedList(profiles);
828 }
829 profiles=DestroyLinkedList(profiles,RelinquishMagickMemory);
830 }
831 depth=GetImageQuantumDepth(image,MagickFalse);
832 if (image->storage_class == PseudoClass)
833 {
834 /*
835 Create image colormap.
836 */
cristy018f07f2011-09-04 21:15:19 +0000837 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000838 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
839 if (image->colors != 0)
840 {
841 size_t
842 packet_size;
843
844 unsigned char
845 *colormap;
846
847 /*
848 Read image colormap from file.
849 */
850 packet_size=(size_t) (3UL*depth/8UL);
851 colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
852 packet_size*sizeof(*colormap));
853 if (colormap == (unsigned char *) NULL)
854 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
855 count=ReadBlob(image,packet_size*image->colors,colormap);
856 if (count != (ssize_t) (packet_size*image->colors))
857 ThrowReaderException(CorruptImageError,
858 "InsufficientImageDataInFile");
859 p=colormap;
860 switch (depth)
861 {
862 default:
863 ThrowReaderException(CorruptImageError,
864 "ImageDepthNotSupported");
865 case 8:
866 {
867 unsigned char
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=PushCharPixel(p,&pixel);
873 image->colormap[i].red=ScaleCharToQuantum(pixel);
874 p=PushCharPixel(p,&pixel);
875 image->colormap[i].green=ScaleCharToQuantum(pixel);
876 p=PushCharPixel(p,&pixel);
877 image->colormap[i].blue=ScaleCharToQuantum(pixel);
878 }
879 break;
880 }
881 case 16:
882 {
883 unsigned short
884 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=PushShortPixel(MSBEndian,p,&pixel);
889 image->colormap[i].red=ScaleShortToQuantum(pixel);
890 p=PushShortPixel(MSBEndian,p,&pixel);
891 image->colormap[i].green=ScaleShortToQuantum(pixel);
892 p=PushShortPixel(MSBEndian,p,&pixel);
893 image->colormap[i].blue=ScaleShortToQuantum(pixel);
894 }
895 break;
896 }
897 case 32:
898 {
cristy4cb162a2010-05-30 03:04:47 +0000899 unsigned int
cristy3ed852e2009-09-05 21:47:34 +0000900 pixel;
901
cristybb503372010-05-27 20:51:26 +0000902 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +0000903 {
904 p=PushLongPixel(MSBEndian,p,&pixel);
905 image->colormap[i].red=ScaleLongToQuantum(pixel);
906 p=PushLongPixel(MSBEndian,p,&pixel);
907 image->colormap[i].green=ScaleLongToQuantum(pixel);
908 p=PushLongPixel(MSBEndian,p,&pixel);
909 image->colormap[i].blue=ScaleLongToQuantum(pixel);
910 }
911 break;
912 }
913 }
914 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
915 }
916 }
917 if (EOFBlob(image) != MagickFalse)
918 {
919 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
920 image->filename);
921 break;
922 }
923 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
924 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
925 break;
cristyacabb842014-12-14 23:36:33 +0000926 status=SetImageExtent(image,image->columns,image->rows,exception);
927 if (status == MagickFalse)
928 return(DestroyImageList(image));
cristy3ed852e2009-09-05 21:47:34 +0000929 /*
930 Attach persistent pixel cache.
931 */
932 status=PersistPixelCache(image,cache_filename,MagickTrue,&offset,exception);
933 if (status == MagickFalse)
934 ThrowReaderException(CacheError,"UnableToPersistPixelCache");
935 /*
936 Proceed to next image.
937 */
938 do
939 {
940 c=ReadBlobByte(image);
941 } while ((isgraph(c) == MagickFalse) && (c != EOF));
942 if (c != EOF)
943 {
944 /*
945 Allocate next image structure.
946 */
cristy9950d572011-10-01 18:22:35 +0000947 AcquireNextImage(image_info,image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000948 if (GetNextImageInList(image) == (Image *) NULL)
949 {
950 image=DestroyImageList(image);
951 return((Image *) NULL);
952 }
953 image=SyncNextImageInList(image);
954 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
955 GetBlobSize(image));
956 if (status == MagickFalse)
957 break;
958 }
959 } while (c != EOF);
960 (void) CloseBlob(image);
961 return(GetFirstImageInList(image));
962}
963
964/*
965%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
966% %
967% %
968% %
969% R e g i s t e r M P C I m a g e %
970% %
971% %
972% %
973%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
974%
975% RegisterMPCImage() adds properties for the Cache image format to
976% the list of supported formats. The properties include the image format
977% tag, a method to read and/or write the format, whether the format
978% supports the saving of more than one frame to the same file or blob,
979% whether the format supports native in-memory I/O, and a brief
980% description of the format.
981%
982% The format of the RegisterMPCImage method is:
983%
cristybb503372010-05-27 20:51:26 +0000984% size_t RegisterMPCImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000985%
986*/
cristybb503372010-05-27 20:51:26 +0000987ModuleExport size_t RegisterMPCImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000988{
989 MagickInfo
990 *entry;
991
dirk06b627a2015-04-06 18:59:17 +0000992 entry=AcquireMagickInfo("MPC","CACHE",
993 "Magick Persistent Cache image format");
cristy3ed852e2009-09-05 21:47:34 +0000994 entry->module=ConstantString("CACHE");
dirk08e9a112015-02-22 01:51:41 +0000995 entry->flags|=CoderStealthFlag;
cristy3ed852e2009-09-05 21:47:34 +0000996 (void) RegisterMagickInfo(entry);
dirk06b627a2015-04-06 18:59:17 +0000997 entry=AcquireMagickInfo("MPC","MPC","Magick Persistent Cache image format");
cristy3ed852e2009-09-05 21:47:34 +0000998 entry->decoder=(DecodeImageHandler *) ReadMPCImage;
999 entry->encoder=(EncodeImageHandler *) WriteMPCImage;
1000 entry->magick=(IsImageFormatHandler *) IsMPC;
cristy3ed852e2009-09-05 21:47:34 +00001001 (void) RegisterMagickInfo(entry);
1002 return(MagickImageCoderSignature);
1003}
1004
1005/*
1006%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1007% %
1008% %
1009% %
1010% U n r e g i s t e r M P C I m a g e %
1011% %
1012% %
1013% %
1014%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1015%
1016% UnregisterMPCImage() removes format registrations made by the
1017% MPC module from the list of supported formats.
1018%
1019% The format of the UnregisterMPCImage method is:
1020%
1021% UnregisterMPCImage(void)
1022%
1023*/
1024ModuleExport void UnregisterMPCImage(void)
1025{
1026 (void) UnregisterMagickInfo("CACHE");
1027 (void) UnregisterMagickInfo("MPC");
1028}
1029
1030/*
1031%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1032% %
1033% %
1034% %
1035% W r i t e M P C I m a g e %
1036% %
1037% %
1038% %
1039%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1040%
1041% WriteMPCImage() writes an Magick Persistent Cache image to a file.
1042%
1043% The format of the WriteMPCImage method is:
1044%
cristy1e178e72011-08-28 19:44:34 +00001045% MagickBooleanType WriteMPCImage(const ImageInfo *image_info,
1046% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001047%
1048% A description of each parameter follows:
1049%
1050% o image_info: the image info.
1051%
1052% o image: the image.
1053%
cristy1e178e72011-08-28 19:44:34 +00001054% o exception: return any errors or warnings in this structure.
1055%
cristy3ed852e2009-09-05 21:47:34 +00001056*/
cristy1e178e72011-08-28 19:44:34 +00001057static MagickBooleanType WriteMPCImage(const ImageInfo *image_info,Image *image,
1058 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001059{
1060 char
cristy151b66d2015-04-15 10:50:31 +00001061 buffer[MagickPathExtent],
1062 cache_filename[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00001063
1064 const char
1065 *property,
1066 *value;
1067
1068 MagickBooleanType
1069 status;
1070
1071 MagickOffsetType
1072 offset,
1073 scene;
1074
cristybb503372010-05-27 20:51:26 +00001075 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001076 i;
1077
cristybb503372010-05-27 20:51:26 +00001078 size_t
cristy688dc7a2013-04-07 00:02:55 +00001079 depth;
cristy3ed852e2009-09-05 21:47:34 +00001080
1081 /*
1082 Open persistent cache.
1083 */
1084 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00001085 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00001086 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00001087 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00001088 if (image->debug != MagickFalse)
1089 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy3a37efd2011-08-28 20:31:03 +00001090 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00001091 assert(exception->signature == MagickCoreSignature);
cristy1e178e72011-08-28 19:44:34 +00001092 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00001093 if (status == MagickFalse)
1094 return(status);
cristy151b66d2015-04-15 10:50:31 +00001095 (void) CopyMagickString(cache_filename,image->filename,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +00001096 AppendImageFormat("cache",cache_filename);
1097 scene=0;
1098 offset=0;
1099 do
1100 {
1101 /*
1102 Write persistent cache meta-information.
1103 */
1104 depth=GetImageQuantumDepth(image,MagickTrue);
1105 if ((image->storage_class == PseudoClass) &&
cristy3e4e9f42013-04-06 22:29:40 +00001106 (image->colors > (size_t) (GetQuantumRange(image->depth)+1)))
cristy688dc7a2013-04-07 00:02:55 +00001107 (void) SetImageStorageClass(image,DirectClass,exception);
cristy3ed852e2009-09-05 21:47:34 +00001108 (void) WriteBlobString(image,"id=MagickCache\n");
cristy151b66d2015-04-15 10:50:31 +00001109 (void) FormatLocaleString(buffer,MagickPathExtent,"magick-signature=%u\n",
cristy6e323672013-02-05 18:44:04 +00001110 GetMagickSignature((const StringInfo *) NULL));
cristy3ed852e2009-09-05 21:47:34 +00001111 (void) WriteBlobString(image,buffer);
cristy151b66d2015-04-15 10:50:31 +00001112 (void) FormatLocaleString(buffer,MagickPathExtent,
cristy8a46d822012-08-28 23:32:39 +00001113 "class=%s colors=%.20g alpha-trait=%s\n",CommandOptionToMnemonic(
cristye8c25f92010-06-03 00:53:06 +00001114 MagickClassOptions,image->storage_class),(double) image->colors,
cristy8a46d822012-08-28 23:32:39 +00001115 CommandOptionToMnemonic(MagickPixelTraitOptions,(ssize_t)
1116 image->alpha_trait));
cristy3ed852e2009-09-05 21:47:34 +00001117 (void) WriteBlobString(image,buffer);
cristy151b66d2015-04-15 10:50:31 +00001118 (void) FormatLocaleString(buffer,MagickPathExtent,
cristye8c25f92010-06-03 00:53:06 +00001119 "columns=%.20g rows=%.20g depth=%.20g\n",(double) image->columns,
1120 (double) image->rows,(double) image->depth);
cristy3ed852e2009-09-05 21:47:34 +00001121 (void) WriteBlobString(image,buffer);
cristy5f1c1ff2010-12-23 21:38:06 +00001122 if (image->type != UndefinedType)
cristy3ed852e2009-09-05 21:47:34 +00001123 {
cristy151b66d2015-04-15 10:50:31 +00001124 (void) FormatLocaleString(buffer,MagickPathExtent,"type=%s\n",
cristy042ee782011-04-22 18:48:30 +00001125 CommandOptionToMnemonic(MagickTypeOptions,image->type));
cristy3ed852e2009-09-05 21:47:34 +00001126 (void) WriteBlobString(image,buffer);
1127 }
1128 if (image->colorspace != UndefinedColorspace)
1129 {
cristy151b66d2015-04-15 10:50:31 +00001130 (void) FormatLocaleString(buffer,MagickPathExtent,"colorspace=%s\n",
cristy042ee782011-04-22 18:48:30 +00001131 CommandOptionToMnemonic(MagickColorspaceOptions,image->colorspace));
cristy3ed852e2009-09-05 21:47:34 +00001132 (void) WriteBlobString(image,buffer);
1133 }
cristy3e4e9f42013-04-06 22:29:40 +00001134 if (image->intensity != UndefinedPixelIntensityMethod)
1135 {
cristy151b66d2015-04-15 10:50:31 +00001136 (void) FormatLocaleString(buffer,MagickPathExtent,"pixel-intensity=%s\n",
cristy3e4e9f42013-04-06 22:29:40 +00001137 CommandOptionToMnemonic(MagickPixelIntensityOptions,
1138 image->intensity));
1139 (void) WriteBlobString(image,buffer);
1140 }
cristy3ed852e2009-09-05 21:47:34 +00001141 if (image->endian != UndefinedEndian)
1142 {
cristy151b66d2015-04-15 10:50:31 +00001143 (void) FormatLocaleString(buffer,MagickPathExtent,"endian=%s\n",
cristy042ee782011-04-22 18:48:30 +00001144 CommandOptionToMnemonic(MagickEndianOptions,image->endian));
cristy3ed852e2009-09-05 21:47:34 +00001145 (void) WriteBlobString(image,buffer);
1146 }
1147 if (image->compression != UndefinedCompression)
1148 {
cristy151b66d2015-04-15 10:50:31 +00001149 (void) FormatLocaleString(buffer,MagickPathExtent,
cristy042ee782011-04-22 18:48:30 +00001150 "compression=%s quality=%.20g\n",CommandOptionToMnemonic(
cristye8c25f92010-06-03 00:53:06 +00001151 MagickCompressOptions,image->compression),(double) image->quality);
cristy3ed852e2009-09-05 21:47:34 +00001152 (void) WriteBlobString(image,buffer);
1153 }
1154 if (image->units != UndefinedResolution)
1155 {
cristy151b66d2015-04-15 10:50:31 +00001156 (void) FormatLocaleString(buffer,MagickPathExtent,"units=%s\n",
cristy042ee782011-04-22 18:48:30 +00001157 CommandOptionToMnemonic(MagickResolutionOptions,image->units));
cristy3ed852e2009-09-05 21:47:34 +00001158 (void) WriteBlobString(image,buffer);
1159 }
cristy2a11bef2011-10-28 18:33:11 +00001160 if ((image->resolution.x != 0) || (image->resolution.y != 0))
cristy3ed852e2009-09-05 21:47:34 +00001161 {
cristy151b66d2015-04-15 10:50:31 +00001162 (void) FormatLocaleString(buffer,MagickPathExtent,
cristy2a11bef2011-10-28 18:33:11 +00001163 "resolution=%gx%g\n",image->resolution.x,image->resolution.y);
cristy3ed852e2009-09-05 21:47:34 +00001164 (void) WriteBlobString(image,buffer);
1165 }
1166 if ((image->page.width != 0) || (image->page.height != 0))
1167 {
cristy151b66d2015-04-15 10:50:31 +00001168 (void) FormatLocaleString(buffer,MagickPathExtent,
cristye8c25f92010-06-03 00:53:06 +00001169 "page=%.20gx%.20g%+.20g%+.20g\n",(double) image->page.width,(double)
1170 image->page.height,(double) image->page.x,(double) image->page.y);
cristy3ed852e2009-09-05 21:47:34 +00001171 (void) WriteBlobString(image,buffer);
1172 }
1173 else
1174 if ((image->page.x != 0) || (image->page.y != 0))
1175 {
cristy151b66d2015-04-15 10:50:31 +00001176 (void) FormatLocaleString(buffer,MagickPathExtent,"page=%+ld%+ld\n",
cristyf2faecf2010-05-28 19:19:36 +00001177 (long) image->page.x,(long) image->page.y);
cristy3ed852e2009-09-05 21:47:34 +00001178 (void) WriteBlobString(image,buffer);
1179 }
cristyff1cf6f2015-05-03 19:56:44 +00001180 if ((image->tile_offset.x != 0) || (image->tile_offset.y != 0))
cristy3ed852e2009-09-05 21:47:34 +00001181 {
cristyff1cf6f2015-05-03 19:56:44 +00001182 (void) FormatLocaleString(buffer,MagickPathExtent,
1183 "tile-offset=%+ld%+ld\n",(long) image->tile_offset.x,(long)
1184 image->tile_offset.y);
cristy3ed852e2009-09-05 21:47:34 +00001185 (void) WriteBlobString(image,buffer);
1186 }
1187 if ((GetNextImageInList(image) != (Image *) NULL) ||
1188 (GetPreviousImageInList(image) != (Image *) NULL))
1189 {
1190 if (image->scene == 0)
cristy151b66d2015-04-15 10:50:31 +00001191 (void) FormatLocaleString(buffer,MagickPathExtent,
cristye8c25f92010-06-03 00:53:06 +00001192 "iterations=%.20g delay=%.20g ticks-per-second=%.20g\n",(double)
1193 image->iterations,(double) image->delay,(double)
cristyf2faecf2010-05-28 19:19:36 +00001194 image->ticks_per_second);
cristy3ed852e2009-09-05 21:47:34 +00001195 else
cristy151b66d2015-04-15 10:50:31 +00001196 (void) FormatLocaleString(buffer,MagickPathExtent,"scene=%.20g "
cristyaff6d802011-04-26 01:46:31 +00001197 "iterations=%.20g delay=%.20g ticks-per-second=%.20g\n",
cristye8c25f92010-06-03 00:53:06 +00001198 (double) image->scene,(double) image->iterations,(double)
1199 image->delay,(double) image->ticks_per_second);
cristy3ed852e2009-09-05 21:47:34 +00001200 (void) WriteBlobString(image,buffer);
1201 }
1202 else
1203 {
1204 if (image->scene != 0)
1205 {
cristy151b66d2015-04-15 10:50:31 +00001206 (void) FormatLocaleString(buffer,MagickPathExtent,"scene=%.20g\n",
cristye8c25f92010-06-03 00:53:06 +00001207 (double) image->scene);
cristy3ed852e2009-09-05 21:47:34 +00001208 (void) WriteBlobString(image,buffer);
1209 }
1210 if (image->iterations != 0)
1211 {
cristy151b66d2015-04-15 10:50:31 +00001212 (void) FormatLocaleString(buffer,MagickPathExtent,"iterations=%.20g\n",
cristye8c25f92010-06-03 00:53:06 +00001213 (double) image->iterations);
cristy3ed852e2009-09-05 21:47:34 +00001214 (void) WriteBlobString(image,buffer);
1215 }
1216 if (image->delay != 0)
1217 {
cristy151b66d2015-04-15 10:50:31 +00001218 (void) FormatLocaleString(buffer,MagickPathExtent,"delay=%.20g\n",
cristye8c25f92010-06-03 00:53:06 +00001219 (double) image->delay);
cristy3ed852e2009-09-05 21:47:34 +00001220 (void) WriteBlobString(image,buffer);
1221 }
1222 if (image->ticks_per_second != UndefinedTicksPerSecond)
1223 {
cristy151b66d2015-04-15 10:50:31 +00001224 (void) FormatLocaleString(buffer,MagickPathExtent,
cristye8c25f92010-06-03 00:53:06 +00001225 "ticks-per-second=%.20g\n",(double) image->ticks_per_second);
cristy3ed852e2009-09-05 21:47:34 +00001226 (void) WriteBlobString(image,buffer);
1227 }
1228 }
1229 if (image->gravity != UndefinedGravity)
1230 {
cristy151b66d2015-04-15 10:50:31 +00001231 (void) FormatLocaleString(buffer,MagickPathExtent,"gravity=%s\n",
cristy042ee782011-04-22 18:48:30 +00001232 CommandOptionToMnemonic(MagickGravityOptions,image->gravity));
cristy3ed852e2009-09-05 21:47:34 +00001233 (void) WriteBlobString(image,buffer);
1234 }
1235 if (image->dispose != UndefinedDispose)
1236 {
cristy151b66d2015-04-15 10:50:31 +00001237 (void) FormatLocaleString(buffer,MagickPathExtent,"dispose=%s\n",
cristy042ee782011-04-22 18:48:30 +00001238 CommandOptionToMnemonic(MagickDisposeOptions,image->dispose));
cristy3ed852e2009-09-05 21:47:34 +00001239 (void) WriteBlobString(image,buffer);
1240 }
1241 if (image->rendering_intent != UndefinedIntent)
1242 {
cristy151b66d2015-04-15 10:50:31 +00001243 (void) FormatLocaleString(buffer,MagickPathExtent,
cristyaff6d802011-04-26 01:46:31 +00001244 "rendering-intent=%s\n",CommandOptionToMnemonic(MagickIntentOptions,
1245 image->rendering_intent));
cristy3ed852e2009-09-05 21:47:34 +00001246 (void) WriteBlobString(image,buffer);
1247 }
1248 if (image->gamma != 0.0)
1249 {
cristy151b66d2015-04-15 10:50:31 +00001250 (void) FormatLocaleString(buffer,MagickPathExtent,"gamma=%g\n",
cristy3ed852e2009-09-05 21:47:34 +00001251 image->gamma);
1252 (void) WriteBlobString(image,buffer);
1253 }
1254 if (image->chromaticity.white_point.x != 0.0)
1255 {
1256 /*
1257 Note chomaticity points.
1258 */
cristy151b66d2015-04-15 10:50:31 +00001259 (void) FormatLocaleString(buffer,MagickPathExtent,"red-primary="
cristye7f51092010-01-17 00:39:37 +00001260 "%g,%g green-primary=%g,%g blue-primary=%g,%g\n",
cristy3ed852e2009-09-05 21:47:34 +00001261 image->chromaticity.red_primary.x,image->chromaticity.red_primary.y,
1262 image->chromaticity.green_primary.x,
1263 image->chromaticity.green_primary.y,
1264 image->chromaticity.blue_primary.x,
1265 image->chromaticity.blue_primary.y);
1266 (void) WriteBlobString(image,buffer);
cristy151b66d2015-04-15 10:50:31 +00001267 (void) FormatLocaleString(buffer,MagickPathExtent,
cristye7f51092010-01-17 00:39:37 +00001268 "white-point=%g,%g\n",image->chromaticity.white_point.x,
cristy8cd5b312010-01-07 01:10:24 +00001269 image->chromaticity.white_point.y);
cristy3ed852e2009-09-05 21:47:34 +00001270 (void) WriteBlobString(image,buffer);
1271 }
1272 if (image->orientation != UndefinedOrientation)
1273 {
cristy151b66d2015-04-15 10:50:31 +00001274 (void) FormatLocaleString(buffer,MagickPathExtent,
cristy042ee782011-04-22 18:48:30 +00001275 "orientation=%s\n",CommandOptionToMnemonic(MagickOrientationOptions,
cristy3ed852e2009-09-05 21:47:34 +00001276 image->orientation));
1277 (void) WriteBlobString(image,buffer);
1278 }
1279 if (image->profiles != (void *) NULL)
1280 {
1281 const char
1282 *name;
1283
1284 const StringInfo
1285 *profile;
1286
1287 /*
1288 Generic profile.
1289 */
1290 ResetImageProfileIterator(image);
1291 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1292 {
1293 profile=GetImageProfile(image,name);
1294 if (profile != (StringInfo *) NULL)
1295 {
cristy151b66d2015-04-15 10:50:31 +00001296 (void) FormatLocaleString(buffer,MagickPathExtent,
cristye8c25f92010-06-03 00:53:06 +00001297 "profile:%s=%.20g\n",name,(double)
1298 GetStringInfoLength(profile));
cristy3ed852e2009-09-05 21:47:34 +00001299 (void) WriteBlobString(image,buffer);
1300 }
1301 name=GetNextImageProfile(image);
1302 }
1303 }
1304 if (image->montage != (char *) NULL)
1305 {
cristy151b66d2015-04-15 10:50:31 +00001306 (void) FormatLocaleString(buffer,MagickPathExtent,"montage=%s\n",
cristy3ed852e2009-09-05 21:47:34 +00001307 image->montage);
1308 (void) WriteBlobString(image,buffer);
1309 }
1310 ResetImagePropertyIterator(image);
1311 property=GetNextImageProperty(image);
1312 while (property != (const char *) NULL)
1313 {
cristy151b66d2015-04-15 10:50:31 +00001314 (void) FormatLocaleString(buffer,MagickPathExtent,"%s=",property);
cristy3ed852e2009-09-05 21:47:34 +00001315 (void) WriteBlobString(image,buffer);
cristyd15e6592011-10-15 00:13:06 +00001316 value=GetImageProperty(image,property,exception);
cristy3ed852e2009-09-05 21:47:34 +00001317 if (value != (const char *) NULL)
1318 {
cristyd76ed5d2012-05-20 16:15:57 +00001319 size_t
1320 length;
1321
cristy181c99c2012-05-20 16:14:14 +00001322 length=strlen(value);
1323 for (i=0; i < (ssize_t) length; i++)
cristy3ed852e2009-09-05 21:47:34 +00001324 if (isspace((int) ((unsigned char) value[i])) != 0)
1325 break;
cristy04e917f2013-08-17 00:54:17 +00001326 if ((i == (ssize_t) length) && (i != 0))
cristy181c99c2012-05-20 16:14:14 +00001327 (void) WriteBlob(image,length,(const unsigned char *) value);
cristyb880ee82012-04-07 15:08:14 +00001328 else
1329 {
1330 (void) WriteBlobByte(image,'{');
cristy181c99c2012-05-20 16:14:14 +00001331 if (strchr(value,'}') == (char *) NULL)
1332 (void) WriteBlob(image,length,(const unsigned char *) value);
1333 else
1334 for (i=0; i < (ssize_t) length; i++)
1335 {
1336 if (value[i] == (int) '}')
1337 (void) WriteBlobByte(image,'\\');
1338 (void) WriteBlobByte(image,value[i]);
1339 }
cristyb880ee82012-04-07 15:08:14 +00001340 (void) WriteBlobByte(image,'}');
1341 }
cristy3ed852e2009-09-05 21:47:34 +00001342 }
1343 (void) WriteBlobByte(image,'\n');
1344 property=GetNextImageProperty(image);
1345 }
cristy3ed852e2009-09-05 21:47:34 +00001346 (void) WriteBlobString(image,"\f\n:\032");
1347 if (image->montage != (char *) NULL)
1348 {
1349 /*
1350 Write montage tile directory.
1351 */
1352 if (image->directory != (char *) NULL)
1353 (void) WriteBlobString(image,image->directory);
1354 (void) WriteBlobByte(image,'\0');
1355 }
1356 if (image->profiles != 0)
1357 {
1358 const char
1359 *name;
1360
1361 const StringInfo
1362 *profile;
1363
1364 /*
1365 Write image profiles.
1366 */
1367 ResetImageProfileIterator(image);
1368 name=GetNextImageProfile(image);
1369 while (name != (const char *) NULL)
1370 {
1371 profile=GetImageProfile(image,name);
1372 (void) WriteBlob(image,GetStringInfoLength(profile),
1373 GetStringInfoDatum(profile));
1374 name=GetNextImageProfile(image);
1375 }
1376 }
1377 if (image->storage_class == PseudoClass)
1378 {
1379 size_t
1380 packet_size;
1381
1382 unsigned char
1383 *colormap,
1384 *q;
1385
1386 /*
1387 Allocate colormap.
1388 */
1389 packet_size=(size_t) (3UL*depth/8UL);
1390 colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
1391 packet_size*sizeof(*colormap));
1392 if (colormap == (unsigned char *) NULL)
1393 return(MagickFalse);
1394 /*
1395 Write colormap to file.
1396 */
1397 q=colormap;
cristybb503372010-05-27 20:51:26 +00001398 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00001399 {
1400 switch (depth)
1401 {
1402 default:
1403 ThrowWriterException(CorruptImageError,"ImageDepthNotSupported");
1404 case 32:
1405 {
cristy4cb162a2010-05-30 03:04:47 +00001406 unsigned int
cristy3ed852e2009-09-05 21:47:34 +00001407 pixel;
1408
1409 pixel=ScaleQuantumToLong(image->colormap[i].red);
1410 q=PopLongPixel(MSBEndian,pixel,q);
1411 pixel=ScaleQuantumToLong(image->colormap[i].green);
1412 q=PopLongPixel(MSBEndian,pixel,q);
1413 pixel=ScaleQuantumToLong(image->colormap[i].blue);
1414 q=PopLongPixel(MSBEndian,pixel,q);
dirkc67e36d2014-05-18 06:58:25 +00001415 break;
cristy3ed852e2009-09-05 21:47:34 +00001416 }
1417 case 16:
1418 {
1419 unsigned short
1420 pixel;
1421
1422 pixel=ScaleQuantumToShort(image->colormap[i].red);
1423 q=PopShortPixel(MSBEndian,pixel,q);
1424 pixel=ScaleQuantumToShort(image->colormap[i].green);
1425 q=PopShortPixel(MSBEndian,pixel,q);
1426 pixel=ScaleQuantumToShort(image->colormap[i].blue);
1427 q=PopShortPixel(MSBEndian,pixel,q);
1428 break;
1429 }
1430 case 8:
1431 {
1432 unsigned char
1433 pixel;
1434
1435 pixel=(unsigned char) ScaleQuantumToChar(image->colormap[i].red);
1436 q=PopCharPixel(pixel,q);
1437 pixel=(unsigned char) ScaleQuantumToChar(
1438 image->colormap[i].green);
1439 q=PopCharPixel(pixel,q);
1440 pixel=(unsigned char) ScaleQuantumToChar(image->colormap[i].blue);
1441 q=PopCharPixel(pixel,q);
1442 break;
1443 }
1444 }
1445 }
1446 (void) WriteBlob(image,packet_size*image->colors,colormap);
1447 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1448 }
1449 /*
1450 Initialize persistent pixel cache.
1451 */
1452 status=PersistPixelCache(image,cache_filename,MagickFalse,&offset,
cristy1e178e72011-08-28 19:44:34 +00001453 exception);
cristy3ed852e2009-09-05 21:47:34 +00001454 if (status == MagickFalse)
1455 ThrowWriterException(CacheError,"UnableToPersistPixelCache");
1456 if (GetNextImageInList(image) == (Image *) NULL)
1457 break;
1458 image=SyncNextImageInList(image);
1459 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1460 {
1461 status=image->progress_monitor(SaveImagesTag,scene,
1462 GetImageListLength(image),image->client_data);
1463 if (status == MagickFalse)
1464 break;
1465 }
1466 scene++;
1467 } while (image_info->adjoin != MagickFalse);
1468 (void) CloseBlob(image);
1469 return(status);
1470}