Coverage Report

Created: 2026-05-24 07:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/graphicsmagick/coders/pcd.c
Line
Count
Source
1
/*
2
% Copyright (C) 2003-2026 GraphicsMagick Group
3
% Copyright (C) 2002 ImageMagick Studio
4
% Copyright 1991-1999 E. I. du Pont de Nemours and Company
5
%
6
% This program is covered by multiple licenses, which are described in
7
% Copyright.txt. You should have received a copy of Copyright.txt with this
8
% package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
9
%
10
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11
%                                                                             %
12
%                                                                             %
13
%                                                                             %
14
%                            PPPP    CCCC  DDDD                               %
15
%                            P   P  C      D   D                              %
16
%                            PPPP   C      D   D                              %
17
%                            P      C      D   D                              %
18
%                            P       CCCC  DDDD                               %
19
%                                                                             %
20
%                                                                             %
21
%                     Read/Write Photo CD Image Format.                       %
22
%                                                                             %
23
%                                                                             %
24
%                              Software Design                                %
25
%                                John Cristy                                  %
26
%                                 July 1992                                   %
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/blob.h"
41
#include "magick/pixel_cache.h"
42
#include "magick/decorate.h"
43
#include "magick/gem.h"
44
#include "magick/log.h"
45
#include "magick/magick.h"
46
#include "magick/monitor.h"
47
#include "magick/montage.h"
48
#include "magick/resize.h"
49
#include "magick/shear.h"
50
#include "magick/transform.h"
51
#include "magick/utility.h"
52
#include "magick/static.h"
53

54
/*
55
  Forward declarations.
56
*/
57
static unsigned int
58
  WritePCDImage(const ImageInfo *,Image *);
59

60
/*
61
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
62
%                                                                             %
63
%                                                                             %
64
%                                                                             %
65
%   U p s a m p l e                                                           %
66
%                                                                             %
67
%                                                                             %
68
%                                                                             %
69
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
70
%
71
%  Upsample() doubles the size of the image.
72
%
73
%  The format of the Upsample method is:
74
%
75
%      void Upsample(const unsigned long width,const unsigned long height,
76
%        const unsigned long scaled_width,unsigned char *pixels)
77
%
78
%  A description of each parameter follows:
79
%
80
%    o width,height:  Unsigned values representing the width and height of
81
%      the image pixel array.
82
%
83
%    o scaled_width:  Specifies the final width of the upsampled pixel array.
84
%
85
%    o pixels:  An unsigned char containing the pixel data.  On output the
86
%      upsampled pixels are returned here.
87
%
88
%
89
*/
90
static void Upsample(const unsigned long width,const unsigned long height,
91
                     const unsigned long scaled_width,unsigned char *pixels)
92
5.04k
{
93
5.04k
  register long
94
5.04k
    x,
95
5.04k
    y;
96
97
5.04k
  register unsigned char
98
5.04k
    *p,
99
5.04k
    *q,
100
5.04k
    *r;
101
102
  /*
103
    Create a new image that is a integral size greater than an existing one.
104
  */
105
5.04k
  assert(pixels != (unsigned char *) NULL);
106
327k
  for (y=0; y < (long) height; y++)
107
322k
  {
108
322k
    p=pixels+((size_t)height-1-y)*scaled_width+((size_t)width-1);
109
322k
    q=pixels+(((size_t)height-1-y) << 1)*(size_t)scaled_width+(((size_t)width-1) << 1);
110
322k
    *q=(*p);
111
322k
    *(q+1)=(*(p));
112
30.9M
    for (x=1; x < (long) width; x++)
113
30.6M
    {
114
30.6M
      p--;
115
30.6M
      q-=2;
116
30.6M
      *q=(*p);
117
30.6M
      *(q+1)=(unsigned char) ((((long) *p)+((long) *(p+1))+1) >> 1);
118
30.6M
    }
119
322k
  }
120
322k
  for (y=0; y < (long) ((size_t)height-1); y++)
121
317k
  {
122
317k
    p=pixels+((size_t)y << 1)*scaled_width;
123
317k
    q=p+(size_t)scaled_width;
124
317k
    r=q+ (size_t)scaled_width;
125
30.4M
    for (x=0; x < (long) (width-1); x++)
126
30.1M
    {
127
30.1M
      *q=(unsigned char) ((((long) *p)+((long) *r)+1) >> 1);
128
30.1M
      *(q+1)=(unsigned char)
129
30.1M
        ((((long) *p)+((long) *(p+2))+((long) *r)+((long) *(r+2))+2) >> 2);
130
30.1M
      q+=2;
131
30.1M
      p+=2;
132
30.1M
      r+=2;
133
30.1M
    }
134
317k
    *q++=(unsigned char) ((((long) *p++)+((long) *r++)+1) >> 1);
135
317k
    *q++=(unsigned char) ((((long) *p++)+((long) *r++)+1) >> 1);
136
317k
  }
137
5.04k
  p=pixels+(2*(size_t)height-2)* (size_t)scaled_width;
138
5.04k
  q=pixels+(2*(size_t)height-1)* (size_t)scaled_width;
139
5.04k
  (void) memcpy(q,p,2*(size_t)width);
140
5.04k
}
141

142
/*
143
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
144
%                                                                             %
145
%                                                                             %
146
%                                                                             %
147
%   D e c o d e I m a g e                                                     %
148
%                                                                             %
149
%                                                                             %
150
%                                                                             %
151
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
152
%
153
%  Method DecodeImage recovers the Huffman encoded luminance and chrominance
154
%  deltas.
155
%
156
%  The format of the DecodeImage method is:
157
%
158
%      static unsigned int DecodeImage(Image *image,unsigned char *luma,
159
%        unsigned char *chroma1,unsigned char *chroma2)
160
%
161
%  A description of each parameter follows:
162
%
163
%    o status:  Method DecodeImage returns True if all the deltas are
164
%      recovered without error, otherwise False.
165
%
166
%    o image: The address of a structure of type Image.
167
%
168
%    o luma: The address of a character buffer that contains the
169
%      luminance information.
170
%
171
%    o chroma1: The address of a character buffer that contains the
172
%      chrominance information.
173
%
174
%    o chroma2: The address of a character buffer that contains the
175
%      chrominance information.
176
%
177
%
178
%
179
*/
180
0
#define IsSync  ((sum & 0xffffff00) == 0xfffffe00)
181
0
#define DecodeImageText  "[%s] PCD decode image..."
182
0
#define PCDGetBits(n) \
183
0
{  \
184
0
  sum=(sum << n) & 0xffffffff; \
185
0
  bits-=n; \
186
0
  while (bits <= 24) \
187
0
  { \
188
0
    if (p >= (buffer+0x800)) \
189
0
      { \
190
0
        if (ReadBlob(image,0x800,(char *) buffer) != 0x800) \
191
0
          break;                                            \
192
0
        p=buffer; \
193
0
      } \
194
0
    sum|=(((unsigned int) (*p)) << (24-bits));  \
195
0
    bits+=8; \
196
0
    p++; \
197
0
  } \
198
0
  if (EOFBlob(image)) \
199
0
    break; \
200
0
}
201
static MagickPassFail DecodeImage(Image *image,unsigned char *luma,
202
  unsigned char *chroma1,unsigned char *chroma2)
