Coverage Report

Created: 2025-06-16 07:00

/src/imagemagick/coders/mpc.c
Line
Count
Source (jump to first uncovered line)
1
/*
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 Pixel Cache Image Format                  %
14
%                                                                             %
15
%                              Software Design                                %
16
%                                   Cristy                                    %
17
%                                 March 2000                                  %
18
%                                                                             %
19
%                                                                             %
20
%  Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization         %
21
%  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
%    https://imagemagick.org/script/license.php                               %
27
%                                                                             %
28
%  Unless required by applicable law or agreed to in writing, software        %
29
%  distributed under the License is distributed on an "AS IS" BASIS,          %
30
%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31
%  See the License for the specific language governing permissions and        %
32
%  limitations under the License.                                             %
33
%                                                                             %
34
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35
%
36
%
37
%
38
*/
39

40
/*
41
  Include declarations.
42
*/
43
#include "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/image.h"
57
#include "MagickCore/image-private.h"
58
#include "MagickCore/linked-list.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/pixel-private.h"
67
#include "MagickCore/profile-private.h"
68
#include "MagickCore/property.h"
69
#include "MagickCore/quantum-private.h"
70
#include "MagickCore/resource_.h"
71
#include "MagickCore/static.h"
72
#include "MagickCore/statistic.h"
73
#include "MagickCore/string_.h"
74
#include "MagickCore/string-private.h"
75
#include "MagickCore/utility.h"
76
#include "MagickCore/version-private.h"
77

78
/*
79
  Define declarations.
80
*/
81
9.00k
#define MagickPixelCacheNonce  "MagickPixelCache"
82

83
/*
84
  Forward declarations.
85
*/
86
static MagickBooleanType
87
  WriteMPCImage(const ImageInfo *,Image *,ExceptionInfo *);
88

89
/*
90
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
91
%                                                                             %
92
%                                                                             %
93
%                                                                             %
94
%   I s M P C                                                                 %
95
%                                                                             %
96
%                                                                             %
97
%                                                                             %
98
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
99
%
100
%  IsMPC() returns MagickTrue if the image format type, identified by the
101
%  magick string, is an Magick Pixel Cache image.
102
%
103
%  The format of the IsMPC method is:
104
%
105
%      MagickBooleanType IsMPC(const unsigned char *magick,const size_t length)
106
%
107
%  A description of each parameter follows:
108
%
109
%    o magick: compare image format pattern against these bytes.
110
%
111
%    o length: Specifies the length of the magick string.
112
%
113
*/
114
static MagickBooleanType IsMPC(const unsigned char *magick,const size_t length)
115
0
{
116
0
  if (length < 19)
117
0
    return(MagickFalse);
118
0
  if (LocaleNCompare((const char *) magick,"id=MagickPixelCache",19) == 0)
119
0
    return(MagickTrue);
120
0
  return(MagickFalse);
121
0
}
122

123
/*
124
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
125
%                                                                             %
126
%                                                                             %
127
%                                                                             %
128
%   R e a d C A C H E I m a g e                                               %
129
%                                                                             %
130
%                                                                             %
131
%                                                                             %
132
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
133
%
134
%  ReadMPCImage() reads an Magick Pixel Cache image file and returns
135
%  it.  It allocates the memory necessary for the new Image structure and
136
%  returns a pointer to the new image.
137
%
138
%  The format of the ReadMPCImage method is:
139
%
140
%      Image *ReadMPCImage(const ImageInfo *image_info,ExceptionInfo *exception)
141
%
142
%  Decompression code contributed by Kyle Shorter.
143
%
144
%  A description of each parameter follows:
145
%
146
%    o image_info: the image info.
147
%
148
%    o exception: return any errors or warnings in this structure.
149
%
150
*/
151
static Image *ReadMPCImage(const ImageInfo *image_info,ExceptionInfo *exception)
152
7.73k
{
153
7.73k
  char
154
7.73k
    cache_filename[MagickPathExtent],
155
7.73k
    id[MagickPathExtent],
156
7.73k
    keyword[MagickPathExtent],
157
7.73k
    *options;
158
159
7.73k
  GeometryInfo
160
7.73k
    geometry_info;
161
162
7.73k
  Image
163
7.73k
    *image;
164
165
7.73k
  int
166
7.73k
    c;
167
168
7.73k
  LinkedListInfo
169
7.73k
    *profiles;
170
171
7.73k
  MagickBooleanType
172
7.73k
    status;
173
174
7.73k
  MagickOffsetType
175
7.73k
    offset;
176
177
7.73k
  MagickStatusType
178
7.73k
    flags;
179
180
7.73k
  size_t
181
7.73k
    depth,
182
7.73k
    extent,
183
7.73k
    length;
184
185
7.73k
  ssize_t
186
7.73k
    count,
187
7.73k
    i;
188
189
7.73k
  StringInfo
190
7.73k
    *nonce;
191
192
7.73k
  unsigned int
193
7.73k
    signature;
194
195
  /*
196
    Open image file.
197
  */
198
7.73k
  assert(image_info != (const ImageInfo *) NULL);
199
7.73k
  assert(image_info->signature == MagickCoreSignature);
200
7.73k
  assert(exception != (ExceptionInfo *) NULL);
201
7.73k
  assert(exception->signature == MagickCoreSignature);
202
7.73k
  if (IsEventLogging() != MagickFalse)
203
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
204
0
      image_info->filename);
205
7.73k
  image=AcquireImage(image_info,exception);
206
7.73k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
207
7.73k
  if (status == MagickFalse)
208
0
    {
209
0
      image=DestroyImageList(image);
210
0
      return((Image *) NULL);
211
0
    }
212
7.73k
  (void) CopyMagickString(cache_filename,image->filename,MagickPathExtent-6);
213
7.73k
  AppendImageFormat("cache",cache_filename);
214
7.73k
  c=ReadBlobByte(image);
215
7.73k
  if (c == EOF)
216
0
    {
217
0
      image=DestroyImage(image);
218
0
      return((Image *) NULL);
219
0
    }
220
7.73k
  *id='\0';
221
7.73k
  (void) memset(keyword,0,sizeof(keyword));
222
7.73k
  offset=0;
223
7.73k
  do
