~ubuntu-branches/ubuntu/intrepid/graphicsmagick/intrepid

« back to all changes in this revision

Viewing changes to coders/mpc.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Kobras
  • Date: 2006-05-06 16:28:08 UTC
  • Revision ID: james.westby@ubuntu.com-20060506162808-vt2ni3r5nytcszms
Tags: upstream-1.1.7
ImportĀ upstreamĀ versionĀ 1.1.7

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
% Copyright (C) 2003 GraphicsMagick Group
 
3
% Copyright (C) 2002 ImageMagick Studio
 
4
%
 
5
% This program is covered by multiple licenses, which are described in
 
6
% Copyright.txt. You should have received a copy of Copyright.txt with this
 
7
% package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
 
8
%
 
9
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
10
%                                                                             %
 
11
%                                                                             %
 
12
%                                                                             %
 
13
%                            M   M  PPPP    CCCC                              %
 
14
%                            MM MM  P   P  C                                  %
 
15
%                            M M M  PPPP   C                                  %
 
16
%                            M   M  P      C                                  %
 
17
%                            M   M  P       CCCC                              %
 
18
%                                                                             %
 
19
%                                                                             %
 
20
%              Read/Write Magick Persistant Cache Image Format.               %
 
21
%                                                                             %
 
22
%                                                                             %
 
23
%                              Software Design                                %
 
24
%                                John Cristy                                  %
 
25
%                                 March 2000                                  %
 
26
%                                                                             %
 
27
%                                                                             %
 
28
%                                                                             %
 
29
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
30
%
 
31
%
 
32
%
 
33
*/
 
34
 
 
35
/*
 
36
  Include declarations.
 
37
*/
 
38
#include "magick/studio.h"
 
39
#include "magick/attribute.h"
 
40
#include "magick/cache.h"
 
41
#include "magick/blob.h"
 
42
#include "magick/color.h"
 
43
#include "magick/magick.h"
 
44
#include "magick/monitor.h"
 
45
#include "magick/utility.h"
 
46
 
 
47
/*
 
48
  Forward declarations.
 
49
*/
 
50
static unsigned int
 
51
  WriteMPCImage(const ImageInfo *,Image *);
 
52
 
 
53
/*
 
54
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
55
%                                                                             %
 
56
%                                                                             %
 
57
%                                                                             %
 
58
%   I s M P C                                                                 %
 
59
%                                                                             %
 
60
%                                                                             %
 
61
%                                                                             %
 
62
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
63
%
 
64
%  Method IsMPC returns True if the image format type, identified by the
 
65
%  magick string, is an Magick Persistent Cache image.
 
66
%
 
67
%  The format of the IsMPC method is:
 
68
%
 
69
%      unsigned int IsMPC(const unsigned char *magick,const size_t length)
 
70
%
 
71
%  A description of each parameter follows:
 
72
%
 
73
%    o status:  Method IsMPC returns True if the image format type is MPC.
 
74
%
 
75
%    o magick: This string is generally the first few bytes of an image file
 
76
%      or blob.
 
77
%
 
78
%    o length: Specifies the length of the magick string.
 
79
%
 
80
%
 
81
*/
 
82
static unsigned int IsMPC(const unsigned char *magick,const size_t length)
 
83
{
 
84
  if (length < 14)
 
85
    return(False);
 
86
  if (LocaleNCompare((char *) magick,"id=MagickCache",14) == 0)
 
87
    return(True);
 
88
  return(False);
 
89
}
 
90
 
 
91
/*
 
92
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
93
%                                                                             %
 
94
%                                                                             %
 
95
%                                                                             %
 
96
%   R e a d C A C H E I m a g e                                               %
 
97
%                                                                             %
 
98
%                                                                             %
 
99
%                                                                             %
 
100
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
101
%
 
102
%  Method ReadMPCImage reads an Magick Persistent Cache image file and returns
 
103
%  it.  It allocates the memory necessary for the new Image structure and
 
104
%  returns a pointer to the new image.
 
105
%
 
106
%  The format of the ReadMPCImage method is:
 
107
%
 
108
%      Image *ReadMPCImage(const ImageInfo *image_info,ExceptionInfo *exception)
 
109
%
 
110
%  Decompression code contributed by Kyle Shorter.
 
111
%
 
112
%  A description of each parameter follows:
 
113
%
 
114
%    o image: Method ReadMPCImage returns a pointer to the image after
 
115
%      reading.  A null image is returned if there is a memory shortage or
 
116
%      if the image cannot be read.
 
117
%
 
118
%    o image_info: Specifies a pointer to a ImageInfo structure.
 
119
%
 
120
%    o exception: return any errors or warnings in this structure.
 
121
%
 
122
%
 
123
*/
 
124
static Image *ReadMPCImage(const ImageInfo *image_info,ExceptionInfo *exception)
 