203
0
{
204
0
  typedef struct PCDTable
205
0
  {
206
0
    unsigned int
207
0
      length,
208
0
      sequence;
209
210
0
    unsigned int
211
0
      mask;
212
213
0
    unsigned char
214
0
      key;
215
0
  } PCDTable;
216
217
0
  long
218
    /* count, */
219
0
    quantum;
220
221
0
  PCDTable
222
0
    *pcd_table[3];
223
224
0
  register long
225
0
    i,
226
0
    j;
227
228
0
  register PCDTable
229
0
    *r;
230
231
0
  register unsigned char
232
0
    *p,
233
0
    *q;
234
235
0
  size_t
236
0
    length;
237
238
0
  unsigned char
239
0
    *buffer;
240
241
0
  unsigned int
242
0
    bits,
243
0
    plane,
244
0
    pcd_length[3],
245
0
    row,
246
0
    sum;
247
248
0
  unsigned int
249
0
    status = MagickPass;
250
251
  /*
252
    Initialize Huffman tables.
253
  */
254
0
  assert(image != (const Image *) NULL);
255
0
  assert(image->signature == MagickSignature);
256
0
  assert(luma != (unsigned char *) NULL);
257
0
  assert(chroma1 != (unsigned char *) NULL);
258
0
  assert(chroma2 != (unsigned char *) NULL);
259
0
  if (image->logging)
260
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
261
0
                          "Huffman decode image %lux%lu (%u tables)",
262
0
                          image->columns, image->rows,
263
0
                          (image->columns > 1536 ? 3U : 1U));
264
0
  pcd_table[2]=pcd_table[1]=pcd_table[0]=(PCDTable *) NULL;
265
0
  pcd_length[2]=pcd_length[1]=pcd_length[0]=0;
266
0
  buffer=MagickAllocateResourceLimitedMemory(unsigned char *,0x800);
267
0
  if (buffer == (unsigned char *) NULL)
268
0
    ThrowBinaryException(ResourceLimitError,MemoryAllocationFailed,
269
0
      (char *) NULL);
270
0
  sum=0;
271
0
  bits=32;
272
0
  p=buffer+0x800;
273
0
  for (i=0; i < (image->columns > 1536 ? 3 : 1); i++)
274
0
  {
275
0
    PCDGetBits(8);
276
0
    length=(size_t)(sum & 0xff)+1;
277
0
    pcd_table[i]=MagickAllocateResourceLimitedArray(PCDTable *,length,sizeof(PCDTable));
278
0
    if (pcd_table[i] == (PCDTable *) NULL)
279
0
      {
280
0
        ThrowException(&image->exception,ResourceLimitError,
281
0
                       MemoryAllocationFailed,image->filename);
282
0
        status=MagickFail;
283
0
        goto decode_image_error;
284
0
      }
285
0
    r=pcd_table[i];
286
0
    for (j=0; j < (long) length; j++)
287
0
    {
288
0
      PCDGetBits(8);
289
0
      r->length=(sum & 0xff)+1;
290
0
      if (r->length > 16)
291
0
        {
292
0
          if (image->logging)
293
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
294
0
                                  "Excessive length %" MAGICK_SIZE_T_F "u!",
295
0
                                  (MAGICK_SIZE_T) length);
296
0
          ThrowException(&image->exception,CorruptImageError,
297
0
                         UnableToUncompressImage,image->filename);
298
0
          status=MagickFail;
299
0
          goto decode_image_error;
300
0
        }
301
0
      PCDGetBits(16);
302
0
      r->sequence=(sum & 0xffff) << 16;
303
0
      PCDGetBits(8);
304
0
      r->key=(unsigned char) (sum & 0xff);
305
0
      r->mask=(~((((unsigned int) 1) << (32-r->length))-1));
306
0
      r++;
307
0
    }
308
0
    pcd_length[i]=(unsigned int) length;
309
0
  }
310
0
  if (EOFBlob(image))
311
0
    {
312
0
      status=MagickFail;
313
0
      goto decode_image_error;
314
0
    }
315
316
  /*
317
    Search for Sync byte.
318
  */
319
0
  for (i=0; i < 1; i++)
320
0
    PCDGetBits(16);
321
0
  for (i=0; i < 1; i++)
322
0
    PCDGetBits(16);
323
0
  while ((sum & 0x00fff000) != 0x00fff000)
324
0
    PCDGetBits(8);
325
0
  while (!IsSync)
326
0
    PCDGetBits(1);
327
  /*
328
    Recover the Huffman encoded luminance and chrominance deltas.
329
  */
330
  /* count=0; */
331
0
  length=0;
332
0
  plane=0;
333
0
  row=0;
334
0
  q=luma;
335
0
  for ( ; ; )