224
7.73k
  {
225
    /*
226
      Decode image header;  header terminates one character beyond a ':'.
227
    */
228
7.73k
    SetGeometryInfo(&geometry_info);
229
7.73k
    profiles=(LinkedListInfo *) NULL;
230
7.73k
    length=MagickPathExtent;
231
7.73k
    options=AcquireString((char *) NULL);
232
7.73k
    nonce=StringToStringInfo(MagickPixelCacheNonce);
233
7.73k
    signature=GetMagickSignature(nonce);
234
7.73k
    nonce=DestroyStringInfo(nonce);
235
7.73k
    image->depth=8;
236
7.73k
    image->compression=NoCompression;
237
225k
    while ((isgraph((int) ((unsigned char) c)) != 0) && (c != (int) ':'))
238
217k
    {
239
217k
      char
240
217k
        *p;
241
242
217k
      if (c == (int) '{')
243
7.33k
        {
244
7.33k
          char
245
7.33k
            *comment;
246
247
          /*
248
            Read comment-- any text between { }.
249
          */
250
7.33k
          length=MagickPathExtent;
251
7.33k
          comment=AcquireString((char *) NULL);
252
57.6k
          for (p=comment; comment != (char *) NULL; p++)
253
57.6k
          {
254
57.6k
            c=ReadBlobByte(image);
255
57.6k
            if (c == (int) '\\')
256
935
              c=ReadBlobByte(image);
257
56.7k
            else
258
56.7k
              if ((c == EOF) || (c == (int) '}'))
259
7.33k
                break;
260
50.3k
            if ((size_t) (p-comment+1) >= length)
261
4
              {
262
4
                *p='\0';
263
4
                length<<=1;
264
4
                comment=(char *) ResizeQuantumMemory(comment,length+
265
4
                  MagickPathExtent,sizeof(*comment));
266
4
                if (comment == (char *) NULL)
267
0
                  break;
268
4
                p=comment+strlen(comment);
269
4
              }
270
50.3k
            *p=(char) c;
271
50.3k
          }
272
7.33k
          if (comment == (char *) NULL)
273
0
            {
274
0
              options=DestroyString(options);
275
0
              ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
276
0
            }
277
7.33k
          *p='\0';
278
7.33k
          (void) SetImageProperty(image,"comment",comment,exception);
279
7.33k
          comment=DestroyString(comment);
280
7.33k
          c=ReadBlobByte(image);
281
7.33k
        }
282
210k
      else
283
210k
        if (isalnum((int) ((unsigned char) c)) != MagickFalse)
284
126k
          {
285
            /*
286
              Get the keyword.
287
            */
288
126k
            length=MagickPathExtent-1;
289
126k
            p=keyword;
290
126k
            do
291
1.24M
            {
292
1.24M
              if (c == (int) '=')
293
123k
                break;
294
1.12M
              if ((size_t) (p-keyword) < (MagickPathExtent-1))
295
1.12M
                *p++=(char) c;
296
1.12M
              c=ReadBlobByte(image);
297
1.12M
            } while (c != EOF);
298
0
            *p='\0';
299
126k
            p=options;
300
126k
            while (isspace((int) ((unsigned char) c)) != 0)
301
0
              c=ReadBlobByte(image);
302
126k
            if (c == (int) '=')
303
123k
              {
304
                /*
305
                  Get the keyword value.
306
                */
307
123k
                c=ReadBlobByte(image);
308
1.00M
                while ((c != (int) '{') && (c != (int) '}') && (c != EOF))
309
917k
                {
310
917k
                  if ((size_t) (p-options+1) >= length)
311
16
                    {
312
16
                      *p='\0';
313
16
                      length<<=1;
314
16
                      options=(char *) ResizeQuantumMemory(options,length+
315
16
                        MagickPathExtent,sizeof(*options));
316
16
                      if (options == (char *) NULL)
317
0
                        break;
318
16
                      p=options+strlen(options);
319
16
                    }
320
917k
                  *p++=(char) c;
321
917k
                  c=ReadBlobByte(image);
322
917k
                  if (c == '\\')
323
4.71k
                    {
324
4.71k
                      c=ReadBlobByte(image);
325
4.71k
                      if ((c == (int) '{') || (c == (int) '}'))
326
801
                        {
327
801
                          *p++=(char) c;
328
801
                          c=ReadBlobByte(image);
329
801
                        }
330
4.71k
                    }
331
917k
                  if (*options != '{')
332
917k
                    if (isspace((int) ((unsigned char) c)) != 0)
333
40.6k
                      break;
334
917k
                }
335
123k
                if (options == (char *) NULL)
336
0
                  ThrowReaderException(ResourceLimitError,
337
123k
                    "MemoryAllocationFailed");
338
123k
              }
339
126k
            *p='\0';
340
126k
            if (*options == '{')
341
0
              (void) CopyMagickString(options,options+1,strlen(options));
342
            /*
343
              Assign a value to the specified keyword.
344
            */
345
126k
            switch (*keyword)
346
126k
            {
347
1.93k
              case 'a':
348
5.62k
              case 'A':
349
5.62k
              {
350
5.62k
                if (LocaleCompare(keyword,"alpha-trait") == 0)
351
396
                  {
352
396
                    ssize_t
353
396
                      alpha_trait;
354
355
396
                    alpha_trait=ParseCommandOption(MagickPixelTraitOptions,
356
396
                      MagickFalse,options);
357
396
                    if (alpha_trait < 0)
358
194
                      break;
359
202
                    image->alpha_trait=(PixelTrait) alpha_trait;
360
202
                    break;
361
396
                  }
362
5.23k
                (void) SetImageProperty(image,keyword,options,exception);
363
5.23k
                break;
364
5.62k
              }
365
4.69k
              case 'b':
366
6.75k
              case 'B':
367
6.75k
              {
368
6.75k
                if (LocaleCompare(keyword,"background-color") == 0)
369
194
                  {
370
194
                    (void) QueryColorCompliance(options,AllCompliance,
371
194
                      &image->background_color,exception);
372
194
                    break;
373
194
                  }
374
6.56k
                if (LocaleCompare(keyword,"blue-primary") == 0)
375
389
                  {
376
389
                    flags=ParseGeometry(options,&geometry_info);
377
389
                    image->chromaticity.blue_primary.x=geometry_info.rho;
378
389
                    image->chromaticity.blue_primary.y=geometry_info.sigma;
379
389
                    if ((flags & SigmaValue) == 0)
380
194
                      image->chromaticity.blue_primary.y=
381
194
                        image->chromaticity.blue_primary.x;
382
389
                    break;
383
389
                  }
384
6.17k
                if (LocaleCompare(keyword,"border-color") == 0)
385
554
                  {
386
554
                    (void) QueryColorCompliance(options,AllCompliance,
387
554
                      &image->border_color,exception);
388
554
                    break;
389
554
                  }
390
5.62k
                (void) SetImageProperty(image,keyword,options,exception);
391
5.62k
                break;
392
6.17k
              }
393
6.17k
              case 'c':
394
7.49k
              case 'C':
395
7.49k
              {
396
7.49k
                if (LocaleCompare(keyword,"channel-mask") == 0)
397
0
                  {
398
0
                    image->channel_mask=(ChannelType)
399
0
                      strtol(options,(char **) NULL,16);
400
0
                    break;
401
0
                  }
402
7.49k
                if (LocaleCompare(keyword,"class") == 0)
403
557
                  {
404
557
                    ssize_t
405
557
                      storage_class;
406
407
557
                    storage_class=ParseCommandOption(MagickClassOptions,
408
557
                      MagickFalse,options);
409
557
                    if (storage_class < 0)
410
201
                      break;
411
356
                    image->storage_class=(ClassType) storage_class;
412
356
                    break;
413
557
                  }
414
6.94k
                if (LocaleCompare(keyword,"colors") == 0)
415
350
                  {
416
350
                    image->colors=StringToUnsignedLong(options);
417
350
                    break;
418
350
                  }
419
6.59k
                if (LocaleCompare(keyword,"colorspace") == 0)
420
395
                  {
421
395
                    ssize_t
422
395
                      colorspace;
423
424
395
                    colorspace=ParseCommandOption(MagickColorspaceOptions,
425
395
                      MagickFalse,options);
426
395
                    if (colorspace < 0)
427
194
                      break;
428
201
                    image->colorspace=(ColorspaceType) colorspace;
429
201
                    break;
430
395
                  }
431
6.19k
                if (LocaleCompare(keyword,"compression") == 0)
432
525
                  {
433
525
                    ssize_t
434
525
                      compression;
435
436
525
                    compression=ParseCommandOption(MagickCompressOptions,
437
525
                      MagickFalse,options);
438
525
                    if (compression < 0)
439
295
                      break;
440
230
                    image->compression=(CompressionType) compression;
441
230
                    break;
442
525
                  }
443
5.67k
                if (LocaleCompare(keyword,"columns") == 0)
444
2.13k
                  {
445
2.13k
                    image->columns=StringToUnsignedLong(options);
446
2.13k
                    break;
447
2.13k
                  }
448
3.53k
                (void) SetImageProperty(image,keyword,options,exception);
449
3.53k
                break;
450
5.67k
              }
451
2.16k
              case 'd':
452
13.3k
              case 'D':
453
13.3k
              {
454
13.3k
                if (LocaleCompare(keyword,"delay") == 0)
455
194
                  {
456
194
                    image->delay=StringToUnsignedLong(options);
457
194
                    break;
458
194
                  }
459
13.1k
                if (LocaleCompare(keyword,"depth") == 0)
460
330
                  {
461
330
                    image->depth=StringToUnsignedLong(options);
462
330
                    break;
463
330
                  }
464
12.8k
                if (LocaleCompare(keyword,"dispose") == 0)
465
490
                  {
466
490
                    ssize_t
467
490
                      dispose;
468
469
490
                    dispose=ParseCommandOption(MagickDisposeOptions,MagickFalse,
470
490
                      options);
471
490
                    if (dispose < 0)
472
295
                      break;
473
195
                    image->dispose=(DisposeType) dispose;
474
195
                    break;
475
490
                  }
476
12.3k
                (void) SetImageProperty(image,keyword,options,exception);
477
12.3k
                break;
478
12.8k
              }
479
1.99k
              case 'e':
480
2.77k
              case 'E':
481
2.77k
              {
482
2.77k
                if (LocaleCompare(keyword,"endian") == 0)
483
424
                  {
484
424
                    ssize_t
485
424
                      endian;
486
487
424
                    endian=ParseCommandOption(MagickEndianOptions,MagickFalse,
488
424
                      options);
489
424
                    if (endian < 0)
490
229
                      break;
491
195
                    image->endian=(EndianType) endian;
492
195
                    break;
493
424
                  }
494
2.35k
                if (LocaleCompare(keyword,"error") == 0)
495
195
                  {
496
195
                    image->error.mean_error_per_pixel=StringToDouble(options,
497
195
                      (char **) NULL);
498
195
                    break;
499
195
                  }
500
2.15k
                (void) SetImageProperty(image,keyword,options,exception);
501
2.15k
                break;
502
2.35k
              }
503
4.24k
              case 'g':
504
5.19k
              case 'G':
505
5.19k
              {
506
5.19k
                if (LocaleCompare(keyword,"gamma") == 0)
507
194
                  {
508
194
                    image->gamma=StringToDouble(options,(char **) NULL);
509
194
                    break;
510
194
                  }
511
4.99k
                if (LocaleCompare(keyword,"green-primary") == 0)
512
1.84k
                  {
513
1.84k
                    flags=ParseGeometry(options,&geometry_info);
514
1.84k
                    image->chromaticity.green_primary.x=geometry_info.rho;
515
1.84k
                    image->chromaticity.green_primary.y=geometry_info.sigma;
516
1.84k
                    if ((flags & SigmaValue) == 0)
517
1.34k
                      image->chromaticity.green_primary.y=
518
1.34k
                        image->chromaticity.green_primary.x;
519
1.84k
                    break;
520
1.84k
                  }
521
3.15k
                (void) SetImageProperty(image,keyword,options,exception);
522
3.15k
                break;
523
4.99k
              }
524
5.37k
              case 'i':
525
7.77k
              case 'I':
526
7.77k
              {
527
7.77k
                if (LocaleCompare(keyword,"id") == 0)
528
3.05k
                  {
529
3.05k
                    (void) CopyMagickString(id,options,MagickPathExtent);
530
3.05k
                    break;
531
3.05k
                  }
532
4.72k
                if (LocaleCompare(keyword,"iterations") == 0)
533
194
                  {
534
194
                    image->iterations=StringToUnsignedLong(options);
535
194
                    break;
536
194
                  }
537
4.52k
                (void) SetImageProperty(image,keyword,options,exception);
538
4.52k
                break;
539
4.72k
              }
540
25.1k
              case 'm':
541
27.6k
              case 'M':
542
27.6k
              {
543
27.6k
                if (LocaleCompare(keyword,"magick-signature") == 0)
544
232
                  {
545
232
                    signature=(unsigned int) StringToUnsignedLong(options);
546
232
                    break;
547
232
                  }
548
27.4k
                if (LocaleCompare(keyword,"mattecolor") == 0)
549
20.6k
                  {
550
20.6k
                    (void) QueryColorCompliance(options,AllCompliance,
551
20.6k
                      &image->matte_color,exception);
552
20.6k
                    break;
553
20.6k
                  }
554
6.81k
                if (LocaleCompare(keyword,"maximum-error") == 0)
555
198
                  {
556
198
                    image->error.normalized_maximum_error=StringToDouble(
557
198
                      options,(char **) NULL);
558
198
                    break;
559
198
                  }
560
6.61k
                if (LocaleCompare(keyword,"mean-error") == 0)
561
194
                  {
562
194
                    image->error.normalized_mean_error=StringToDouble(options,
563
194
                      (char **) NULL);
564
194
                    break;
565
194
                  }
566
6.42k
                if (LocaleCompare(keyword,"montage") == 0)
567
1.24k
                  {
568
1.24k
                    (void) CloneString(&image->montage,options);
569
1.24k
                    break;
570
1.24k
                  }
571
5.17k
                (void) SetImageProperty(image,keyword,options,exception);
572
5.17k
                break;
573
6.42k
              }
574
1.16k
              case 'n':
575
1.62k
              case 'N':
576
1.62k
              {
577
1.62k
                if (LocaleCompare(keyword,"number-channels") == 0)
578
288
                  {
579
288
                    image->number_channels=StringToUnsignedLong(options);
580
288
                    break;
581
288
                  }
582
1.33k
                if (LocaleCompare(keyword,"number-meta-channels") == 0)
583
445
                  {
584
445
                    image->number_meta_channels=StringToUnsignedLong(options);
585
445
                    break;
586
445
                  }
587
894
                break;
588
1.33k
              }
589
1.71k
              case 'o':
590
2.81k
              case 'O':
591
2.81k
              {
592
2.81k
                if (LocaleCompare(keyword,"orientation") == 0)
593
388
                  {
594
388
                    ssize_t
595
388
                      orientation;
596
597
388
                    orientation=ParseCommandOption(MagickOrientationOptions,
598
388
                      MagickFalse,options);
599
388
                    if (orientation < 0)
600
194
                      break;
601
194
                    image->orientation=(OrientationType) orientation;
602
194
                    break;
603
388
                  }
604
2.42k
                (void) SetImageProperty(image,keyword,options,exception);
605
2.42k
                break;
606
2.81k
              }
607
11.3k
              case 'p':
608
14.2k
              case 'P':
609
14.2k
              {
610
14.2k
                if (LocaleCompare(keyword,"page") == 0)
611
2.80k
                  {
612
2.80k
                    char
613
2.80k
                      *geometry;
614
615
2.80k
                    geometry=GetPageGeometry(options);
616
2.80k
                    (void) ParseAbsoluteGeometry(geometry,&image->page);
617
2.80k
                    geometry=DestroyString(geometry);
618
2.80k
                    break;
619
2.80k
                  }
620
11.4k
                if (LocaleCompare(keyword,"pixel-intensity") == 0)
621
388
                  {
622
388
                    ssize_t
623
388
                      intensity;
624
625
388
                    intensity=ParseCommandOption(MagickPixelIntensityOptions,
626
388
                      MagickFalse,options);
627
388
                    if (intensity < 0)
628
194
                      break;
629
194
                    image->intensity=(PixelIntensityMethod) intensity;
630
194
                    break;
631
388
                  }
632
11.0k
                if (LocaleCompare(keyword,"profile") == 0)
633
7.40k
                  {
634
7.40k
                    if (profiles == (LinkedListInfo *) NULL)
635
665
                      profiles=NewLinkedList(0);
636
7.40k
                    (void) AppendValueToLinkedList(profiles,
637
7.40k
                      AcquireString(options));
638
7.40k
                    break;
639
7.40k
                  }
640
3.60k
                (void) SetImageProperty(image,keyword,options,exception);
641
3.60k
                break;
642
11.0k
              }
643
670
              case 'q':
644
3.64k
              case 'Q':
645
3.64k
              {
646
3.64k
                if (LocaleCompare(keyword,"quality") == 0)
647
194
                  {
648
194
                    image->quality=StringToUnsignedLong(options);
649
194
                    break;
650
194
                  }
651
3.44k
                (void) SetImageProperty(image,keyword,options,exception);
652
3.44k
                break;
653
3.64k
              }
654
4.25k
              case 'r':
655
5.30k
              case 'R':
656
5.30k
              {
657
5.30k
                if (LocaleCompare(keyword,"red-primary") == 0)
658
447
                  {
659
447
                    flags=ParseGeometry(options,&geometry_info);
660
447
                    image->chromaticity.red_primary.x=geometry_info.rho;
661
447
                    if ((flags & SigmaValue) != 0)
662
205
                      image->chromaticity.red_primary.y=geometry_info.sigma;
663
447
                    break;
664
447
                  }
665
4.85k
                if (LocaleCompare(keyword,"rendering-intent") == 0)
666
397
                  {
667
397
                    ssize_t
668
397
                      rendering_intent;
669
670
397
                    rendering_intent=ParseCommandOption(MagickIntentOptions,
671
397
                      MagickFalse,options);
672
397
                    if (rendering_intent < 0)
673
197
                      break;
674
200
                    image->rendering_intent=(RenderingIntent) rendering_intent;
675
200
                    break;
676
397
                  }
677
4.46k
                if (LocaleCompare(keyword,"resolution") == 0)
678
388
                  {
679
388
                    flags=ParseGeometry(options,&geometry_info);
680
388
                    image->resolution.x=geometry_info.rho;
681
388
                    image->resolution.y=geometry_info.sigma;
682
388
                    if ((flags & SigmaValue) == 0)
683
194
                      image->resolution.y=image->resolution.x;
684
388
                    break;
685
388
                  }
686
4.07k
                if (LocaleCompare(keyword,"rows") == 0)
687
1.99k
                  {
688
1.99k
                    image->rows=StringToUnsignedLong(options);
689
1.99k
                    break;
690
1.99k
                  }
691
2.07k
                (void) SetImageProperty(image,keyword,options,exception);
692
2.07k
                break;
693
4.07k
              }
694
2.02k
              case 's':
695
2.73k
              case 'S':
696
2.73k
              {
697
2.73k
                if (LocaleCompare(keyword,"scene") == 0)
698
194
                  {
699
194
                    image->scene=StringToUnsignedLong(options);
700
194
                    break;
701
194
                  }
702
2.53k
                (void) SetImageProperty(image,keyword,options,exception);
703
2.53k
                break;
704
2.73k
              }
705
7.04k
              case 't':
706
7.66k
              case 'T':
707
7.66k
              {
708
7.66k
                if (LocaleCompare(keyword,"ticks-per-second") == 0)
709
194
                  {
710
194
                    image->ticks_per_second=(ssize_t) StringToLong(options);
711
194
                    break;
712
194
                  }
713
7.46k
                if (LocaleCompare(keyword,"tile-offset") == 0)
714
1.78k
                  {
715
1.78k
                    char
716
1.78k
                      *geometry;
717
718
1.78k
                    geometry=GetPageGeometry(options);
719
1.78k
                    (void) ParseAbsoluteGeometry(geometry,&image->tile_offset);
720
1.78k
                    geometry=DestroyString(geometry);
721
1.78k
                  }
722
7.46k
                if (LocaleCompare(keyword,"type") == 0)
723
4.11k
                  {
724
4.11k
                    ssize_t
725
4.11k
                      type;
726
727
4.11k
                    type=ParseCommandOption(MagickTypeOptions,MagickFalse,
728
4.11k
                      options);
729
4.11k
                    if (type < 0)
730
3.71k
                      break;
731
398
                    image->type=(ImageType) type;
732
398
                    break;
733
4.11k
                  }
734
3.35k
                (void) SetImageProperty(image,keyword,options,exception);
735
3.35k
                break;
736
7.46k
              }
737
2.54k
              case 'u':
738
3.10k
              case 'U':
739
3.10k
              {
740
3.10k
                if (LocaleCompare(keyword,"units") == 0)
741
1.71k
                  {
742
1.71k
                    ssize_t
743
1.71k
                      units;
744
745
1.71k
                    units=ParseCommandOption(MagickResolutionOptions,
746
1.71k
                      MagickFalse,options);
747
1.71k
                    if (units < 0)
748
200
                      break;
749
1.51k
                    image->units=(ResolutionType) units;
750
1.51k
                    break;
751
1.71k
                  }
752
1.39k
                (void) SetImageProperty(image,keyword,options,exception);
753
1.39k
                break;
754
3.10k
              }
755
1.23k
              case 'w':
756
2.03k
              case 'W':
757
2.03k
              {
758
2.03k
                if (LocaleCompare(keyword,"white-point") == 0)
759
388
                  {
760
388
                    flags=ParseGeometry(options,&geometry_info);
761
388
                    image->chromaticity.white_point.x=geometry_info.rho;
762
388
                    image->chromaticity.white_point.y=geometry_info.sigma;
763
388
                    if ((flags & SigmaValue) == 0)
764
194
                      image->chromaticity.white_point.y=
765
194
                        image->chromaticity.white_point.x;
766
388
                    break;
767
388
                  }
768
1.65k
                (void) SetImageProperty(image,keyword,options,exception);
769
1.65k
                break;
770
2.03k
              }
771
6.47k
              default:
772
6.47k
              {
773
6.47k
                (void) SetImageProperty(image,keyword,options,exception);
774
6.47k
                break;
775
2.03k
              }
776
126k
            }
777
126k
          }
778
84.1k
        else
779
84.1k
          c=ReadBlobByte(image);
780
265k
      while (isspace((int) ((unsigned char) c)) != 0)
781
47.8k
        c=ReadBlobByte(image);
782
217k
    }
783
7.73k
    options=DestroyString(options);
784
7.73k
    (void) ReadBlobByte(image);
785
    /*
786
      Verify that required image information is defined.
787
    */
788
7.73k
    if ((LocaleCompare(id,"MagickPixelCache") != 0) ||
789
7.73k
        (image->storage_class == UndefinedClass) ||
790
7.73k
        (image->compression == UndefinedCompression) ||
791
7.73k
        (image->columns == 0) || (image->rows == 0) ||
792
7.73k
        (image->number_channels > MaxPixelChannels) ||
793
7.73k
        (image->number_meta_channels > (size_t) (MaxPixelChannels-MetaPixelChannels)) ||
794
7.73k
        ((image->number_channels+image->number_meta_channels) >= MaxPixelChannels) ||
795
7.73k
        (image->depth == 0) || (image->depth > 64))
796
6.47k
      {
797
6.47k
        if (profiles != (LinkedListInfo *) NULL)
798
33
          profiles=DestroyLinkedList(profiles,RelinquishMagickMemory);
799
6.47k
        ThrowReaderException(CorruptImageError,"ImproperImageHeader");
800
0
      }
801
1.26k
    nonce=StringToStringInfo(MagickPixelCacheNonce);
802
1.26k
    if (signature != GetMagickSignature(nonce))
803
38
      {
804
38
        nonce=DestroyStringInfo(nonce);
805
38
        if (profiles != (LinkedListInfo *) NULL)
806
1
          profiles=DestroyLinkedList(profiles,RelinquishMagickMemory);
807
38
        ThrowReaderException(CacheError,"IncompatibleAPI");
808
0
      }
809
1.22k
    nonce=DestroyStringInfo(nonce);
810
1.22k
    if (image->montage != (char *) NULL)
811
22
      {
812
22
        char
813
22
          *p;
814
815
        /*
816
          Image directory.
817
        */
818
22
        extent=MagickPathExtent;
819
22
        image->directory=AcquireString((char *) NULL);
820
22
        p=image->directory;
821
22
        length=0;
822
22
        do
823
12.9k
        {
824
12.9k
          *p='\0';
825
12.9k
          if ((length+MagickPathExtent) >= extent)
826
23
            {
827
              /*
828
                Allocate more memory for the image directory.
829
              */
830
23
              extent<<=1;
831
23
              image->directory=(char *) ResizeQuantumMemory(image->directory,
832
23
                extent+MagickPathExtent,sizeof(*image->directory));
833
23
              if (image->directory == (char *) NULL)
834
0
                {
835
0
                  if (profiles != (LinkedListInfo *) NULL)
836
0
                    profiles=DestroyLinkedList(profiles,RelinquishMagickMemory);
837
0
                  ThrowReaderException(CorruptImageError,
838
0
                    "UnableToReadImageData");
839
0
                }
840
23
              p=image->directory+length;
841
23
            }
842
12.9k
          c=ReadBlobByte(image);
843
12.9k
          if (c == EOF)
844
16
            break;
845
12.9k
          *p++=(char) c;
846
12.9k
          length++;
847
12.9k
        } while (c != (int) '\0');
848
22
      }
849
1.22k
    if (profiles != (LinkedListInfo *) NULL)
850
631
      {
851
631
        const char
852
631
          *name;
853
854
631
        StringInfo
855
631
          *profile;
856
857
        /*
858
          Read image profile blobs.
859
        */
860
631
        ResetLinkedListIterator(profiles);
861
631
        name=(const char *) GetNextValueInLinkedList(profiles);
862
7.43k
        while (name != (const char *) NULL)
863
6.87k
        {
864
6.87k
          length=ReadBlobMSBLong(image);
865
6.87k
          if ((MagickSizeType) length > GetBlobSize(image))
866
32
            break;
867
6.84k
          profile=AcquireProfileStringInfo(name,length,exception);
868
6.84k
          if (profile == (StringInfo *) NULL)
869
0
            {
870
0
              count=(ssize_t) SeekBlob(image,(MagickOffsetType) length,SEEK_CUR);
871
0
              if (count != (ssize_t) length)
872
0
                break;
873
0
            }
874
6.84k
          else
875
6.84k
            {
876
6.84k
              count=ReadBlob(image,length,GetStringInfoDatum(profile));
877
6.84k
              if (count != (ssize_t) length)
878
40
                {
879
40
                  profile=DestroyStringInfo(profile);
880
40
                  break;
881
40
                }
882
6.80k
              status=SetImageProfilePrivate(image,profile,exception);
883
6.80k
            }
884
6.80k
          if (status == MagickFalse)
885
0
            break;
886
6.80k
          name=(const char *) GetNextValueInLinkedList(profiles);
887
6.80k
        }
888
631
        profiles=DestroyLinkedList(profiles,RelinquishMagickMemory);
889
631
      }
890
1.22k
    depth=GetImageQuantumDepth(image,MagickFalse);
891
1.22k
    if (image->storage_class == PseudoClass)
892
160
      {
893
160
        const unsigned char
894
160
          *p;
895
896
160
        size_t
897
160
          packet_size;
898
899
160
        unsigned char
900
160
          *colormap;
901
902
        /*
903
          Create image colormap.
904
        */
905
160
        packet_size=(size_t) (3UL*depth/8UL);
906
160
        if ((MagickSizeType) (packet_size*image->colors) > GetBlobSize(image))
907
102
          ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
908
58
        image->colormap=(PixelInfo *) AcquireQuantumMemory(image->colors+1,
909
58
          sizeof(*image->colormap));
910
58
        if (image->colormap == (PixelInfo *) NULL)
911
54
          ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
912
54
        if (image->colors != 0)
913
49
          {
914
            /*
915
              Read image colormap from file.
916
            */
917
49
            colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
918
49
              packet_size*sizeof(*colormap));
919
49
            if (colormap == (unsigned char *) NULL)
920
49
              ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
921
49
            count=ReadBlob(image,packet_size*image->colors,colormap);
922
49
            if (count != (ssize_t) (packet_size*image->colors))
923
14
              {
924
14
                colormap=(unsigned char *) RelinquishMagickMemory(colormap);
925
14
                ThrowReaderException(CorruptImageError,
926
14
                  "InsufficientImageDataInFile");
927
0
              }
928
35
            p=colormap;
929
35
            switch (depth)
930
35
            {
931
1
              default:
932
1
                colormap=(unsigned char *) RelinquishMagickMemory(colormap);
933
1
                ThrowReaderException(CorruptImageError,
934
0
                  "ImageDepthNotSupported");
935
13
              case 8:
936
13
              {
937
13
                unsigned char
938
13
                  pixel;
939
940
4.05k
                for (i=0; i < (ssize_t) image->colors; i++)
941
4.03k
                {
942
4.03k
                  p=PushCharPixel(p,&pixel);
943
4.03k
                  image->colormap[i].red=(MagickRealType)
944
4.03k
                    ScaleCharToQuantum(pixel);
945
4.03k
                  p=PushCharPixel(p,&pixel);
946
4.03k
                  image->colormap[i].green=(MagickRealType)
947
4.03k
                    ScaleCharToQuantum(pixel);
948
4.03k
                  p=PushCharPixel(p,&pixel);
949
4.03k
                  image->colormap[i].blue=(MagickRealType)
950
4.03k
                    ScaleCharToQuantum(pixel);
951
4.03k
                }
952
13
                break;
953
0
              }
954
12
              case 16:
955
12
              {
956
12
                unsigned short
957
12
                  pixel;
958
959
2.38k
                for (i=0; i < (ssize_t) image->colors; i++)
960
2.37k
                {
961
2.37k
                  p=PushShortPixel(MSBEndian,p,&pixel);
962
2.37k
                  image->colormap[i].red=(MagickRealType)
963
2.37k
                    ScaleShortToQuantum(pixel);
964
2.37k
                  p=PushShortPixel(MSBEndian,p,&pixel);
965
2.37k
                  image->colormap[i].green=(MagickRealType)
966
2.37k
                    ScaleShortToQuantum(pixel);
967
2.37k
                  p=PushShortPixel(MSBEndian,p,&pixel);
968
2.37k
                  image->colormap[i].blue=(MagickRealType)
969
2.37k
                    ScaleShortToQuantum(pixel);
970
2.37k
                }
971
12
                break;
972
0
              }
973
9
              case 32:
974
9
              {
975
9
                unsigned int
976
9
                  pixel;
977
978
212
                for (i=0; i < (ssize_t) image->colors; i++)
979
203
                {
980
203
                  p=PushLongPixel(MSBEndian,p,&pixel);
981
203
                  image->colormap[i].red=(MagickRealType)
982
203
                    ScaleLongToQuantum(pixel);
983
203
                  p=PushLongPixel(MSBEndian,p,&pixel);
984
203
                  image->colormap[i].green=(MagickRealType)
985
203
                    ScaleLongToQuantum(pixel);
986
203
                  p=PushLongPixel(MSBEndian,p,&pixel);
987
203
                  image->colormap[i].blue=(MagickRealType)
988
203
                    ScaleLongToQuantum(pixel);
989
203
                }
990
9
                break;
991
0
              }
992
35
            }
993
34
            colormap=(unsigned char *) RelinquishMagickMemory(colormap);
994
34
          }
995
54
      }