125
{
 
126
  char
 
127
    cache_filename[MaxTextExtent],
 
128
    id[MaxTextExtent],
 
129
    keyword[MaxTextExtent],
 
130
    *values;
 
131
 
 
132
  ExtendedSignedIntegralType
 
133
    offset;
 
134
 
 
135
  Image
 
136
    *image;
 
137
 
 
138
  int
 
139
    c;
 
140
 
 
141
  register long
 
142
    i;
 
143
 
 
144
  register unsigned char
 
145
    *p;
 
146
 
 
147
  size_t
 
148
    length;
 
149
 
 
150
  unsigned int
 
151
    status;
 
152
 
 
153
  unsigned long
 
154
    quantum_depth;
 
155
 
 
156
  /*
 
157
    Open image file.
 
158
  */
 
159
  assert(image_info != (const ImageInfo *) NULL);
 
160
  assert(image_info->signature == MagickSignature);
 
161
  assert(exception != (ExceptionInfo *) NULL);
 
162
  assert(exception->signature == MagickSignature);
 
163
  image=AllocateImage(image_info);
 
164
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
 
165
  if (status == False)
 
166
    ThrowReaderException(FileOpenError,UnableToOpenFile,image);
 
167
  (void) strncpy(cache_filename,image->filename,MaxTextExtent-1);
 
168
  AppendImageFormat("cache",cache_filename);
 
169
  c=ReadBlobByte(image);
 
170
  if (c == EOF)
 
171
    {
 
172
      DestroyImage(image);
 
173
      return((Image *) NULL);
 
174
    }
 
175
  *id='\0';
 
176
  offset=0;
 
177
  do
 
178
  {
 
179
    /*
 
180
      Decode image header;  header terminates one character beyond a ':'.
 
181
    */
 
182
    length=MaxTextExtent;
 
183
    values=AllocateString((char *) NULL);
 
184
    quantum_depth=QuantumDepth;
 
185
    image->depth=8;
 
186
    image->compression=NoCompression;
 
187
    while (isgraph(c) && (c != ':'))
 
188
    {
 
189
      register char
 
190
        *p;
 
191
 
 
192
      if (c == '{')
 
193
        {
 
194
          char
 
195
            *comment;
 
196
 
 
197
          /*
 
198
            Read comment-- any text between { }.
 
199
          */
 
200
          length=MaxTextExtent;
 
201
          comment=AllocateString((char *) NULL);
 
202
          p=comment;
 
203
          for ( ; comment != (char *) NULL; p++)
 
204
          {
 
205
            c=ReadBlobByte(image);
 
206
            if ((c == EOF) || (c == '}'))
 
207
              break;
 
208
            if ((p-comment+1) >= length)
 
209
              {
 
210
                *p='\0';
 
211
                length<<=1;
 
212
                MagickReallocMemory(comment,length);
 
213
                if (comment == (char *) NULL)
 
214
                  break;
 
215
                p=comment+strlen(comment);
 
216
              }
 
217
            *p=c;
 
218
          }
 
219
          if (comment == (char *) NULL)
 
220
            ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
 
221
              image);
 
222
          *p='\0';
 
223
          (void) SetImageAttribute(image,"comment",comment);
 
224
          MagickFreeMemory(comment);
 
225
          c=ReadBlobByte(image);
 
226
        }
 
227
      else
 
228
        if (isalnum(c))
 
229
          {
 
230
            /*
 
231
              Determine a keyword and its value.
 
232
            */
 
233
            p=keyword;
 
234
            do
 
235
            {
 
236
              if ((p-keyword) < (MaxTextExtent-1))
 
237
                *p++=c;
 
238
              c=ReadBlobByte(image);
 
239
            } while (isalnum(c) || (c == '-'));
 
240
            *p='\0';
 
241
            while (isspace(c) || (c == '='))
 
242
              c=ReadBlobByte(image);
 
243
            p=values;
 
244
            while ((c != '}') && (c != EOF))
 
245
            {
 
246
              if ((p-values+1) >= (int) length)
 
247
                {
 
248
                  *p='\0';
 
249
                  length<<=1;
 
250
                  MagickReallocMemory(values,length);
 
251
                  if (values == (char *) NULL)
 
252
                    break;
 
253
                  p=values+strlen(values);
 
254
                }
 
255
              if (values == (char *) NULL)
 
256
                ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
 
257
              *p++=c;
 
258
              c=ReadBlobByte(image);
 
259
              if (*values != '{')
 
260
                if (isspace(c))
 
261
                  break;
 
262
            }
 
263
            *p='\0';
 
264
            /*
 
265
              Assign a value to the specified keyword.
 
266
            */
 
267
            switch (*keyword)
 
268
            {
 
269
              case 'b':
 
270
              case 'B':
 
271
              {
 
272
                if (LocaleCompare(keyword,"background-color") == 0)
 
273
                  {
 
274
                    (void) QueryColorDatabase(values,&image->background_color,
 
275
                      exception);
 
276
                    break;
 
277
                  }
 
278
                if (LocaleCompare(keyword,"blue-primary") == 0)
 
279
                  {
 
280
                    (void) sscanf(values,"%lf,%lf",
 
281
                      &image->chromaticity.blue_primary.x,
 
282
                      &image->chromaticity.blue_primary.y);
 
283
                    break;
 
284
                  }
 
285
                if (LocaleCompare(keyword,"border-color") == 0)
 
286
                  {
 
287
                    (void) QueryColorDatabase(values,&image->border_color,
 
288
                      exception);
 
289
                    break;
 
290
                  }
 
291
                (void) SetImageAttribute(image,keyword,
 
292
                  *values == '{' ? values+1 : values);
 
293
                break;
 
294
              }
 
295
              case 'c':
 
296
              case 'C':
 
297
              {
 
298
                if (LocaleCompare(keyword,"class") == 0)
 
299
                  {
 
300
                    image->storage_class=UndefinedClass;
 
301
                    if (LocaleCompare(values,"PseudoClass") == 0)
 
302
                      image->storage_class=PseudoClass;
 
303
                    else
 
304
                      if (LocaleCompare(values,"DirectClass") == 0)
 
305
                        image->storage_class=DirectClass;
 
306
                    break;
 
307
                  }
 
308
                if (LocaleCompare(keyword,"colors") == 0)
 
309
                  {
 
310
                    image->colors=atol(values);
 
311
                    break;
 
312
                  }
 
313
                if (LocaleCompare(keyword,"colorspace") == 0)
 
314
                  {
 
315
                    image->colorspace=UndefinedColorspace;
 
316
                    if (LocaleCompare(values,"CMYK") == 0)
 
317
                      image->colorspace=CMYKColorspace;
 
318
                    else
 
319
                      if (LocaleCompare(values,"RGB") == 0)
 
320
                        image->colorspace=RGBColorspace;
 
321
                    break;
 
322
                  }
 
323
                if (LocaleCompare(keyword,"compression") == 0)
 
324
                  {
 
325
                    CompressionType
 
326
                      compression;
 
327
 
 
328
                    compression=UndefinedCompression;
 
329
                    if (LocaleCompare("None",values) == 0)
 
330
                      compression=NoCompression;
 
331
                    if (LocaleCompare("BZip",values) == 0)
 
332
                      compression=BZipCompression;
 
333
                    if (LocaleCompare("Fax",values) == 0)
 
334
                      compression=FaxCompression;
 
335
                    if (LocaleCompare("Group4",values) == 0)
 
336
                      compression=Group4Compression;
 
337
                    if (LocaleCompare("JPEG",values) == 0)
 
338
                      compression=JPEGCompression;
 
339
                    if (LocaleCompare("Lossless",values) == 0)
 
340
                      compression=LosslessJPEGCompression;
 
341
                    if (LocaleCompare("LZW",values) == 0)
 
342
                      compression=LZWCompression;
 
343
                    if (LocaleCompare("RLE",values) == 0)
 
344
                      compression=RLECompression;
 
345
                    if (LocaleCompare("Zip",values) == 0)
 
346
                      compression=ZipCompression;
 
347
                    image->compression=compression;
 
348
                    break;
 
349
                  }
 
350
                if (LocaleCompare(keyword,"columns") == 0)
 
351
                  {
 
352
                    image->columns= atol(values);
 
353
                    break;
 
354
                  }
 
355
                (void) SetImageAttribute(image,keyword,
 
356
                  *values == '{' ? values+1 : values);
 
357
                break;
 
358
              }
 
359
              case 'd':
 
360
              case 'D':
 
361
              {
 
362
                if (LocaleCompare(keyword,"delay") == 0)
 
363
                  {
 
364
                    image->delay=atol(values);
 
365
                    break;
 
366
                  }
 
367
                if (LocaleCompare(keyword,"depth") == 0)
 
368
                  {
 
369
                    image->depth=atol(values);
 
370
                    break;
 
371
                  }
 
372
                if (LocaleCompare(keyword,"dispose") == 0)
 
373
                  {
 
374
                    image->dispose=(DisposeType) atol(values);
 
375
                    if (LocaleCompare(values,"Background") == 0)
 
376
                      image->dispose=BackgroundDispose;
 
377
                    else
 
378
                      if (LocaleCompare(values,"None") == 0)
 
379
                        image->dispose=NoneDispose;
 
380
                      else
 
381
                        if (LocaleCompare(values,"Previous") == 0)
 
382
                          image->dispose=PreviousDispose;
 
383
                    break;
 
384
                  }
 
385
                (void) SetImageAttribute(image,keyword,
 
386
                  *values == '{' ? values+1 : values);
 
387
                break;
 
388
              }
 
389
              case 'e':
 
390
              case 'E':
 
391
              {
 
392
                if (LocaleCompare(keyword,"error") == 0)
 
393
                  {
 
394
                    image->error.mean_error_per_pixel=atof(values);
 
395
                    break;
 
396
                  }
 
397
                (void) SetImageAttribute(image,keyword,
 
398
                  *values == '{' ? values+1 : values);
 
399
                break;
 
400
              }
 
401
              case 'g':
 
402
              case 'G':
 
403
              {
 
404
                if (LocaleCompare(keyword,"gamma") == 0)
 
405
                  {
 
406
                    image->gamma=atof(values);
 
407
                    break;
 
408
                  }
 
409
                if (LocaleCompare(keyword,"grayscale") == 0)
 
410
                  {
 
411
                    image->is_grayscale=(LocaleCompare(values,"True") == 0) ||
 
412
                      (LocaleCompare(values,"true") == 0);
 
413
                    break;
 
414
                  }
 
415
                if (LocaleCompare(keyword,"green-primary") == 0)
 
416
                  {
 
417
                    (void) sscanf(values,"%lf,%lf",
 
418
                      &image->chromaticity.green_primary.x,
 
419
                      &image->chromaticity.green_primary.y);
 
420
                    break;
 
421
                  }
 
422
                (void) SetImageAttribute(image,keyword,
 
423
                  *values == '{' ? values+1 : values);
 
424
                break;
 
425
              }
 
426
              case 'i':
 
427
              case 'I':
 
428
              {
 
429
                if (LocaleCompare(keyword,"id") == 0)
 
430
                  {
 
431
                    (void) strncpy(id,values,MaxTextExtent-1);
 
432
                    break;
 
433
                  }
 
434
                if (LocaleCompare(keyword,"iterations") == 0)
 
435
                  {
 
436
                    image->iterations=atol(values);
 
437
                    break;
 
438
                  }
 
439
                (void) SetImageAttribute(image,keyword,
 
440
                  *values == '{' ? values+1 : values);
 
441
                break;
 
442
              }
 
443
              case 'm':
 
444
              case 'M':
 
445
              {
 
446
                if (LocaleCompare(keyword,"matte") == 0)
 
447
                  {
 
448
                    image->matte=(LocaleCompare(values,"True") == 0) ||
 
449
                      (LocaleCompare(values,"true") == 0);
 
450
                    break;
 
451
                  }
 
452
                if (LocaleCompare(keyword,"matte-color") == 0)
 
453
                  {
 
454
                    (void) QueryColorDatabase(values,&image->matte_color,
 
455
                      exception);
 
456
                    break;
 
457
                  }
 
458
                if (LocaleCompare(keyword,"maximum-error") == 0)
 
459
                  {
 
460
                    image->error.normalized_maximum_error=atof(values);
 
461
                    break;
 
462
                  }
 
463
                if (LocaleCompare(keyword,"mean-error") == 0)
 
464
                  {
 
465
                    image->error.normalized_mean_error=atof(values);
 
466
                    break;
 
467
                  }
 
468
                if (LocaleCompare(keyword,"monochrome") == 0)
 
469
                  {
 
470
                    image->is_monochrome=(LocaleCompare(values,"True") == 0) ||
 
471
                      (LocaleCompare(values,"true") == 0);
 
472
                    break;
 
473
                  }
 
474
                if (LocaleCompare(keyword,"montage") == 0)
 
475
                  {
 
476
                    (void) CloneString(&image->montage,values);
 
477
                    break;
 
478
                  }
 
479
                (void) SetImageAttribute(image,keyword,
 
480
                  *values == '{' ? values+1 : values);
 
481
                break;
 
482
              }
 
483
              case 'p':
 
484
              case 'P':
 
485
              {
 
486
                if (LocaleCompare(keyword,"page") == 0)
 
487
                  {
 
488
                    char
 
489
                      *geometry;
 
490
 
 
491
                    geometry=GetPageGeometry(values);
 
492
                    (void) GetGeometry(geometry,&image->page.x,&image->page.y,
 
493
                      &image->page.width,&image->page.height);
 
494
                    MagickFreeMemory(geometry);
 
495
                    break;
 
496
                  }
 
497
                if (LocaleNCompare(keyword,"profile-",8) == 0)
 
498
                  {
 
499
                    if (LocaleCompare(keyword,"profile-icc") == 0)
 
500
                      {
 
501
                        image->color_profile.length=atol(values);
 
502
                        break;
 
503
                      }
 
504
                    if (LocaleCompare(keyword,"profile-iptc") == 0)
 
505
                      {
 
506
                        image->iptc_profile.length=atol(values);
 
507
                        break;
 
508
                      }
 
509
                    i=(long) image->generic_profiles;
 
510
                    if (image->generic_profile == (ProfileInfo *) NULL)
 
511
                      image->generic_profile=MagickAllocateMemory(ProfileInfo *,
 
512
                        sizeof(ProfileInfo));
 
513
                    else
 
514
                      MagickReallocMemory(image->generic_profile,
 
515
                        (i+1)*sizeof(ProfileInfo));
 
516
                    if (image->generic_profile == (ProfileInfo *) NULL)
 
517
                      ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
 
518
                    image->generic_profile[i].name=AllocateString(keyword+8);
 
519
                    image->generic_profile[i].length=atol(values);
 
520
                    image->generic_profile[i].info=(unsigned char *) NULL;
 
521
                    image->generic_profiles++;
 
522
                    break;
 
523
                  }
 
524
                (void) SetImageAttribute(image,keyword,
 
525
                  *values == '{' ? values+1 : values);
 
526
                break;
 
527
              }
 
528
              case 'o':
 
529
              case 'O':
 
530
              {
 
531
                if (LocaleCompare(keyword,"opaque") == 0)
 
532
                  {
 
533
                    image->matte=(LocaleCompare(values,"True") == 0) ||
 
534
                      (LocaleCompare(values,"true") == 0);
 
535
                    break;
 
536
                   }
 
537
                (void) SetImageAttribute(image,keyword,
 
538
                  *values == '{' ? values+1 : values);
 
539
                break;
 
540
              }
 
541
              case 'q':
 
542
              case 'Q':
 
543
              {
 
544
                if (LocaleCompare(keyword,"quantum-depth") == 0)
 
545
                  {
 
546
                    quantum_depth=atol(values);
 
547
                    break;
 
548
                  }
 
549
                (void) SetImageAttribute(image,keyword,
 
550
                  *values == '{' ? values+1 : values);
 
551
                break;
 
552
              }
 
553
              case 'r':
 
554
              case 'R':
 
555
              {
 
556
                if (LocaleCompare(keyword,"red-primary") == 0)
 
557
                  {
 
558
                    (void) sscanf(values,"%lf,%lf",
 
559
                      &image->chromaticity.red_primary.x,
 
560
                      &image->chromaticity.red_primary.y);
 
561
                    break;
 
562
                  }
 
563
                if (LocaleCompare(keyword,"rendering-intent") == 0)
 
564
                  {
 
565
                    image->rendering_intent=UndefinedIntent;
 
566
                    if (LocaleCompare(values,"Saturation") == 0)
 
567
                      image->rendering_intent=SaturationIntent;
 
568
                    else
 
569
                      if (LocaleCompare(values,"perceptual") == 0)
 
570
                        image->rendering_intent=PerceptualIntent;
 
571
                      else
 
572
                        if (LocaleCompare(values,"absolute") == 0)
 
573
                          image->rendering_intent=AbsoluteIntent;
 
574
                        else
 
575
                          if (LocaleCompare(values,"relative") == 0)
 
576
                            image->rendering_intent=RelativeIntent;
 
577
                    break;
 
578
                  }
 
579
                if (LocaleCompare(keyword,"resolution") == 0)
 
580
                  {
 
581
                    (void) GetMagickDimension(values,&image->x_resolution,
 
582
                      &image->y_resolution);
 
583
                    break;
 
584
                  }
 
585
                if (LocaleCompare(keyword,"rows") == 0)
 
586
                  {
 
587
                    image->rows=atol(values);
 
588
                    break;
 
589
                  }
 
590
                (void) SetImageAttribute(image,keyword,
 
591
                  *values == '{' ? values+1 : values);
 
592
                break;
 
593
              }
 
594
              case 's':
 
595
              case 'S':
 
596
              {
 
597
                if (LocaleCompare(keyword,"scene") == 0)
 
598
                  {
 
599
                    image->scene=atol(values);
 
600
                    break;
 
601
                  }
 
602
                (void) SetImageAttribute(image,keyword,
 
603
                  *values == '{' ? values+1 : values);
 
604
                break;
 
605
              }
 
606
              case 'u':
 
607
              case 'U':
 
608
              {
 
609
                if (LocaleCompare(keyword,"units") == 0)
 
610
                  {
 
611
                    image->units=UndefinedResolution;
 
612
                    if (LocaleCompare(values,"pixels-per-inch") == 0)
 
613
                      image->units=PixelsPerInchResolution;
 
614
                    else
 
615
                      if (LocaleCompare(values,"pixels-per-centimeter") == 0)
 
616
                        image->units=PixelsPerCentimeterResolution;
 
617
                    break;
 
618
                  }
 
619
                (void) SetImageAttribute(image,keyword,
 
620
                  *values == '{' ? values+1 : values);
 
621
                break;
 
622
              }
 
623
              case 'w':
 
624
              case 'W':
 
625
              {
 
626
                if (LocaleCompare(keyword,"white-point") == 0)
 
627
                  {
 
628
                    (void) sscanf(values,"%lf,%lf",
 
629
                      &image->chromaticity.white_point.x,
 
630
                      &image->chromaticity.white_point.y);
 
631
                    break;
 
632
                  }
 
633
                (void) SetImageAttribute(image,keyword,
 
634
                  *values == '{' ? values+1 : values);
 
635
                break;
 
636
              }
 
637
              default:
 
638
              {
 
639
                (void) SetImageAttribute(image,keyword,
 
640
                  *values == '{' ? values+1 : values);
 
641
                break;
 
642
              }
 
643
            }
 
644
          }
 
645
        else
 
646
          c=ReadBlobByte(image);
 
647
      while (isspace(c))
 
648
        c=ReadBlobByte(image);
 
649
    }
 
650
    MagickFreeMemory(values);
 
651
    (void) ReadBlobByte(image);
 
652
    /*
 
653
      Verify that required image information is defined.
 
654
    */
 
655
    if ((LocaleCompare(id,"MagickCache") != 0) ||
 
656
        (image->storage_class == UndefinedClass) ||
 
657
        (image->compression == UndefinedCompression) || (image->columns == 0) ||
 
658
        (image->rows == 0))
 
659
      ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
 
660
    if (quantum_depth != QuantumDepth)
 
661
      ThrowReaderException(CacheError,InconsistentPersistentCacheDepth,image);
 
662
    if (image->montage != (char *) NULL)
 
663
      {
 
664
        register char
 
665
          *p;
 
666
 
 
667
        /*
 
668
          Image directory.
 
669
        */
 
670
        image->directory=AllocateString((char *) NULL);
 
671
        if (image->directory == (char *) NULL)
 
672
          ThrowReaderException(CorruptImageError,UnableToReadImageData,image);
 
673
        p=image->directory;
 
674
        do
 
675
        {
 
676
          *p='\0';
 
677
          if (((strlen(image->directory)+1) % MaxTextExtent) == 0)
 
678
            {
 
679
              /*
 
680
                Allocate more memory for the image directory.
 
681
              */
 
682
              MagickReallocMemory(image->directory,
 
683
                (strlen(image->directory)+MaxTextExtent+1));
 
684
              if (image->directory == (char *) NULL)
 
685
                ThrowReaderException(CorruptImageError,UnableToReadImageData,
 
686
                  image);
 
687
              p=image->directory+strlen(image->directory);
 
688
            }
 
689
          c=ReadBlobByte(image);
 
690
          *p++=c;
 
691
        } while (c != '\0');
 
692
      }
 
693
    if (image->color_profile.length != 0)
 
694
      {
 
695
        /*
 
696
          Color profile.
 
697
        */
 
698
        image->color_profile.info=MagickAllocateMemory(unsigned char *,
 
699
          image->color_profile.length);
 
700
        if (image->color_profile.info == (unsigned char *) NULL)
 
701
          ThrowReaderException(CorruptImageError,UnableToReadColorProfile,
 
702
            image);
 
703
        (void) ReadBlob(image,image->color_profile.length,
 
704
          image->color_profile.info);
 
705
      }
 
706
    if (image->iptc_profile.length != 0)
 
707
      {
 
708
        /*
 
709
          IPTC profile.
 
710
        */
 
711
        image->iptc_profile.info=MagickAllocateMemory(unsigned char *,
 
712
          image->iptc_profile.length);
 
713
        if (image->iptc_profile.info == (unsigned char *) NULL)
 
714
          ThrowReaderException(CorruptImageError,UnableToReadIPTCProfile,
 
715
            image);
 
716
        (void) ReadBlob(image,image->iptc_profile.length,
 
717
          image->iptc_profile.info);
 
718
      }
 
719
    if (image->generic_profiles != 0)
 
720
      {
 
721
        /*
 
722
          Generic profile.
 
723
        */
 
724
        for (i=0; i < (long) image->generic_profiles; i++)
 
725
        {
 
726
          if (image->generic_profile[i].length == 0)
 
727
            continue;
 
728
          image->generic_profile[i].info=MagickAllocateMemory(unsigned char *,
 
729
            image->generic_profile[i].length);
 
730
          if (image->generic_profile[i].info == (unsigned char *) NULL)
 
731
            ThrowReaderException(CorruptImageError,UnableToReadGenericProfile,
 
732
              image);
 
733
          (void) ReadBlob(image,image->generic_profile[i].length,
 
734
            image->generic_profile[i].info);
 
735
        }
 
736
      }
 
737
    if (image->storage_class == PseudoClass)
 
738
      {
 
739
        /*
 
740
          Create image colormap.
 
741
        */
 
742
        if (!AllocateImageColormap(image,image->colors))
 
743
          ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
 
744
            image);
 
745
        if (image->colors == 0)
 
746
          for (i=0; i < 256; i++)
 
747
          {
 
748
            image->colormap[i].red=ScaleCharToQuantum(i);
 
749
            image->colormap[i].green=ScaleCharToQuantum(i);
 
750
            image->colormap[i].blue=ScaleCharToQuantum(i);
 
751
            image->colors++;
 
752
          }
 
753
        else
 
754
          {
 
755
            unsigned char
 
756
              *colormap;
 
757
 
 
758
            unsigned int
 
759
              packet_size;
 
760
 
 
761
            /*
 
762
              Read image colormap from file.
 
763
            */
 
764
            packet_size=image->depth > 8 ? 6 : 3;
 
765
            colormap=MagickAllocateMemory(unsigned char *,packet_size*image->colors);
 
766
            if (colormap == (unsigned char *) NULL)
 
767
              ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
 
768
                image);
 
769
            (void) ReadBlob(image,packet_size*image->colors,colormap);
 
770
            p=colormap;
 
771
            if (image->depth <= 8)
 
772
              for (i=0; i < (long) image->colors; i++)
 
773
              {
 
774
                image->colormap[i].red=ScaleCharToQuantum(*p++);
 
775
                image->colormap[i].green=ScaleCharToQuantum(*p++);
 
776
                image->colormap[i].blue=ScaleCharToQuantum(*p++);
 
777
              }
 
778
            else
 
779
              for (i=0; i < (long) image->colors; i++)
 
780
              {
 
781
                image->colormap[i].red=(*p++ << 8);
 
782
                image->colormap[i].red|=(*p++);
 
783
                image->colormap[i].green=(*p++ << 8);
 
784
                image->colormap[i].green|=(*p++);
 
785
                image->colormap[i].blue=(*p++ << 8);
 
786
                image->colormap[i].blue|=(*p++);
 
787
              }
 
788
            MagickFreeMemory(colormap);
 
789
          }
 