336
0
  {
337
0
    if (IsSync)
338
0
      {
339
        /*
340
          Determine plane and row number.
341
        */
342
0
        PCDGetBits(16);
343
0
        row=((sum >> 9) & 0x1fff);
344
0
        if (row == image->rows)
345
0
          break;
346
0
        PCDGetBits(8);
347
0
        plane=sum >> 30;
348
0
        PCDGetBits(16);
349
0
        switch (plane)
350
0
        {
351
0
          case 0:
352
0
          {
353
0
            q=luma+row*(size_t)image->columns;
354
            /* count=(long) image->columns; */
355
0
            break;
356
0
          }
357
0
          case 2:
358
0
          {
359
0
            q=chroma1+(row >> 1)*(size_t)image->columns;
360
            /* count=(long) (image->columns >> 1); */
361
0
            plane--;
362
0
            break;
363
0
          }
364
0
          case 3:
365
0
          {
366
0
            q=chroma2+(row >> 1)*(size_t)image->columns;
367
            /* count=(long) (image->columns >> 1); */
368
0
            plane--;
369
0
            break;
370
0
          }
371
0
          default:
372
0
          {
373
0
            if (image->logging)
374
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
375
0
                                    "Unhandled plane %u!", plane);
376
0
            ThrowException(&image->exception,CorruptImageError,
377
0
                         UnableToUncompressImage,image->filename);
378
0
            status=MagickFail;
379
0
            goto decode_image_error;
380
0
          }
381
0
        }
382
0
        length=pcd_length[plane];
383
0
        if (QuantumTick(row,image->rows))
384
0
          if (!MagickMonitorFormatted(row,image->rows,&image->exception,
385
0
                                      DecodeImageText,image->filename))
386
0
            {
387
0
              status=MagickFail;
388
0
              goto decode_image_error;
389
0
            }
390
0
        continue;
391
0
      }
392
    /*
393
      Decode luminance or chrominance deltas.
394
    */
395
0
    r=pcd_table[plane];
396
0
    for (i=1; ((i < (long) length) && ((sum & r->mask) != r->sequence)); i++)
397
0
      r++;
398
0
    if ((row > image->rows) || (r == (PCDTable *) NULL))
399
0
      {
400
0
        ThrowException(&image->exception,CorruptImageWarning,SkipToSyncByte,
401
0
                       image->filename);
402
0
        while ((sum & 0x00fff000) != 0x00fff000)
403
0
          PCDGetBits(8);
404
0
        while (!IsSync)
405
0
          PCDGetBits(1);
406
0
        continue;
407
0
      }
408
0
    if (r->key < 128U)
409
0
      quantum=(long) (*q)+r->key;
410
0
    else
411
0
      quantum=(long) (*q)+r->key-256;
412
0
    *q=(unsigned char) ((quantum < 0L) ? 0U :
413
0
                        (quantum > 255L) ? 255U :
414
0
                        (unsigned char) quantum);
415
0
    q++;
416
0
    PCDGetBits(r->length);
417
    /* count--; */
418
0
  }
419
0
 decode_image_error:
420
  /*
421
    Free memory.
422
  */
423
0
  for (i=0; i < (image->columns > 1536 ? 3 : 1); i++)
424
0
    MagickFreeResourceLimitedMemory(PCDTable *,pcd_table[i]);
425
0
  MagickFreeResourceLimitedMemory(unsigned char *,buffer);
426
0
  return(status);
427
0
}
428

429
/*
430
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
431
%                                                                             %
432
%                                                                             %
433
%                                                                             %
434
%   I s P C D                                                                 %
435
%                                                                             %
436
%                                                                             %
437
%                                                                             %
438
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
439
%
440
%  Method IsPCD returns True if the image format type, identified by the
441
%  magick string, is PCD.
442
%
443
%  The format of the IsPCD method is:
444
%
445
%      unsigned int IsPCD(const unsigned char *magick,const size_t length)
446
%
447
%  A description of each parameter follows:
448
%
449
%    o status:  Method IsPCD returns True if the image format type is PCD.
450
%
451
%    o magick: This string is generally the first few bytes of an image file
452
%      or blob.
453
%
454
%    o length: Specifies the length of the magick string.
455
%
456
%
457
*/
458
static unsigned int IsPCD(const unsigned char *magick,const size_t length)
459
0
{
460
0
  if (length < 2052)
461
0
    return(False);
462
0
  if (LocaleNCompare((char *) magick+2048,"PCD_",4) == 0)
463
0
    return(True);
464
0
  return(False);
465
0
}
466

467
/*
468
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
469
%                                                                             %
470
%                                                                             %
471
%                                                                             %
472
%   R e a d P C D I m a g e                                                   %
473
%                                                                             %
474
%                                                                             %
475
%                                                                             %
476
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
477
%
478
%  Method ReadPCDImage reads a Photo CD image file and returns it.  It
479
%  allocates the memory necessary for the new Image structure and returns a
480
%  pointer to the new image.  Much of the PCD decoder was derived from
481
%  the program hpcdtoppm(1) by Hadmut Danisch.
482
%
483
%  The format of the ReadPCDImage method is:
484
%
485
%      image=ReadPCDImage(image_info)
486
%
487
%  A description of each parameter follows:
488
%
489
%    o image:  Method ReadPCDImage returns a pointer to the image after
490
%      reading.  A null image is returned if there is a memory shortage or
491
%      if the image cannot be read.
492
%
493
%    o image_info: Specifies a pointer to a ImageInfo structure.
494
%
495
%    o exception: return any errors or warnings in this structure.
496
%
497
%
498
*/
499
500
static Image *OverviewImage(const ImageInfo *image_info,Image *images,
501
  ExceptionInfo *exception)
502
60
{
503
60
  Image
504
60
    *montage_image;
505
506
60
  MontageInfo
507
60
    *montage_info;
508
509
  /*
510
    Label image tiles.
511
  */
512
60
  {
513
60
    Image
514
60
      *label_image;
515
516
704
    for( label_image=GetFirstImageInList(images); label_image != 0;
517
644
         label_image=GetNextImageInList(label_image) )
518
644
      (void) SetImageAttribute(label_image, "label", DefaultTileLabel);
519
60
  }
520
521
  /*
522
    Create the PCD Overview image.
523
  */
524
60
  montage_info=CloneMontageInfo(image_info,(MontageInfo *) NULL);
525
60
  (void) strlcpy(montage_info->filename,image_info->filename,MaxTextExtent);
526
60
  montage_image=MontageImages(images,montage_info,exception);
527
60
  DestroyMontageInfo(montage_info);
528
60
  DestroyImageList(images);
529
60
  return(montage_image);
530
60
}
531
532
#define ThrowPCDReaderException(code_,reason_,image_)                \
533
1.47k
  {                                                                  \
534
1.47k
    MagickFreeResourceLimitedMemory(unsigned char *,chroma1);        \
535
1.47k
    MagickFreeResourceLimitedMemory(unsigned char *,chroma2);        \
536
1.47k
    MagickFreeResourceLimitedMemory(unsigned char *,luma);           \
537
1.47k
    ThrowReaderException(code_,reason_,image_);                      \
538
0
  }