996
1.10k
    if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
997
0
      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
998
0
        break;
999
1.10k
    if ((AcquireMagickResource(WidthResource,image->columns) == MagickFalse) ||
1000
1.10k
        (AcquireMagickResource(HeightResource,image->rows) == MagickFalse))
1001
900
      ThrowReaderException(ImageError,"WidthOrHeightExceedsLimit");
1002
    /*
1003
      Attach persistent pixel cache.
1004
    */
1005
900
    status=PersistPixelCache(image,cache_filename,MagickTrue,&offset,exception);
1006
900
    if (status == MagickFalse)
1007
900
      {
1008
900
        status=SetImageExtent(image,image->columns,image->rows,exception);
1009
900
        ThrowReaderException(CacheError,"UnableToPersistPixelCache");
1010
0
      }
1011
0
    if (EOFBlob(image) != MagickFalse)
1012
0
      {
1013
0
        ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
1014
0
          image->filename);
1015
0
        break;
1016
0
      }
1017
    /*
1018
      Proceed to next image.
1019
    */
1020
0
    do
1021
0
    {
1022
0
      c=ReadBlobByte(image);
1023
0
    } while ((isgraph((int) ((unsigned char) c)) == 0) && (c != EOF));
1024
0
    if ((c != EOF) && ((c == 'i') || (c == 'I')))