790
      }
 
791
    if (EOFBlob(image))
 
792
      {
 
793
        ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,
 
794
          image->filename);
 
795
        break;
 
796
      }
 
797
    if (image_info->ping && (image_info->subrange != 0))
 
798
      if (image->scene >= (image_info->subimage+image_info->subrange-1))
 
799
        break;
 
800
    /*
 
801
      Attach persistent pixel cache.
 
802
    */
 
803
    status=PersistCache(image,cache_filename,True,&offset,exception);
 
804
    if (status == False)
 
805
      ThrowReaderException(CacheError,UnableToPeristPixelCache,image);
 
806
    /*
 
807
      Proceed to next image.
 
808
    */
 
809
    do
 
810
    {
 
811
      c=ReadBlobByte(image);
 
812
    } while (!isgraph(c) && (c != EOF));
 
813
    if (c != EOF)
 
814
      {
 
815
        /*
 
816
          Allocate next image structure.
 
817
        */
 
818
        AllocateNextImage(image_info,image);
 
819
        if (image->next == (Image *) NULL)
 
820
          {
 
821
            DestroyImageList(image);
 
822
            return((Image *) NULL);
 
823
          }
 
824
        image=SyncNextImageInList(image);
 
825
        status=MagickMonitor(LoadImagesText,TellBlob(image),GetBlobSize(image),
 
826
          exception);
 
827
        if (status == False)
 
828
          break;
 
829
      }
 