539
540
static Image *ReadPCDImage(const ImageInfo *image_info,ExceptionInfo *exception)
541
1.51k
{
542
1.51k
  Image
543
1.51k
    *image;
544
545
1.51k
  long
546
1.51k
    x;
547
548
1.51k
  ExtendedSignedIntegralType
549
1.51k
    offset;
550
551
1.51k
  register long
552
1.51k
    y;
553
554
1.51k
  register PixelPacket
555
1.51k
    *q;
556
557
1.51k
  register long
558
1.51k
    i;
559
560
1.51k
  register unsigned char
561
1.51k
    *c1,
562
1.51k
    *c2,
563
1.51k
    *yy;
564
565
1.51k
  size_t
566
1.51k
    number_pixels,
567
1.51k
    count;
568
569
1.51k
  unsigned char
570
1.51k
    *chroma1 = NULL,
571
1.51k
    *chroma2 = NULL,
572
1.51k
    header[3*0x800],
573
1.51k
    *luma = NULL;
574
575
1.51k
  unsigned int
576
1.51k
    overview,
577
1.51k
    rotate,
578
1.51k
    status;
579
580
1.51k
  unsigned long
581
1.51k
    height,
582
1.51k
    number_images,
583
1.51k
    subimage,
584
1.51k
    width;
585
586
  /*
587
    Open image file.
588
  */
589
1.51k
  assert(image_info != (const ImageInfo *) NULL);
590
1.51k
  assert(image_info->signature == MagickSignature);
591
1.51k
  assert(exception != (ExceptionInfo *) NULL);
592
1.51k
  assert(exception->signature == MagickSignature);
593
1.51k
  image=AllocateImage(image_info);
594
1.51k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
595
1.51k
  if (status == False)
596
1.51k
    ThrowReaderException(FileOpenError,UnableToOpenFile,image);
597
  /*
598
    Determine if this is a PCD file.
599
  */
600
1.51k
  if ((count=ReadBlob(image,3*0x800,(char *) header)) != 3*0x800)
601
1.32k
    ThrowPCDReaderException(CorruptImageError,UnexpectedEndOfFile,image);
602
1.32k
  overview=LocaleNCompare((char *) header,"PCD_OPA",7) == 0;
603
1.32k
  if ((LocaleNCompare((char *) header+0x800,"PCD",3) != 0) && !overview)
604
1.27k
    ThrowPCDReaderException(CorruptImageError,ImproperImageHeader,image);
605
1.27k
  rotate=header[0x0e02] & 0x03;
606
1.27k
  number_images=((header[10] << 8) | header[11]) & 0xFFFF;
607
  /*
608
    Determine resolution by subimage specification.
609
  */
610
1.27k
  number_pixels= (size_t)image->columns*image->rows;
611
1.27k
  if (number_pixels == 0)
612
1.27k
    {
613
1.27k
      subimage=3;
614
1.27k
    }
615
0
  else
616
0
    {
617
0
      width=192;
618
0
      height=128;
619
0
      for (subimage=1; subimage < 6; subimage++)
620
0
      {
621
0
        if ((width >= image->columns) && (height >= image->rows))
622
0
          break;
623
0
        width<<=1;
624
0
        height<<=1;
625
0
      }
626
0
    }
627
1.27k
  if (image_info->subrange != 0)
628
1.27k
    subimage=Min(image_info->subimage,6);
629
1.27k
  if (overview)
630
428
    subimage=1;
631
  /*
632
    Initialize image structure.
633
  */
634
1.27k
  width=192;
635
1.27k
  height=128;
636
1.27k
  for (i=1; i < (long) Min(subimage,3); i++)
637
0
  {
638
0
    width<<=1;
639
0
    height<<=1;
640
0
  }
641
1.27k
  image->columns=width;
642
1.27k
  image->rows=height;
643
1.27k
  image->depth=8;
644
1.27k
  for ( ; i < (long) subimage; i++)
645
0
  {
646
0
    image->columns<<=1;
647
0
    image->rows<<=1;
648
0
  }
649
1.27k
  if (image->logging)
650
1.27k
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
651
1.27k
                          "Decode PCD %simage geometry %lux%lu",
652
1.27k
                          (overview ? "(with overview) " : ""),
653
1.27k
                          image->columns,image->rows);
654
655
1.27k
  if (CheckImagePixelLimits(image, exception) != MagickPass)
656
717
    ThrowReaderException(ResourceLimitError,ImagePixelLimitExceeded,image);
657
658
  /*
659
    Allocate luma and chroma memory.
660
  */
661
717
  number_pixels=MagickArraySize(image->columns,image->rows);
662
717
  if (number_pixels == 0 || number_pixels+1 < number_pixels)
663
717
    ThrowPCDReaderException(ResourceLimitError,MemoryAllocationFailed,image);
664
717
  chroma1=MagickAllocateResourceLimitedMemory(unsigned char *,number_pixels+1);
665
717
  chroma2=MagickAllocateResourceLimitedMemory(unsigned char *,number_pixels+1);
666
717
  luma=MagickAllocateResourceLimitedMemory(unsigned char *,number_pixels+1);
667
717
  if ((chroma1 == (unsigned char *) NULL) ||
668
717
      (chroma2 == (unsigned char *) NULL) ||
669
717
      (luma == (unsigned char *) NULL))
670
717
    ThrowPCDReaderException(ResourceLimitError,MemoryAllocationFailed,image);
671
  /*
672
    Advance to image data.
673
  */
674
717
  offset=93;
675
717
  if (overview)
676
427
    offset=2;
677
290
  else
678
290
    if (subimage == 2)
679
0
      offset=20;
680
290
    else
681
290
      if (subimage <= 1)
682
290
        offset=1;
683
2.09M
  for (i=0; i < (long) (offset*0x800); i++)
684
2.09M
    if (ReadBlobByte(image) == EOF)