1025
0
      {
1026
        /*
1027
          Allocate next image structure.
1028
        */
1029
0
        AcquireNextImage(image_info,image,exception);
1030
0
        if (GetNextImageInList(image) == (Image *) NULL)
1031
0
          {
1032
0
            status=MagickFalse;
1033
0
            break;
1034
0
          }
1035
0
        image=SyncNextImageInList(image);
1036
0
        status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
1037
0
          GetBlobSize(image));
1038
0
        if (status == MagickFalse)
1039
0
          break;
1040
0
      }
1041
0
  } while ((c != EOF) && ((c == 'i') || (c == 'I')));
1042
0
  if (CloseBlob(image) == MagickFalse)
1043
0
    status=MagickFalse;
1044
0
  if (status == MagickFalse)
1045
0
    return(DestroyImageList(image));
1046
0
  return(GetFirstImageInList(image));
1047
0
}
1048

1049
/*
1050
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1051
%                                                                             %
1052
%                                                                             %
1053
%                                                                             %
1054
%   R e g i s t e r M P C I m a g e                                           %
1055
%                                                                             %
1056
%                                                                             %
1057
%                                                                             %
1058
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1059
%
1060
%  RegisterMPCImage() adds properties for the Cache image format to
1061
%  the list of supported formats.  The properties include the image format
1062
%  tag, a method to read and/or write the format, whether the format
1063
%  supports the saving of more than one frame to the same file or blob,
1064
%  whether the format supports native in-memory I/O, and a brief
1065
%  description of the format.
1066
%
1067
%  The format of the RegisterMPCImage method is:
1068
%
1069
%      size_t RegisterMPCImage(void)
1070
%
1071
*/
1072
ModuleExport size_t RegisterMPCImage(void)
1073
10
{
1074
10
  MagickInfo
1075
10
    *entry;
1076
1077
10
  entry=AcquireMagickInfo("MPC","CACHE","Magick Pixel Cache image format");
1078
10
  entry->flags|=CoderStealthFlag;
1079
10
  (void) RegisterMagickInfo(entry);
1080
10
  entry=AcquireMagickInfo("MPC","MPC","Magick Pixel Cache image format");
1081
10
  entry->decoder=(DecodeImageHandler *) ReadMPCImage;
1082
10
  entry->encoder=(EncodeImageHandler *) WriteMPCImage;
1083
10
  entry->magick=(IsImageFormatHandler *) IsMPC;
1084
10
  entry->flags|=CoderDecoderSeekableStreamFlag;
1085
10
  (void) RegisterMagickInfo(entry);
1086
10
  return(MagickImageCoderSignature);
1087
10
}
1088