830
  } while (c != EOF);
 
831
  while (image->previous != (Image *) NULL)
 
832
    image=image->previous;
 
833
  CloseBlob(image);
 
834
  return(image);
 
835
}
 
836
 
 
837
/*
 
838
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
839
%                                                                             %
 
840
%                                                                             %
 
841
%                                                                             %
 
842
%   R e g i s t e r M P C I m a g e                                           %
 
843
%                                                                             %
 
844
%                                                                             %
 
845
%                                                                             %
 
846
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
847
%
 
848
%  Method RegisterMPCImage adds attributes for the Cache image format to
 
849
%  the list of supported formats.  The attributes include the image format
 
850
%  tag, a method to read and/or write the format, whether the format
 
851
%  supports the saving of more than one frame to the same file or blob,
 
852
%  whether the format supports native in-memory I/O, and a brief
 
853
%  description of the format.
 
854
%
 
855
%  The format of the RegisterMPCImage method is:
 
856
%
 
857
%      RegisterMPCImage(void)
 
858
%
 
859
*/
 
860
ModuleExport void RegisterMPCImage(void)
 
861
{
 
862
  MagickInfo
 
863
    *entry;
 
864
 
 
865
  entry=SetMagickInfo("CACHE");
 
866
  entry->description=AcquireString("Magick Persistent Cache image format");
 
867
  entry->module=AcquireString("CACHE");
 
868
  (void) RegisterMagickInfo(entry);
 
869
  entry=SetMagickInfo("MPC");
 
870
  entry->decoder=(DecoderHandler) ReadMPCImage;
 
871
  entry->encoder=(EncoderHandler) WriteMPCImage;
 
872
  entry->magick=(MagickHandler) IsMPC;
 
873
  entry->description=AcquireString("Magick Persistent Cache image format");
 
874
  entry->module=AcquireString("MPC");
 
875
  (void) RegisterMagickInfo(entry);
 
876
}
 