685
639
      ThrowPCDReaderException(CorruptImageError,UnexpectedEndOfFile,image);
686
639
  if (overview)
687
367
    {
688
367
      MonitorHandler
689
367
        handler;
690
691
367
      register long
692
367
        j;
693
694
      /*
695
        Read thumbnails from overview image.
696
      */
697
2.75k
      for (j=1; j <= (long) number_images; j++)
698
2.69k
      {
699
2.69k
        handler=SetMonitorHandler((MonitorHandler) NULL);
700
2.69k
        MagickFormatString(image->filename,sizeof(image->filename),"images/img%04ld.pcd",j);
701
2.69k
        MagickFormatString(image->magick_filename,sizeof(image->magick_filename),"images/img%04ld.pcd",j);
702
2.69k
        image->scene=j;
703
2.69k
        image->columns=width;
704
2.69k
        image->rows=height;
705
2.69k
        image->depth=8;
706
2.69k
        yy=luma;
707
2.69k
        c1=chroma1;
708
2.69k
        c2=chroma2;
709
159k
        for (y=0; y < (long) height; y+=2)
710
156k
        {
711
156k
          if (ReadBlob(image,width,(char *) yy) != width)
712
146
            break;
713
156k
          yy+=image->columns;
714
156k
          if (ReadBlob(image,width,(char *) yy) != width)
715
61
            break;
716
156k
          yy+=image->columns;
717
156k
          if (ReadBlob(image,width >> 1,(char *) c1) != (width >> 1))
718
56
            break;
719
156k
          c1+=image->columns;
720
156k
          if (ReadBlob(image,width >> 1,(char *) c2) != (width >> 1))
721
44
            break;
722
156k
          c2+=image->columns;
723
156k
        }
724
2.69k
        if (EOFBlob(image))
725
2.38k
          ThrowPCDReaderException(CorruptImageError,UnexpectedEndOfFile,image);
726
2.38k
        Upsample(image->columns >> 1,image->rows >> 1,image->columns,chroma1);
727
2.38k
        Upsample(image->columns >> 1,image->rows >> 1,image->columns,chroma2);
728
        /*
729
          Transfer luminance and chrominance channels.
730
        */
731
2.38k
        yy=luma;
732
2.38k
        c1=chroma1;
733
2.38k
        c2=chroma2;
734
307k
        for (y=0; y < (long) image->rows; y++)
735
305k
        {
736
305k
          q=SetImagePixels(image,0,y,image->columns,1);
737
305k
          if (q == (PixelPacket *) NULL)
738
0
            break;
739
58.8M
          for (x=0; x < (long) image->columns; x++)
740
58.5M
          {
741
58.5M
            q->red=ScaleCharToQuantum(*yy++);
742
58.5M
            q->green=ScaleCharToQuantum(*c1++);
743
58.5M
            q->blue=ScaleCharToQuantum(*c2++);
744
58.5M
            q++;
745
58.5M
          }
746
305k
          if (!SyncImagePixels(image))
747
0
            break;
748
305k
        }
749
2.38k
        if (LocaleCompare(image_info->magick,"PCDS") == 0)
750
1.20k
          image->colorspace=sRGBColorspace;
751
1.18k
        else
752
1.18k
          image->colorspace=YCCColorspace;
753
2.38k
        if (TransformColorspace(image,RGBColorspace) != MagickPass)
754
0
          break;
755
2.38k
        StopTimer(&image->timer);
756
2.38k
        if (j < (long) number_images)
757
2.32k
          {
758
            /*
759
              Allocate next image structure.
760
            */
761
2.32k
            AllocateNextImage(image_info,image);
762
2.32k
            if (image->next == (Image *) NULL)
763
2.32k
              ThrowPCDReaderException(ResourceLimitError,MemoryAllocationFailed,image);
764
2.32k
            image=SyncNextImageInList(image);
765
2.32k
          }
766
2.38k
        (void) SetMonitorHandler(handler);
767
2.38k
        if (!MagickMonitorFormatted((size_t)j-1,number_images,&image->exception,
768
2.38k
                                    LoadImageText,image->filename,
769
2.38k
                                    image->columns,image->rows))
770
0
          break;
771
2.38k
      }
772
60
      MagickFreeResourceLimitedMemory(unsigned char *,chroma2);
773
60
      MagickFreeResourceLimitedMemory(unsigned char *,chroma1);
774
60
      MagickFreeResourceLimitedMemory(unsigned char *,luma);
775
644
      while (image->previous != (Image *) NULL)
776
584
        image=image->previous;
777
60
      CloseBlob(image);
778
      /* OverviewImage destroys image list before returning */
779
60
      return OverviewImage(image_info,image,exception);
780
367
    }
781
  /*
782
    Read interleaved image.
783
  */
784
272
  yy=luma;
785
272
  c1=chroma1;
786
272
  c2=chroma2;
787
10.1k
  for (y=0; y < (long) height; y+=2)
788
9.97k
  {
789
9.97k
    if (ReadBlob(image,width,(char *) yy) != width)
790
38
      break;
791
9.94k
    yy+=image->columns;
792
9.94k
    if (ReadBlob(image,width,(char *) yy) != width)
793
21
      break;
794
9.92k
    yy+=image->columns;
795
9.92k
    if (ReadBlob(image,width >> 1,(char *) c1) != (width >> 1))
796
42
      break;
797
9.87k
    c1+=image->columns;
798
9.87k
    if (ReadBlob(image,width >> 1,(char *) c2)  != (width >> 1))
799
34
      break;
800
9.84k
    c2+=image->columns;
801
9.84k
  }
802
272
  if (EOFBlob(image))
803
137
    ThrowPCDReaderException(CorruptImageError,UnexpectedEndOfFile,image);
804
137
  if (subimage >= 4)