1089
/*
1090
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1091
%                                                                             %
1092
%                                                                             %
1093
%                                                                             %
1094
%   U n r e g i s t e r M P C I m a g e                                       %
1095
%                                                                             %
1096
%                                                                             %
1097
%                                                                             %
1098
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1099
%
1100
%  UnregisterMPCImage() removes format registrations made by the
1101
%  MPC module from the list of supported formats.
1102
%
1103
%  The format of the UnregisterMPCImage method is:
1104
%
1105
%      UnregisterMPCImage(void)
1106
%
1107
*/
1108
ModuleExport void UnregisterMPCImage(void)
1109
0
{
1110
0
  (void) UnregisterMagickInfo("CACHE");
1111
0
  (void) UnregisterMagickInfo("MPC");
1112
0
}
1113

1114
/*
1115
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1116
%                                                                             %
1117
%                                                                             %
1118
%                                                                             %
1119
%   W r i t e M P C I m a g e                                                 %
1120
%                                                                             %
1121
%                                                                             %
1122
%                                                                             %
1123
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1124
%
1125
%  WriteMPCImage() writes an Magick Pixel Cache image to a file.
1126
%
1127
%  The format of the WriteMPCImage method is:
1128
%
1129
%      MagickBooleanType WriteMPCImage(const ImageInfo *image_info,
1130
%        Image *image,ExceptionInfo *exception)
1131
%
1132
%  A description of each parameter follows:
1133
%
1134
%    o image_info: the image info.
1135
%
1136
%    o image: the image.
1137
%
1138
%    o exception: return any errors or warnings in this structure.
1139
%
1140
*/
1141
static MagickBooleanType WriteMPCImage(const ImageInfo *image_info,Image *image,
1142
  ExceptionInfo *exception)