877
 
 
878
/*
 
879
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
880
%                                                                             %
 
881
%                                                                             %
 
882
%                                                                             %
 
883
%   U n r e g i s t e r M P C I m a g e                                       %
 
884
%                                                                             %
 
885
%                                                                             %
 
886
%                                                                             %
 
887
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
888
%
 
889
%  Method UnregisterMPCImage removes format registrations made by the
 
890
%  MPC module from the list of supported formats.
 
891
%
 
892
%  The format of the UnregisterMPCImage method is:
 
893
%
 
894
%      UnregisterMPCImage(void)
 
895
%
 
896
*/
 
897
ModuleExport void UnregisterMPCImage(void)
 
898
{
 
899
  (void) UnregisterMagickInfo("CACHE");
 
900
  (void) UnregisterMagickInfo("MPC");
 
901
}
 
902
 
 
903
/*
 
904
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
905
%                                                                             %
 
906
%                                                                             %
 
907
%                                                                             %
 
908
%   W r i t e M P C I m a g e                                                 %
 
909
%                                                                             %
 
910
%                                                                             %
 
911
%                                                                             %
 
912
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
913
%
 
914
%  Method WriteMPCImage writes an Magick Persistent Cache image to a file.
 
915
%
 
916
%  The format of the WriteMPCImage method is:
 
917
%
 
918
%      unsigned int WriteMPCImage(const ImageInfo *image_info,Image *image)
 
919
%
 
920
%  A description of each parameter follows:
 
921
%
 
922
%    o status: Method WriteMPCImage return True if the image is written.
 
923
%      False is returned if there is a memory shortage or if the image file
 
924
%      fails to write.
 
925
%
 
926
%    o image_info: Specifies a pointer to a ImageInfo structure.
 
927
%
 
928
%    o image: A pointer to an Image structure.
 
929
%
 
930
%
 
931
*/
 