805
0
    {
806
      /*
807
        Recover luminance deltas for 1536x1024 image.
808
      */
809
0
      Upsample(768,512,image->columns,luma);
810
0
      Upsample(384,256,image->columns,chroma1);
811
0
      Upsample(384,256,image->columns,chroma2);
812
0
      image->rows=1024;
813
0
      for (i=0; i < (4*0x800); i++)
814
0
        (void) ReadBlobByte(image);
815
0
      status=DecodeImage(image,luma,chroma1,chroma2);
816
0
      if ((subimage >= 5) && status)
817
0
        {
818
          /*
819
            Recover luminance deltas for 3072x2048 image.
820
          */
821
0
          Upsample(1536,1024,image->columns,luma);
822
0
          Upsample(768,512,image->columns,chroma1);
823
0
          Upsample(768,512,image->columns,chroma2);
824
0
          image->rows=2048;
825
0
          offset=TellBlob(image)/0x800+12;
826
0
          (void) SeekBlob(image,offset*0x800,SEEK_SET);
827
0
          status=DecodeImage(image,luma,chroma1,chroma2);
828
0
          if ((subimage >= 6) && status)
829
0
            {
830
              /*
831
                Recover luminance deltas for 6144x4096 image (vaporware).
832
              */
833
0
              Upsample(3072,2048,image->columns,luma);
834
0
              Upsample(1536,1024,image->columns,chroma1);
835
0
              Upsample(1536,1024,image->columns,chroma2);
836
0
              image->rows=4096;
837
0
            }
838
0
        }
839
0
    }
840
137
  if (EOFBlob(image))
841
137
    ThrowPCDReaderException(CorruptImageError,UnexpectedEndOfFile,image);
842
843
137
  CloseBlob(image);
844
845
137
  Upsample(image->columns >> 1,image->rows >> 1,image->columns,chroma1);
846
137
  Upsample(image->columns >> 1,image->rows >> 1,image->columns,chroma2);
847
  /*
848
    Transfer luminance and chrominance channels.
849
  */
850
137
  yy=luma;
851
137
  c1=chroma1;
852
137
  c2=chroma2;
853
17.6k
  for (y=0; y < (long) image->rows; y++)
854
17.5k
  {
855
17.5k
    q=SetImagePixels(image,0,y,image->columns,1);
856
17.5k
    if (q == (PixelPacket *) NULL)
857
0
      break;
858
3.38M
    for (x=0; x < (long) image->columns; x++)
859
3.36M
    {
860
3.36M
      q->red=ScaleCharToQuantum(*yy++);
861
3.36M
      q->green=ScaleCharToQuantum(*c1++);
862
3.36M
      q->blue=ScaleCharToQuantum(*c2++);
863
3.36M
      q++;
864
3.36M
    }
865
17.5k
    if (!SyncImagePixels(image))
866
0
      break;
867
17.5k
    if (QuantumTick(y,image->rows))
868
17.5k
      if (!MagickMonitorFormatted(y,image->rows,exception,LoadImageText,
869
17.5k
                                  image->filename,
870
17.5k
                                  image->columns,image->rows))
871
0
        break;
872
17.5k
  }
873
137
  MagickFreeResourceLimitedMemory(unsigned char *,chroma2);
874
137
  MagickFreeResourceLimitedMemory(unsigned char *,chroma1);
875
137
  MagickFreeResourceLimitedMemory(unsigned char *,luma);
876
137
  if (LocaleCompare(image_info->magick,"PCDS") == 0)
877
70
    image->colorspace=sRGBColorspace;
878
67
  else
879
67
    image->colorspace=YCCColorspace;
880
  /* FIXME: YCCColorspace transform is broken! 1.1 is ok! */
881
137
  if (TransformColorspace(image,RGBColorspace) == MagickFail)
882
0
    ThrowException(exception,CoderError,UnableToTransformColorspace,
883
137
                   image->filename);
884
137
  if ((rotate == 1) || (rotate == 3))
885
83
    {
886
83
      double
887
83
        degrees;
888
889
83
      Image
890
83
        *rotated_image;
891
892
      /*
893
        Rotate image.
894
      */
895
83
      degrees=rotate == 1 ? -90.0 : 90.0;
896
83
      rotated_image=RotateImage(image,degrees,exception);
897
83
      if (rotated_image != (Image *) NULL)
898
83
        {
899
83
          DestroyBlob(rotated_image);
900
83
          rotated_image->blob=ReferenceBlob(image->blob);
901
83
          DestroyImage(image);
902
83
          image=rotated_image;
903
83
        }
904
83
    }
905
906
  /*
907
    Set CCIR 709 primaries with a D65 white point.
908
  */
909
137
  image->chromaticity.red_primary.x=0.6400f;
910
137
  image->chromaticity.red_primary.y=0.3300f;
911
137
  image->chromaticity.green_primary.x=0.3000f;
912
137
  image->chromaticity.green_primary.y=0.6000f;
913
137
  image->chromaticity.blue_primary.x=0.1500f;
914
137
  image->chromaticity.blue_primary.y=0.0600f;
915
137
  image->chromaticity.white_point.x=0.3127f;
916
137
  image->chromaticity.white_point.y=0.3290f;
917
137
  image->gamma=1.000f/2.200f;
918
137
  StopTimer(&image->timer);
919
137
  return(image);
920
137
}
921

922
/*
923
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
924
%                                                                             %
925
%                                                                             %
926
%                                                                             %
927
%   R e g i s t e r P C D I m a g e                                           %
928
%                                                                             %
929
%                                                                             %
930
%                                                                             %
931
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
932
%
933
%  Method RegisterPCDImage adds attributes for the PCD image format to
934
%  the list of supported formats.  The attributes include the image format
935
%  tag, a method to read and/or write the format, whether the format
936
%  supports the saving of more than one frame to the same file or blob,
937
%  whether the format supports native in-memory I/O, and a brief
938
%  description of the format.
939
%
940
%  The format of the RegisterPCDImage method is:
941
%
942
%      RegisterPCDImage(void)
943
%
944
*/
945
ModuleExport void RegisterPCDImage(void)
946
5
{
947
5
  MagickInfo
948
5
    *entry;
949
950
5
  entry=SetMagickInfo("PCD");
951
5
  entry->decoder=(DecoderHandler) ReadPCDImage;
952
5
  entry->encoder=(EncoderHandler) WritePCDImage;
953
5
  entry->magick=(MagickHandler) IsPCD;
954
5
  entry->adjoin=False;
955
5
  entry->description="Photo CD";
956
5
  entry->seekable_stream=MagickTrue;
957
5
  entry->module="PCD";
958
5
  (void) RegisterMagickInfo(entry);
959
960
5
  entry=SetMagickInfo("PCDS");
961
5
  entry->decoder=(DecoderHandler) ReadPCDImage;
962
5
  entry->encoder=(EncoderHandler) WritePCDImage;
963
5
  entry->adjoin=False;
964
5
  entry->description="Photo CD";
965
5
  entry->seekable_stream=MagickTrue;
966
5
  entry->module="PCD";
967
5
  (void) RegisterMagickInfo(entry);
968
5
}
969