1143
0
{
1144
0
  char
1145
0
    buffer[MagickPathExtent],
1146
0
    cache_filename[MagickPathExtent];
1147
1148
0
  const char
1149
0
    *property,
1150
0
    *value;
1151
1152
0
  MagickBooleanType
1153
0
    status;
1154
1155
0
  MagickOffsetType
1156
0
    offset,
1157
0
    scene;
1158
1159
0
  size_t
1160
0
    depth,
1161
0
    number_scenes;
1162
1163
0
  ssize_t
1164
0
    i;
1165
1166
  /*
1167
    Open persistent cache.
1168
  */
1169
0
  assert(image_info != (const ImageInfo *) NULL);
1170
0
  assert(image_info->signature == MagickCoreSignature);
1171
0
  assert(image != (Image *) NULL);
1172
0
  assert(image->signature == MagickCoreSignature);
1173
0
  assert(exception != (ExceptionInfo *) NULL);
1174
0
  assert(exception->signature == MagickCoreSignature);
1175
0
  if (IsEventLogging() != MagickFalse)
1176
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1177
0
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1178
0
  if (status == MagickFalse)
1179
0
    return(status);
1180
0
  (void) CopyMagickString(cache_filename,image->filename,MagickPathExtent-6);
1181
0
  AppendImageFormat("cache",cache_filename);
1182
0
  scene=0;
1183
0
  offset=0;
1184
0
  number_scenes=GetImageListLength(image);
1185
0
  do
1186
0
  {
1187
0
    StringInfo
1188
0
      *nonce;
1189
1190
    /*
1191
      Write cache meta-information.
1192
1193
      SetImageStorageClass() required to sync pixel cache.
1194
    */
1195
0
    (void) SetImageStorageClass(image,image->storage_class,exception);
1196
0
    depth=GetImageQuantumDepth(image,MagickTrue);
1197
0
    if ((image->storage_class == PseudoClass) &&
1198
0
        (image->colors > (size_t) (GetQuantumRange(image->depth)+1)))
1199
0
      (void) SetImageStorageClass(image,DirectClass,exception);
1200
0
    (void) WriteBlobString(image,"id=MagickPixelCache\n");
1201
0
    nonce=StringToStringInfo(MagickPixelCacheNonce);
1202
0
    (void) FormatLocaleString(buffer,MagickPathExtent,"magick-signature=%u\n",
1203
0
      GetMagickSignature(nonce));
1204
0
    nonce=DestroyStringInfo(nonce);
1205
0
    (void) WriteBlobString(image,buffer);
1206
0
    (void) FormatLocaleString(buffer,MagickPathExtent,
1207
0
      "class=%s colors=%.20g alpha-trait=%s\n",CommandOptionToMnemonic(
1208
0
      MagickClassOptions,image->storage_class),(double) image->colors,
1209
0
      CommandOptionToMnemonic(MagickPixelTraitOptions,(ssize_t)
1210
0
      image->alpha_trait));
1211
0
    (void) WriteBlobString(image,buffer);
1212
0
    (void) FormatLocaleString(buffer,MagickPathExtent,"number-channels=%.20g "
1213
0
      "number-meta-channels=%.20g channel-mask=0x%016llx\n",
1214
0
      (double) image->number_channels,(double) image->number_meta_channels,
1215
0
      (MagickOffsetType) image->channel_mask);
1216
0
    (void) WriteBlobString(image,buffer);
1217
0
    (void) FormatLocaleString(buffer,MagickPathExtent,
1218
0
      "columns=%.20g rows=%.20g depth=%.20g\n",(double) image->columns,
1219
0
      (double) image->rows,(double) image->depth);
1220
0
    (void) WriteBlobString(image,buffer);
1221
0
    if (image->type != UndefinedType)
1222
0
      {
1223
0
        (void) FormatLocaleString(buffer,MagickPathExtent,"type=%s\n",
1224
0
          CommandOptionToMnemonic(MagickTypeOptions,image->type));
1225
0
        (void) WriteBlobString(image,buffer);
1226
0
      }
1227
0
    (void) FormatLocaleString(buffer,MagickPathExtent,"colorspace=%s\n",
1228
0
      CommandOptionToMnemonic(MagickColorspaceOptions,image->colorspace));
1229
0
    (void) WriteBlobString(image,buffer);
1230
0
    if (image->intensity != UndefinedPixelIntensityMethod)
1231
0
      {
1232
0
        (void) FormatLocaleString(buffer,MagickPathExtent,
1233
0
          "pixel-intensity=%s\n",CommandOptionToMnemonic(
1234
0
          MagickPixelIntensityOptions,image->intensity));
1235
0
        (void) WriteBlobString(image,buffer);
1236
0
      }
1237
0
    if (image->endian != UndefinedEndian)
1238
0
      {
1239
0
        (void) FormatLocaleString(buffer,MagickPathExtent,"endian=%s\n",
1240
0
          CommandOptionToMnemonic(MagickEndianOptions,image->endian));
1241
0
        (void) WriteBlobString(image,buffer);
1242
0
      }
1243
0
    if (image->compression != UndefinedCompression)
1244
0
      {
1245
0
        (void) FormatLocaleString(buffer,MagickPathExtent,
1246
0
          "compression=%s quality=%.20g\n",CommandOptionToMnemonic(
1247
0
          MagickCompressOptions,image->compression),(double) image->quality);
1248
0
        (void) WriteBlobString(image,buffer);
1249
0
      }
1250
0
    if (image->units != UndefinedResolution)
1251
0
      {
1252
0
        (void) FormatLocaleString(buffer,MagickPathExtent,"units=%s\n",
1253
0
          CommandOptionToMnemonic(MagickResolutionOptions,image->units));
1254
0
        (void) WriteBlobString(image,buffer);
1255
0
      }
1256
0
    if ((image->resolution.x != 0) || (image->resolution.y != 0))
1257
0
      {
1258
0
        (void) FormatLocaleString(buffer,MagickPathExtent,
1259
0
          "resolution=%gx%g\n",image->resolution.x,image->resolution.y);
1260
0
        (void) WriteBlobString(image,buffer);
1261
0
      }
1262
0
    if ((image->page.width != 0) || (image->page.height != 0))
1263
0
      {
1264
0
        (void) FormatLocaleString(buffer,MagickPathExtent,
1265
0
          "page=%.20gx%.20g%+.20g%+.20g\n",(double) image->page.width,(double)
1266
0
          image->page.height,(double) image->page.x,(double) image->page.y);
1267
0
        (void) WriteBlobString(image,buffer);
1268
0
      }
1269
0
    else
1270
0
      if ((image->page.x != 0) || (image->page.y != 0))
1271
0
        {
1272
0
          (void) FormatLocaleString(buffer,MagickPathExtent,"page=%+ld%+ld\n",
1273
0
            (long) image->page.x,(long) image->page.y);
1274
0
          (void) WriteBlobString(image,buffer);
1275
0
        }
1276
0
    if ((image->tile_offset.x != 0) || (image->tile_offset.y != 0))
1277
0
      {
1278
0
        (void) FormatLocaleString(buffer,MagickPathExtent,
1279
0
          "tile-offset=%+ld%+ld\n",(long) image->tile_offset.x,(long)
1280
0
           image->tile_offset.y);
1281
0
        (void) WriteBlobString(image,buffer);
1282
0
      }
1283
0
    if ((GetNextImageInList(image) != (Image *) NULL) ||
1284
0
        (GetPreviousImageInList(image) != (Image *) NULL))
1285
0
      {
1286
0
        if (image->scene == 0)
1287
0
          (void) FormatLocaleString(buffer,MagickPathExtent,
1288
0
            "iterations=%.20g delay=%.20g  ticks-per-second=%.20g\n",(double)
1289
0
            image->iterations,(double) image->delay,(double)
1290
0
            image->ticks_per_second);
1291
0
        else
1292
0
          (void) FormatLocaleString(buffer,MagickPathExtent,"scene=%.20g  "
1293
0
            "iterations=%.20g delay=%.20g  ticks-per-second=%.20g\n",
1294
0
            (double) image->scene,(double) image->iterations,(double)
1295
0
            image->delay,(double) image->ticks_per_second);
1296
0
        (void) WriteBlobString(image,buffer);
1297
0
      }
1298
0
    else
1299
0
      {
1300
0
        if (image->scene != 0)
1301
0
          {
1302
0
            (void) FormatLocaleString(buffer,MagickPathExtent,"scene=%.20g\n",
1303
0
              (double) image->scene);
1304
0
            (void) WriteBlobString(image,buffer);
1305
0
          }
1306
0
        if (image->iterations != 0)
1307
0
          {
1308
0
            (void) FormatLocaleString(buffer,MagickPathExtent,
1309
0
              "iterations=%.20g\n",(double) image->iterations);
1310
0
            (void) WriteBlobString(image,buffer);
1311
0
          }
1312
0
        if (image->delay != 0)
1313
0
          {
1314
0
            (void) FormatLocaleString(buffer,MagickPathExtent,"delay=%.20g\n",
1315
0
              (double) image->delay);
1316
0
            (void) WriteBlobString(image,buffer);
1317
0
          }
1318
0
        if (image->ticks_per_second != UndefinedTicksPerSecond)
1319
0
          {
1320
0
            (void) FormatLocaleString(buffer,MagickPathExtent,
1321
0
              "ticks-per-second=%.20g\n",(double) image->ticks_per_second);
1322
0
            (void) WriteBlobString(image,buffer);
1323
0
          }
1324
0
      }
1325
0
    if (image->gravity != UndefinedGravity)
1326
0
      {
1327
0
        (void) FormatLocaleString(buffer,MagickPathExtent,"gravity=%s\n",
1328
0
          CommandOptionToMnemonic(MagickGravityOptions,image->gravity));
1329
0
        (void) WriteBlobString(image,buffer);
1330
0
      }
1331
0
    if (image->dispose != UndefinedDispose)
1332
0
      {
1333
0
        (void) FormatLocaleString(buffer,MagickPathExtent,"dispose=%s\n",
1334
0
          CommandOptionToMnemonic(MagickDisposeOptions,image->dispose));
1335
0
        (void) WriteBlobString(image,buffer);
1336
0
      }
1337
0
    if (image->rendering_intent != UndefinedIntent)
1338
0
      {
1339
0
        (void) FormatLocaleString(buffer,MagickPathExtent,
1340
0
          "rendering-intent=%s\n",CommandOptionToMnemonic(MagickIntentOptions,
1341
0
          image->rendering_intent));
1342
0
        (void) WriteBlobString(image,buffer);
1343
0
      }
1344
0
    if (image->gamma != 0.0)
1345
0
      {
1346
0
        (void) FormatLocaleString(buffer,MagickPathExtent,"gamma=%g\n",
1347
0
          image->gamma);
1348
0
        (void) WriteBlobString(image,buffer);
1349
0
      }
1350
0
    if (image->chromaticity.white_point.x != 0.0)
1351
0
      {
1352
        /*
1353
          Note chromaticity points.
1354
        */
1355
0
        (void) FormatLocaleString(buffer,MagickPathExtent,"red-primary=%g,%g "
1356
0
          "green-primary=%g,%g blue-primary=%g,%g\n",
1357
0
          image->chromaticity.red_primary.x,image->chromaticity.red_primary.y,
1358
0
          image->chromaticity.green_primary.x,
1359
0
          image->chromaticity.green_primary.y,
1360
0
          image->chromaticity.blue_primary.x,
1361
0
          image->chromaticity.blue_primary.y);
1362
0
        (void) WriteBlobString(image,buffer);
1363
0
        (void) FormatLocaleString(buffer,MagickPathExtent,
1364
0
          "white-point=%g,%g\n",image->chromaticity.white_point.x,
1365
0
          image->chromaticity.white_point.y);
1366
0
        (void) WriteBlobString(image,buffer);
1367
0
      }
1368
0
    if (image->orientation != UndefinedOrientation)
1369
0
      {
1370
0
        (void) FormatLocaleString(buffer,MagickPathExtent,
1371
0
          "orientation=%s\n",CommandOptionToMnemonic(MagickOrientationOptions,
1372
0
          image->orientation));
1373
0
        (void) WriteBlobString(image,buffer);
1374
0
      }
1375
0
    if (image->profiles != (void *) NULL)
1376
0
      {
1377
0
        const char
1378
0
          *name;
1379
1380
0
        const StringInfo
1381
0
          *profile;
1382
1383
        /*
1384
          Write image profile names.
1385
        */
1386
0
        ResetImageProfileIterator(image);
1387
0
        for (name=GetNextImageProfile(image); name != (const char *) NULL; )
1388
0
        {
1389
0
          profile=GetImageProfile(image,name);
1390
0
          if (profile != (StringInfo *) NULL)
1391
0
            {
1392
0
              (void) FormatLocaleString(buffer,MagickPathExtent,"profile=%s\n",
1393
0
                name);
1394
0
              (void) WriteBlobString(image,buffer);
1395
0
            }
1396
0
          name=GetNextImageProfile(image);
1397
0
        }
1398
0
      }
1399
0
    if (image->montage != (char *) NULL)
1400
0
      {
1401
0
        (void) FormatLocaleString(buffer,MagickPathExtent,"montage=%s\n",
1402
0
          image->montage);
1403
0
        (void) WriteBlobString(image,buffer);
1404
0
      }
1405
0
    ResetImagePropertyIterator(image);
1406
0
    property=GetNextImageProperty(image);
1407
0
    while (property != (const char *) NULL)
1408
0
    {
1409
0
      (void) FormatLocaleString(buffer,MagickPathExtent,"%s=",property);
1410
0
      (void) WriteBlobString(image,buffer);
1411
0
      value=GetImageProperty(image,property,exception);
1412
0
      if (value != (const char *) NULL)
1413
0
        {
1414
0
          size_t
1415
0
            length;
1416
1417
0
          length=strlen(value);
1418
0
          for (i=0; i < (ssize_t) length; i++)
1419
0
            if (isspace((int) ((unsigned char) value[i])) != 0)
1420
0
              break;
1421
0
          if ((i == (ssize_t) length) && (i != 0))
1422
0
            (void) WriteBlob(image,length,(const unsigned char *) value);
1423
0
          else
1424
0
            {
1425
0
              (void) WriteBlobByte(image,'{');
1426
0
              if ((strchr(value,'{') == (char *) NULL) &&
1427
0
                  (strchr(value,'}') == (char *) NULL))
1428
0
                (void) WriteBlob(image,length,(const unsigned char *) value);
1429
0
              else
1430
0
                for (i=0; i < (ssize_t) length; i++)
1431
0
                {
1432
0
                  if ((value[i] == (int) '{') || (value[i] == (int) '}'))
1433
0
                    (void) WriteBlobByte(image,'\\');
1434
0
                  (void) WriteBlobByte(image,(unsigned char) value[i]);
1435
0
                }
1436
0
              (void) WriteBlobByte(image,'}');
1437
0
            }
1438
0
        }
1439
0
      (void) WriteBlobByte(image,'\n');
1440
0
      property=GetNextImageProperty(image);
1441
0
    }
1442
0
    (void) WriteBlobString(image,"\f\n:\032");
1443
0
    if (image->montage != (char *) NULL)
1444
0
      {
1445
        /*
1446
          Write montage tile directory.
1447
        */
1448
0
        if (image->directory != (char *) NULL)
1449
0
          (void) WriteBlobString(image,image->directory);
1450
0
        (void) WriteBlobByte(image,'\0');
1451
0
      }
1452
0
    if (image->profiles != 0)
1453
0
      {
1454
0
        const char
1455
0
          *name;
1456
1457
0
        const StringInfo
1458
0
          *profile;
1459
1460
        /*
1461
          Write image profile blobs.
1462
        */
1463
0
        ResetImageProfileIterator(image);
1464
0
        name=GetNextImageProfile(image);
1465
0
        while (name != (const char *) NULL)
1466
0
        {
1467
0
          profile=GetImageProfile(image,name);
1468
0
          (void) WriteBlobMSBLong(image,(unsigned int)
1469
0
            GetStringInfoLength(profile));
1470
0
          (void) WriteBlob(image,GetStringInfoLength(profile),
1471
0
            GetStringInfoDatum(profile));
1472
0
          name=GetNextImageProfile(image);
1473
0
        }
1474
0
      }
1475
0
    if (image->storage_class == PseudoClass)
1476
0
      {
1477
0
        size_t
1478
0
          packet_size;
1479
1480
0
        unsigned char
1481
0
          *colormap,
1482
0
          *q;
1483
1484
        /*
1485
          Allocate colormap.
1486
        */
1487
0
        packet_size=(size_t) (3UL*depth/8UL);
1488
0
        colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
1489
0
          packet_size*sizeof(*colormap));
1490
0
        if (colormap == (unsigned char *) NULL)
1491
0
          return(MagickFalse);
1492
        /*
1493
          Write colormap to file.
1494
        */
1495
0
        q=colormap;
1496
0
        for (i=0; i < (ssize_t) image->colors; i++)
1497
0
        {
1498
0
          switch (depth)
1499
0
          {
1500
0
            default:
1501
0
            {
1502
0
              colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1503
0
              ThrowWriterException(CorruptImageError,"ImageDepthNotSupported");
1504
0
              break;
1505
0
            }
1506
0
            case 32:
1507
0
            {
1508
0
              unsigned int
1509
0
                pixel;
1510
1511
0
              pixel=ScaleQuantumToLong(ClampToQuantum(image->colormap[i].red));
1512
0
              q=PopLongPixel(MSBEndian,pixel,q);
1513
0
              pixel=ScaleQuantumToLong(ClampToQuantum(
1514
0
                image->colormap[i].green));
1515
0
              q=PopLongPixel(MSBEndian,pixel,q);
1516
0
              pixel=ScaleQuantumToLong(ClampToQuantum(image->colormap[i].blue));
1517
0
              q=PopLongPixel(MSBEndian,pixel,q);
1518
0
              break;
1519
0
            }
1520
0
            case 16:
1521
0
            {
1522
0
              unsigned short
1523
0
                pixel;
1524
1525
0
              pixel=ScaleQuantumToShort(ClampToQuantum(image->colormap[i].red));
1526
0
              q=PopShortPixel(MSBEndian,pixel,q);
1527
0
              pixel=ScaleQuantumToShort(ClampToQuantum(
1528
0
                image->colormap[i].green));
1529
0
              q=PopShortPixel(MSBEndian,pixel,q);
1530
0
              pixel=ScaleQuantumToShort(ClampToQuantum(
1531
0
                image->colormap[i].blue));
1532
0
              q=PopShortPixel(MSBEndian,pixel,q);
1533
0
              break;
1534
0
            }
1535
0
            case 8:
1536
0
            {
1537
0
              unsigned char
1538
0
                pixel;
1539
1540
0
              pixel=(unsigned char) ScaleQuantumToChar(ClampToQuantum(
1541
0
                image->colormap[i].red));
1542
0
              q=PopCharPixel(pixel,q);
1543
0
              pixel=(unsigned char) ScaleQuantumToChar(ClampToQuantum(
1544
0
                image->colormap[i].green));
1545
0
              q=PopCharPixel(pixel,q);
1546
0
              pixel=(unsigned char) ScaleQuantumToChar(ClampToQuantum(
1547
0
                image->colormap[i].blue));
1548
0
              q=PopCharPixel(pixel,q);
1549
0
              break;
1550
0
            }
1551
0
          }
1552
0
        }
1553
0
        (void) WriteBlob(image,packet_size*image->colors,colormap);
1554
0
        colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1555
0
      }
1556
    /*
1557
      Initialize persistent pixel cache.
1558
    */
1559
0
    status=PersistPixelCache(image,cache_filename,MagickFalse,&offset,
1560
0
      exception);
1561
0
    if (status == MagickFalse)
1562
0
      ThrowWriterException(CacheError,"UnableToPersistPixelCache");
1563
0
    if (GetNextImageInList(image) == (Image *) NULL)
1564
0
      break;
1565
0
    image=SyncNextImageInList(image);
1566
0
    if (image->progress_monitor != (MagickProgressMonitor) NULL)
1567
0
      {
1568
0
        status=image->progress_monitor(SaveImagesTag,scene,
1569
0
          number_scenes,image->client_data);
1570
0
        if (status == MagickFalse)
1571
0
          break;
1572
0
      }
1573
0
    scene++;
1574
0
  } while (image_info->adjoin != MagickFalse);
1575
0
  if (CloseBlob(image) == MagickFalse)
1576
0
    status=MagickFalse;
1577
0
  return(status);
1578
0
}