932
static unsigned int WriteMPCImage(const ImageInfo *image_info,Image *image)
 
933
{
 
934
  char
 
935
    buffer[MaxTextExtent],
 
936
    cache_filename[MaxTextExtent];
 
937
 
 
938
  const ImageAttribute
 
939
    *attribute;
 
940
 
 
941
  ExtendedSignedIntegralType
 
942
    offset;
 
943
 
 
944
  register long
 
945
    i;
 
946
 
 
947
  unsigned int
 
948
    status;
 
949
 
 
950
  unsigned long
 
951
    scene;
 
952
 
 
953
  /*
 
954
    Open persistent cache.
 
955
  */
 
956
  assert(image_info != (const ImageInfo *) NULL);
 
957
  assert(image_info->signature == MagickSignature);
 
958
  assert(image != (Image *) NULL);
 
959
  assert(image->signature == MagickSignature);
 
960
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
 
961
  if (status == False)
 
962
    ThrowWriterException(FileOpenError,UnableToOpenFile,image);
 
963
  (void) strncpy(cache_filename,image->filename,MaxTextExtent-1);
 
964
  AppendImageFormat("cache",cache_filename);
 
965
  scene=0;
 
966
  offset=0;
 
967
  do
 
968
  {
 
969
    /*
 
970
      Write persistent cache meta-information.
 
971
    */
 
972
    (void) WriteBlobString(image,"id=MagickCache\n");
 
973
    FormatString(buffer,"quantum-depth=%d\n",QuantumDepth);
 
974
    (void) WriteBlobString(image,buffer);
 
975
    if (image->storage_class == PseudoClass)
 
976
      FormatString(buffer,"class=PseudoClass  colors=%lu  matte=%s\n",
 
977
        image->colors,image->matte ? "True" : "False");
 
978
    else
 
979
      if (image->colorspace == CMYKColorspace)
 
980
        FormatString(buffer,"class=DirectClass  colorspace=CMYK  matte=%s\n",
 
981
          image->matte ? "True" : "False");
 
982
      else
 
983
        FormatString(buffer,"class=DirectClass  matte=%s\n",
 
984
          image->matte ? "True" : "False");
 
985
    (void) WriteBlobString(image,buffer);
 
986
    switch (image->compression)
 
987
    {
 
988
      default:
 
989
      case NoCompression:
 
990
      {
 
991
        (void) WriteBlobString(image,"compression=None\n");
 
992
        break;
 
993
      }
 
994
      case BZipCompression:
 
995
      {
 
996
        (void) WriteBlobString(image,"compression=BZip\n");
 
997
        break;
 
998
      }
 
999
      case FaxCompression:
 
1000
      {
 
1001
        (void) WriteBlobString(image,"compression=Fax\n");
 
1002
        break;
 
1003
      }
 
1004
      case Group4Compression:
 
1005
      {
 
1006
        (void) WriteBlobString(image,"compression=Group4\n");
 
1007
        break;
 
1008
      }
 
1009
      case JPEGCompression:
 
1010
      {
 
1011
        (void) WriteBlobString(image,"compression=JPEG\n");
 
1012
        break;
 
1013
      }
 
1014
      case LosslessJPEGCompression:
 
1015
      {
 
1016
        (void) WriteBlobString(image,"compression=Lossless\n");
 
1017
        break;
 
1018
      }
 
1019
      case LZWCompression:
 
1020
      {
 
1021
        (void) WriteBlobString(image,"compression=LZW\n");
 
1022
        break;
 
1023
      }
 
1024
      case RLECompression:
 
1025
      {
 
1026
        (void) WriteBlobString(image,"compression=RLE\n");
 
1027
        break;
 
1028
      }
 
1029
      case ZipCompression:
 
1030
      {
 
1031
        (void) WriteBlobString(image,"compression=Zip\n");
 
1032
        break;
 
1033
      }
 
1034
    }
 
1035
    FormatString(buffer,"columns=%lu  rows=%lu  depth=%lu\n",image->columns,
 
1036
      image->rows,image->depth);
 
1037
    (void) WriteBlobString(image,buffer);
 
1038
    if (image->is_monochrome != MagickFalse)
 
1039
      {
 
1040
        FormatString(buffer,"monochrome=True\n");
 
1041
        (void) WriteBlobString(image,buffer);
 
1042
      }
 
1043
    if (image->is_grayscale != MagickFalse)
 
1044
      {
 
1045
        FormatString(buffer,"grayscale=True\n");
 
1046
        (void) WriteBlobString(image,buffer);
 
1047
      }
 
1048
    if ((image->x_resolution != 0) && (image->y_resolution != 0))
 
1049
      {
 
1050
        char
 
1051
          units[MaxTextExtent];
 
1052
 
 
1053
        /*
 
1054
          Set image resolution.
 
1055
        */
 
1056
        (void) strcpy(units,"undefined");
 
1057
        if (image->units == PixelsPerInchResolution)
 
1058
          (void) strcpy(units,"pixels-per-inch");
 
1059
        if (image->units == PixelsPerCentimeterResolution)
 
1060
          (void) strcpy(units,"pixels-per-centimeter");
 
1061
        FormatString(buffer,"Resolution=%gx%g  units=%.1024s\n",
 
1062
          image->x_resolution,image->y_resolution,units);
 
1063
        (void) WriteBlobString(image,buffer);
 
1064
      }
 
1065
    if ((image->page.width != 0) && (image->page.height != 0))
 
1066
      {
 
1067
        FormatString(buffer,"page=%lux%lu%+ld%+ld\n",image->page.width,
 
1068
          image->page.height,image->page.x,image->page.y);
 
1069
        (void) WriteBlobString(image,buffer);
 
1070
      }
 
1071
    if ((image->next != (Image *) NULL) || (image->previous != (Image *) NULL))
 
1072
      {
 
1073
        if (image->scene == 0)
 
1074
          FormatString(buffer,"iterations=%lu  delay=%lu\n",image->iterations,
 
1075
            image->delay);
 
1076
        else
 
1077
          FormatString(buffer,"scene=%lu  iterations=%lu  delay=%lu\n",
 
1078
            image->scene,image->iterations,image->delay);
 
1079
        (void) WriteBlobString(image,buffer);
 
1080
      }
 
1081
    else
 
1082
      {
 
1083
        if (image->scene != 0)
 
1084
          {
 
1085
            FormatString(buffer,"scene=%lu\n",image->scene);
 
1086
            (void) WriteBlobString(image,buffer);
 
1087
          }
 
1088
        if (image->iterations != 0)
 
1089
          {
 
1090
            FormatString(buffer,"iterations=%lu\n",image->iterations);
 
1091
            (void) WriteBlobString(image,buffer);
 
1092
          }
 
1093
        if (image->delay != 0)
 
1094
          {
 
1095
            FormatString(buffer,"delay=%lu\n",image->delay);
 
1096
            (void) WriteBlobString(image,buffer);
 
1097
          }
 
1098
      }
 
1099
    if (image->dispose != UndefinedDispose)
 
1100
      {
 
1101
        if (image->dispose == BackgroundDispose)
 
1102
          (void) strcpy(buffer,"dispose=background\n");
 
1103
        else
 
1104
          if (image->dispose == NoneDispose)
 
1105
            (void) strcpy(buffer,"dispose=none\n");
 
1106
          else
 
1107
            (void) strcpy(buffer,"dispose=previous\n");
 
1108
        (void) WriteBlobString(image,buffer);
 
1109
      }
 
1110
    if (image->error.mean_error_per_pixel != 0.0)
 
1111
      {
 
1112
        FormatString(buffer,"error=%g  mean-error=%g  maximum-error=%g\n",
 
1113
          image->error.mean_error_per_pixel,image->error.normalized_mean_error,
 
1114
          image->error.normalized_maximum_error);
 
1115
        (void) WriteBlobString(image,buffer);
 
1116
      }
 
1117
    if (image->rendering_intent != UndefinedIntent)
 
1118
      {
 
1119
        if (image->rendering_intent == SaturationIntent)
 
1120
          (void) WriteBlobString(image,"rendering-intent=saturation\n");
 
1121
        else
 
1122
          if (image->rendering_intent == PerceptualIntent)
 
1123
            (void) WriteBlobString(image,"rendering-intent=perceptual\n");
 
1124
          else
 
1125
            if (image->rendering_intent == AbsoluteIntent)
 
1126
              (void) WriteBlobString(image,"rendering-intent=absolute\n");
 
1127
            else
 
1128
              (void) WriteBlobString(image,"rendering-intent=relative\n");
 
1129
      }
 
1130
    if (image->gamma != 0.0)
 
1131
      {
 
1132
        FormatString(buffer,"gamma=%g\n",image->gamma);
 
1133
        (void) WriteBlobString(image,buffer);
 
1134
      }
 
1135
    if (image->chromaticity.white_point.x != 0.0)
 
1136
      {
 
1137
        /*
 
1138
          Note chomaticity points.
 
1139
        */
 
1140
        FormatString(buffer,
 
1141
          "red-primary=%g,%g  green-primary=%g,%g  blue-primary=%g,%g\n",
 
1142
          image->chromaticity.red_primary.x,image->chromaticity.red_primary.y,
 
1143
          image->chromaticity.green_primary.x,
 
1144
          image->chromaticity.green_primary.y,
 
1145
          image->chromaticity.blue_primary.x,
 
1146
          image->chromaticity.blue_primary.y);
 
1147
        (void) WriteBlobString(image,buffer);
 
1148
        FormatString(buffer,"white-point=%g,%g\n",
 
1149
          image->chromaticity.white_point.x,image->chromaticity.white_point.y);
 
1150
        (void) WriteBlobString(image,buffer);
 
1151
      }
 
1152
    if (image->color_profile.length != 0)
 
1153
      {
 
1154
        FormatString(buffer,"profile-icc=%lu\n",(unsigned long)
 
1155
          image->color_profile.length);
 
1156
        (void) WriteBlobString(image,buffer);
 
1157
      }
 
1158
    if (image->iptc_profile.length != 0)
 
1159
      {
 
1160
        FormatString(buffer,"profile-iptc=%lu\n",(unsigned long)
 
1161
          image->iptc_profile.length);
 
1162
        (void) WriteBlobString(image,buffer);
 
1163
      }
 
1164
    if (image->generic_profiles != 0)
 
1165
      {
 
1166
        /*
 
1167
          Generic profile.
 
1168
        */
 
1169
        for (i=0; i < (long) image->generic_profiles; i++)
 
1170
        {
 
1171
          FormatString(buffer,"profile-%s=%lu\n",
 
1172
            image->generic_profile[i].name == (char *) NULL ? "generic" :
 
1173
            image->generic_profile[i].name,(unsigned long)
 
1174
            image->generic_profile[i].length);
 
1175
          (void) WriteBlobString(image,buffer);
 
1176
        }
 
1177
      }
 
1178
    if (image->montage != (char *) NULL)
 
1179
      {
 
1180
        FormatString(buffer,"montage=%.1024s\n",image->montage);
 
1181
        (void) WriteBlobString(image,buffer);
 
1182
      }
 
1183
    attribute=GetImageAttribute(image,(char *) NULL);
 
1184
    for ( ; attribute != (const ImageAttribute *) NULL; attribute=attribute->next)
 
1185
    {
 
1186
      if (attribute->value != NULL)
 
1187
        {
 
1188
          long
 
1189
            j;
 
1190
 
 
1191
          FormatString(buffer,"%.1024s=",attribute->key);
 
1192
          (void) WriteBlobString(image,buffer);
 
1193
          for (j=0; j < (long) strlen(attribute->value); j++)
 
1194
            if (isspace((int) attribute->value[j]))
 
1195
              break;
 
1196
          if (j < (long) strlen(attribute->value))
 
1197
            (void) WriteBlobByte(image,'{');
 
1198
          (void) WriteBlobString(image,attribute->value);
 
1199
          if (j < (long) strlen(attribute->value))
 
1200
            (void) WriteBlobByte(image,'}');
 
1201
          (void) WriteBlobByte(image,'\n');
 
1202
        }
 
1203
    }
 
1204
    (void) WriteBlobString(image,"\f\n:\032");
 
1205
    if (image->montage != (char *) NULL)
 
1206
      {
 
1207
        /*
 
1208
          Write montage tile directory.
 
1209
        */
 
1210
        if (image->directory != (char *) NULL)
 
1211
          (void) WriteBlobString(image,image->directory);
 
1212
        (void) WriteBlobByte(image,'\0');
 
1213
      }
 
1214
    if (image->color_profile.length != 0)
 
1215
      (void) WriteBlob(image,image->color_profile.length,
 
1216
        image->color_profile.info);
 
1217
    if (image->iptc_profile.length != 0)
 
1218
      (void) WriteBlob(image,image->iptc_profile.length,
 
1219
        image->iptc_profile.info);
 
1220
    if (image->generic_profiles != 0)
 
1221
      {
 
1222
        /*
 
1223
          Generic profile.
 
1224
        */
 
1225
        for (i=0; i < (long) image->generic_profiles; i++)
 
1226
        {
 
1227
          if (image->generic_profile[i].length == 0)
 
1228
            continue;
 
1229
          (void) WriteBlob(image,image->generic_profile[i].length,
 
1230
            image->generic_profile[i].info);
 
1231
        }
 
1232
      }
 
1233
    if (image->storage_class == PseudoClass)
 
1234
      {
 
1235
        register unsigned char
 
1236
          *q;
 
1237
 
 
1238
        unsigned char
 
1239
          *colormap;
 
1240
 
 
1241
        unsigned int
 
1242
          packet_size;
 
1243
 
 
1244
        /*
 
1245
          Allocate colormap.
 
1246
        */
 
1247
        packet_size=image->depth > 8 ? 6 : 3;
 
1248
        colormap=MagickAllocateMemory(unsigned char *,packet_size*image->colors);
 
1249
        if (colormap == (unsigned char *) NULL)
 
1250
          return(False);
 
1251
        /*
 
1252
          Write colormap to file.
 
1253
        */
 
1254
        q=colormap;
 
1255
        if (image->depth <= 8)
 
1256
          for (i=0; i < (long) image->colors; i++)
 
1257
          {
 
1258
            *q++=image->colormap[i].red;
 
1259
            *q++=image->colormap[i].green;
 
1260
            *q++=image->colormap[i].blue;
 
1261
          }
 
1262
        else
 
1263
          for (i=0; i < (long) image->colors; i++)
 
1264
          {
 
1265
            *q++=image->colormap[i].red >> 8;
 
1266
            *q++=image->colormap[i].red & 0xff;
 
1267
            *q++=image->colormap[i].green >> 8;
 
1268
            *q++=image->colormap[i].green & 0xff;
 
1269
            *q++=image->colormap[i].blue >> 8;
 
1270
            *q++=image->colormap[i].blue & 0xff;
 
1271
          }
 
1272
        (void) WriteBlob(image,packet_size*image->colors,colormap);
 
1273
        MagickFreeMemory(colormap);
 
1274
      }
 
1275
    /*
 
1276
      Initialize persistent pixel cache.
 
1277
    */
 
1278
    status=PersistCache(image,cache_filename,False,&offset,&image->exception);
 
1279
    if (status == False)
 
1280
      ThrowWriterException(CacheError,UnableToPeristPixelCache,image);
 
1281
    if (image->next == (Image *) NULL)
 
1282
      break;
 
1283
    image=SyncNextImageInList(image);
 
1284
    status=MagickMonitor(SaveImagesText,scene++,GetImageListLength(image),
 
1285
      &image->exception);
 
1286
    if (status == False)
 
1287
      break;
 
1288
  } while (image_info->adjoin);
 
1289
  if (image_info->adjoin)
 
1290
    while (image->previous != (Image *) NULL)
 
1291
      image=image->previous;
 
1292
  CloseBlob(image);
 
1293
  return(status);
 
1294
}