970
/*
971
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
972
%                                                                             %
973
%                                                                             %
974
%                                                                             %
975
%   U n r e g i s t e r P C D I m a g e                                       %
976
%                                                                             %
977
%                                                                             %
978
%                                                                             %
979
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
980
%
981
%  Method UnregisterPCDImage removes format registrations made by the
982
%  PCD module from the list of supported formats.
983
%
984
%  The format of the UnregisterPCDImage method is:
985
%
986
%      UnregisterPCDImage(void)
987
%
988
*/
989
ModuleExport void UnregisterPCDImage(void)
990
0
{
991
0
  (void) UnregisterMagickInfo("PCD");
992
0
  (void) UnregisterMagickInfo("PCDS");
993
0
}
994

995
/*
996
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
997
%                                                                             %
998
%                                                                             %
999
%                                                                             %
1000
%   W r i t e P C D I m a g e                                                 %
1001
%                                                                             %
1002
%                                                                             %
1003
%                                                                             %
1004
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1005
%
1006
%  Method WritePCDImage writes an image in the Photo CD encoded image
1007
%  format.
1008
%
1009
%  The format of the WritePCDImage method is:
1010
%
1011
%      unsigned int WritePCDImage(const ImageInfo *image_info,Image *image)
1012
%
1013
%  A description of each parameter follows.
1014
%
1015
%    o status: Method WritePCDImage return True if the image is written.
1016
%      False is returned is there is a memory shortage or if the image file
1017
%      fails to write.
1018
%
1019
%    o image_info: Specifies a pointer to a ImageInfo structure.
1020
%
1021
%    o image:  A pointer to an Image structure.
1022
%
1023
%
1024
*/
1025
1026
static unsigned int WritePCDTile(const ImageInfo *image_info,
1027
  Image *image,char *page_geometry,char *tile_geometry)
1028
411
{
1029
411
  Image
1030
411
    *downsample_image,
1031
411
    *tile_image;
1032
1033
411
  long
1034
411
    y;
1035
1036
411
  RectangleInfo
1037
411
    geometry;
1038
1039
411
  register const PixelPacket
1040
411
    *p,
1041
411
    *q;
1042
1043
411
  register long
1044
411
    i,
1045
411
    x;
1046
1047
411
  ARG_NOT_USED(image_info);
1048
1049
  /*
1050
    Scale image to tile size.
1051
  */
1052
411
  SetGeometry(image,&geometry);
1053
411
  (void) GetMagickGeometry(page_geometry,&geometry.x,&geometry.y,
1054
411
    &geometry.width,&geometry.height);
1055
411
  if ((geometry.width % 2) != 0)
1056
0
    geometry.width = geometry.width > 1 ? geometry.width-1 : geometry.width+1 ;
1057
411
  if ((geometry.height % 2) != 0)
1058
0
    geometry.height = geometry.height > 1 ? geometry.height-1 : geometry.height+1;
1059
411
  tile_image=ResizeImage(image,geometry.width,geometry.height,TriangleFilter,
1060
411
                         1.0,&image->exception);
1061
411
  if (tile_image == (Image *) NULL)
1062
0
    return(False);
1063
411
  (void) sscanf(page_geometry,"%lux%lu",&geometry.width,&geometry.height);
1064
411
  if ((tile_image->columns != geometry.width) ||
1065
0
      (tile_image->rows != geometry.height))
1066
411
    {
1067
411
      Image
1068
411
        *bordered_image;
1069
1070
411
      RectangleInfo
1071
411
        border_info;
1072
1073
      /*
1074
        Put a border around the image.
1075
      */
1076
411
      border_info.width=(geometry.width-tile_image->columns+1) >> 1;
1077
411
      border_info.height=(geometry.height-tile_image->rows+1) >> 1;
1078
411
      if (image->logging)
1079
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1080
0
                              "Adding %lux%lu border to %lux%lu tile ",
1081
0
                              border_info.width, border_info.height,
1082
0
                              image->columns, image->rows);
1083
411
      bordered_image=BorderImage(tile_image,&border_info,&image->exception);
1084
411
      DestroyImage(tile_image);
1085
411
      tile_image=(Image *) NULL;
1086
411
      if (bordered_image == (Image *) NULL)
1087
0
        return(MagickFail);
1088
411
      tile_image=bordered_image;
1089
411
    }
1090
411
  if (image->logging)
1091
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1092
0
                          "Transforming tile to %s from %lux%lu",
1093
0
                          tile_geometry,
1094
0
                          image->columns, image->rows);
1095
411
  (void) TransformImage(&tile_image,(char *) NULL,tile_geometry);
1096
411
  if (TransformColorspace(tile_image,YCCColorspace) == MagickFail)
1097
0
    {
1098
0
      ThrowException(&image->exception,CoderError,UnableToTransformColorspace,
1099
0
                     image->filename);
1100
0
      DestroyImage(tile_image);
1101
0
      return(MagickFail);
1102
0
    }
1103
411
  downsample_image=ResizeImage(tile_image,tile_image->columns/2,
1104
411
    tile_image->rows/2,TriangleFilter,1.0,&image->exception);
1105
411
  if (downsample_image == (Image *) NULL)
1106
0
    {
1107
0
      DestroyImage(tile_image);
1108
0
      return(MagickFail);
1109
0
    }
1110
  /*
1111
    Write tile to PCD file.
1112
  */
1113
61.7k
  for (y=0; y < (long) tile_image->rows; y+=2)
1114
61.3k
  {
1115
61.3k
    p=AcquireImagePixels(tile_image,0,y,tile_image->columns,2,
1116
61.3k
      &tile_image->exception);
1117
61.3k
    if (p == (const PixelPacket *) NULL)
1118
0
      break;
1119
70.7M
    for (x=0; x < (long) (tile_image->columns << 1); x++)
1120
70.7M
    {
1121
70.7M
      (void) WriteBlobByte(image,ScaleQuantumToChar(p->red));
1122
70.7M
      p++;
1123
70.7M
    }
1124
61.3k
    q=AcquireImagePixels(downsample_image,0,y >> 1,downsample_image->columns,
1125
61.3k
      1,&downsample_image->exception);
1126
61.3k
    if (q == (const PixelPacket *) NULL)
1127
0
      break;
1128
17.7M
    for (x=0; x < (long) downsample_image->columns; x++)
1129
17.6M
    {
1130
17.6M
      (void) WriteBlobByte(image,ScaleQuantumToChar(q->green));
1131
17.6M
      q++;
1132
17.6M
    }
1133
61.3k
    q=AcquireImagePixels(downsample_image,0,y >> 1,downsample_image->columns,
1134
61.3k
      1,&downsample_image->exception);
1135
61.3k
    if (q == (const PixelPacket *) NULL)
1136
0
      break;
1137
17.7M
    for (x=0; x < (long) downsample_image->columns; x++)
1138
17.6M
    {
1139
17.6M
      (void) WriteBlobByte(image,ScaleQuantumToChar(q->blue));
1140
17.6M
      q++;
1141
17.6M
    }
1142
61.3k
    if (QuantumTick(y,tile_image->rows))
1143
33.4k
      if (!MagickMonitorFormatted(y,tile_image->rows,&image->exception,
1144
33.4k
                                  SaveImageText,image->filename,
1145
33.4k
                                  image->columns,image->rows))
1146
0
        break;
1147
61.3k
  }
1148
842k
  for (i=0; i < 0x800; i++)
1149
841k
    (void) WriteBlobByte(image,'\0');
1150
411
  DestroyImage(downsample_image);
1151
411
  DestroyImage(tile_image);
1152
411
  return(MagickPass);
1153
411
}
1154
1155
static MagickPassFail WritePCDImage(const ImageInfo *image_info,Image *image)
1156
137
{
1157
137
  Image
1158
137
    *pcd_image;
1159
1160
137
  register long
1161
137
    i;
1162
1163
137
  unsigned int
1164
137
    status;
1165
1166
137
  assert(image_info != (const ImageInfo *) NULL);
1167
137
  assert(image_info->signature == MagickSignature);
1168
137
  assert(image != (Image *) NULL);
1169
137
  assert(image->signature == MagickSignature);
1170
137
  pcd_image=image;
1171
137
  if (image->columns < image->rows)
1172
83
    {
1173
83
      Image
1174
83
        *rotated_image;
1175
1176
      /*
1177
        Rotate portrait to landscape.
1178
      */
1179
83
      rotated_image=RotateImage(image,90.0,&image->exception);
1180
83
      if (rotated_image == (Image *) NULL)
1181
0
        return(False);
1182
83
      pcd_image=rotated_image;
1183
83
      DestroyBlob(rotated_image);
1184
83
      pcd_image->blob=ReferenceBlob(image->blob);
1185
83
    }
1186
  /*
1187
    Open output image file.
1188
  */
1189
137
  status=OpenBlob(image_info,pcd_image,WriteBinaryBlobMode,&image->exception);
1190
137
  if (status == False)
1191
137
    ThrowWriterException(FileOpenError,UnableToOpenFile,pcd_image);
1192
137
  if (TransformColorspace(pcd_image,RGBColorspace) == MagickFail)
1193
137
    ThrowWriterException(CoderError,UnableToTransformColorspace,pcd_image);
1194
  /*
1195
    Write PCD image header.
1196
  */
1197
4.52k
  for (i=0; i < 32; i++)
1198
4.38k
    (void) WriteBlobByte(pcd_image,0xff);
1199
685
  for (i=0; i < 4; i++)
1200
548
    (void) WriteBlobByte(pcd_image,0x0e);
1201
1.23k
  for (i=0; i < 8; i++)
1202
1.09k
    (void) WriteBlobByte(pcd_image,'\0');
1203
685
  for (i=0; i < 4; i++)
1204
548
    (void) WriteBlobByte(pcd_image,0x01);
1205
685
  for (i=0; i < 4; i++)
1206
548
    (void) WriteBlobByte(pcd_image,0x05);
1207
1.23k
  for (i=0; i < 8; i++)
1208
1.09k
    (void) WriteBlobByte(pcd_image,'\0');
1209
685
  for (i=0; i < 4; i++)
1210
548
    (void) WriteBlobByte(pcd_image,0x0A);
1211
5.06k
  for (i=0; i < 36; i++)
1212
4.93k
    (void) WriteBlobByte(pcd_image,'\0');
1213
685
  for (i=0; i < 4; i++)
1214
548
    (void) WriteBlobByte(pcd_image,0x01);
1215
266k
  for (i=0; i < 1944; i++)
1216
266k
    (void) WriteBlobByte(pcd_image,'\0');
1217
137
  (void) WriteBlob(pcd_image,7,"PCD_IPI");
1218
137
  (void) WriteBlobByte(pcd_image,0x06);
1219
209k
  for (i=0; i < 1530; i++)
1220
209k
    (void) WriteBlobByte(pcd_image,'\0');
1221
137
  if (image->columns < image->rows)
1222
83
    (void) WriteBlobByte(pcd_image,'\1');
1223
54
  else
1224
54
    (void) WriteBlobByte(pcd_image,'\0');
1225
631k
  for (i=0; i < (3*0x800-1539); i++)
1226
630k
    (void) WriteBlobByte(pcd_image,'\0');
1227
  /*
1228
    Write PCD tiles.
1229
  */
1230
137
  status=WritePCDTile(image_info,pcd_image,(char *) "768x512>",
1231
137
    (char *) "192x128");
1232
137
  status&=WritePCDTile(image_info,pcd_image,(char *) "768x512>",
1233
137
    (char *) "384x256");
1234
137
  status&=WritePCDTile(image_info,pcd_image,(char *) "768x512>",
1235
137
    (char *) "768x512");
1236
137
  if (GetBlobStatus(pcd_image) != 0)
1237
0
    status=MagickFail;
1238
137
  status &= CloseBlob(pcd_image);
1239
137
  if (pcd_image != image)
1240
83
    DestroyImage(pcd_image);
1241
137
  return(status);
1242
137
}