Coverage Report

Created: 2025-11-14 07:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/imagemagick/coders/pcx.c
Line
Count
Source
1
/*
2
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3
%                                                                             %
4
%                                                                             %
5
%                                                                             %
6
%                            PPPP    CCCC  X   X                              %
7
%                            P   P  C       X X                               %
8
%                            PPPP   C        X                                %
9
%                            P      C       X X                               %
10
%                            P       CCCC  X   X                              %
11
%                                                                             %
12
%                                                                             %
13
%                Read/Write ZSoft IBM PC Paintbrush Image Format              %
14
%                                                                             %
15
%                              Software Design                                %
16
%                                   Cristy                                    %
17
%                                 July 1992                                   %
18
%                                                                             %
19
%                                                                             %
20
%  Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization         %
21
%  dedicated to making software imaging solutions freely available.           %
22
%                                                                             %
23
%  You may not use this file except in compliance with the License.  You may  %
24
%  obtain a copy of the License at                                            %
25
%                                                                             %
26
%    https://imagemagick.org/script/license.php                               %
27
%                                                                             %
28
%  Unless required by applicable law or agreed to in writing, software        %
29
%  distributed under the License is distributed on an "AS IS" BASIS,          %
30
%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31
%  See the License for the specific language governing permissions and        %
32
%  limitations under the License.                                             %
33
%                                                                             %
34
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35
%
36
%
37
*/
38

39
/*
40
  Include declarations.
41
*/
42
#include "MagickCore/studio.h"
43
#include "MagickCore/attribute.h"
44
#include "MagickCore/blob.h"
45
#include "MagickCore/blob-private.h"
46
#include "MagickCore/cache.h"
47
#include "MagickCore/color.h"
48
#include "MagickCore/color-private.h"
49
#include "MagickCore/colormap.h"
50
#include "MagickCore/colorspace.h"
51
#include "MagickCore/colorspace-private.h"
52
#include "MagickCore/exception.h"
53
#include "MagickCore/exception-private.h"
54
#include "MagickCore/image.h"
55
#include "MagickCore/image-private.h"
56
#include "MagickCore/list.h"
57
#include "MagickCore/magick.h"
58
#include "MagickCore/memory_.h"
59
#include "MagickCore/memory-private.h"
60
#include "MagickCore/monitor.h"
61
#include "MagickCore/monitor-private.h"
62
#include "MagickCore/pixel-accessor.h"
63
#include "MagickCore/quantum-private.h"
64
#include "MagickCore/static.h"
65
#include "MagickCore/string_.h"
66
#include "MagickCore/module.h"
67

68
/*
69
  Typedef declarations.
70
*/
71
typedef struct _PCXInfo
72
{
73
  unsigned char
74
    identifier,
75
    version,
76
    encoding,
77
    bits_per_pixel;
78
79
  unsigned short
80
    left,
81
    top,
82
    right,
83
    bottom,
84
    horizontal_resolution,
85
    vertical_resolution;
86
87
  unsigned char
88
    reserved,
89
    planes;
90
91
  unsigned short
92
    bytes_per_line,
93
    palette_info,
94
    horizontal_screensize,
95
    vertical_screensize;
96
97
  unsigned char
98
    colormap_signature;
99
} PCXInfo;
100

101
/*
102
  Forward declarations.
103
*/
104
static MagickBooleanType
105
  WritePCXImage(const ImageInfo *,Image *,ExceptionInfo *);
106

107
/*
108
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
109
%                                                                             %
110
%                                                                             %
111
%                                                                             %
112
%   I s D C X                                                                 %
113
%                                                                             %
114
%                                                                             %
115
%                                                                             %
116
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
117
%
118
%  IsDCX() returns MagickTrue if the image format type, identified by the
119
%  magick string, is DCX.
120
%
121
%  The format of the IsDCX method is:
122
%
123
%      MagickBooleanType IsDCX(const unsigned char *magick,const size_t length)
124
%
125
%  A description of each parameter follows:
126
%
127
%    o magick: compare image format pattern against these bytes.
128
%
129
%    o length: Specifies the length of the magick string.
130
%
131
*/
132
static MagickBooleanType IsDCX(const unsigned char *magick,const size_t length)
133
0
{
134
0
  if (length < 4)
135
0
    return(MagickFalse);
136
0
  if (memcmp(magick,"\261\150\336\72",4) == 0)
137
0
    return(MagickTrue);
138
0
  return(MagickFalse);
139
0
}
140

141
/*
142
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
143
%                                                                             %
144
%                                                                             %
145
%                                                                             %
146
%   I s P C X                                                                 %
147
%                                                                             %
148
%                                                                             %
149
%                                                                             %
150
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
151
%
152
%  IsPCX() returns MagickTrue if the image format type, identified by the
153
%  magick string, is PCX.
154
%
155
%  The format of the IsPCX method is:
156
%
157
%      MagickBooleanType IsPCX(const unsigned char *magick,const size_t length)
158
%
159
%  A description of each parameter follows:
160
%
161
%    o magick: compare image format pattern against these bytes.
162
%
163
%    o length: Specifies the length of the magick string.
164
%
165
*/
166
static MagickBooleanType IsPCX(const unsigned char *magick,const size_t length)
167
0
{
168
0
  if (length < 2)
169
0
    return(MagickFalse);
170
0
  if (memcmp(magick,"\012\002",2) == 0)
171
0
    return(MagickTrue);
172
0
  if (memcmp(magick,"\012\005",2) == 0)
173
0
    return(MagickTrue);
174
0
  return(MagickFalse);
175
0
}
176

177
/*
178
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
179
%                                                                             %
180
%                                                                             %
181
%                                                                             %
182
%   R e a d P C X I m a g e                                                   %
183
%                                                                             %
184
%                                                                             %
185
%                                                                             %
186
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
187
%
188
%  ReadPCXImage() reads a ZSoft IBM PC Paintbrush file and returns it.
189
%  It allocates the memory necessary for the new Image structure and returns
190
%  a pointer to the new image.
191
%
192
%  The format of the ReadPCXImage method is:
193
%
194
%      Image *ReadPCXImage(const ImageInfo *image_info,ExceptionInfo *exception)
195
%
196
%  A description of each parameter follows:
197
%
198
%    o image_info: the image info.
199
%
200
%    o exception: return any errors or warnings in this structure.
201
%
202
*/
203
static Image *ReadPCXImage(const ImageInfo *image_info,ExceptionInfo *exception)
204
1.29k
{
205
3.67k
#define MaxNumberScenes  1024
206
1.29k
#define ThrowPCXException(severity,tag) \
207
764
{ \
208
764
  if (scanline != (unsigned char *) NULL) \
209
764
    scanline=(unsigned char *) RelinquishMagickMemory(scanline); \
210
764
  if (pixel_info != (MemoryInfo *) NULL) \
211
764
    pixel_info=RelinquishVirtualMemory(pixel_info); \
212
764
  if (page_table != (MagickOffsetType *) NULL) \
213
764
    page_table=(MagickOffsetType *) RelinquishMagickMemory(page_table); \
214
764
  ThrowReaderException(severity,tag); \
215
0
}
216
217
1.29k
  Image
218
1.29k
    *image;
219
220
1.29k
  int
221
1.29k
    bits,
222
1.29k
    id,
223
1.29k
    mask;
224
225
1.29k
  MagickBooleanType
226
1.29k
    status;
227
228
1.29k
  MagickOffsetType
229
1.29k
    offset,
230
1.29k
    *page_table;
231
232
1.29k
  MemoryInfo
233
1.29k
    *pixel_info;
234
235
1.29k
  PCXInfo
236
1.29k
    pcx_info;
237
238
1.29k
  Quantum
239
1.29k
    *q;
240
241
1.29k
  size_t
242
1.29k
    one,
243
1.29k
    pcx_packets;
244
245
1.29k
  ssize_t
246
1.29k
    count,
247
1.29k
    i,
248
1.29k
    x,
249
1.29k
    y;
250
251
1.29k
  unsigned char
252
1.29k
    *p,
253
1.29k
    packet,
254
1.29k
    pcx_colormap[768],
255
1.29k
    *pixels,
256
1.29k
    *r,
257
1.29k
    *scanline;
258
259
  /*
260
    Open image file.
261
  */
262
1.29k
  assert(image_info != (const ImageInfo *) NULL);
263
1.29k
  assert(image_info->signature == MagickCoreSignature);
264
1.29k
  assert(exception != (ExceptionInfo *) NULL);
265
1.29k
  assert(exception->signature == MagickCoreSignature);
266
1.29k
  if (IsEventLogging() != MagickFalse)
267
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
268
0
      image_info->filename);
269
1.29k
  image=AcquireImage(image_info,exception);
270
1.29k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
271
1.29k
  if (status == MagickFalse)
272
0
    {
273
0
      image=DestroyImageList(image);
274
0
      return((Image *) NULL);
275
0
    }
276
  /*
277
    Determine if this a PCX file.
278
  */
279
1.29k
  page_table=(MagickOffsetType *) NULL;
280
1.29k
  scanline=(unsigned char *) NULL;
281
1.29k
  pixel_info=(MemoryInfo *) NULL;
282
1.29k
  if (LocaleCompare(image_info->magick,"DCX") == 0)
283
65
    {
284
65
      size_t
285
65
        magic;
286
287
      /*
288
        Read the DCX page table.
289
      */
290
65
      magic=ReadBlobLSBLong(image);
291
65
      if (magic != 987654321)
292
65
        ThrowPCXException(CorruptImageError,"ImproperImageHeader");
293
65
      page_table=(MagickOffsetType *) AcquireQuantumMemory(MaxNumberScenes,
294
65
        sizeof(*page_table));
295
65
      if (page_table == (MagickOffsetType *) NULL)
296
65
        ThrowPCXException(ResourceLimitError,"MemoryAllocationFailed");
297
1.92k
      for (id=0; id < MaxNumberScenes; id++)
298
1.92k
      {
299
1.92k
        page_table[id]=(MagickOffsetType) ReadBlobLSBLong(image);
300
1.92k
        if (page_table[id] == 0)
301
64
          break;
302
1.92k
      }
303
65
    }
304
1.29k
  if (page_table != (MagickOffsetType *) NULL)
305
65
    {
306
65
      offset=SeekBlob(image,(MagickOffsetType) page_table[0],SEEK_SET);
307
65
      if (offset < 0)
308
65
        ThrowPCXException(CorruptImageError,"ImproperImageHeader");
309
65
    }
310
1.29k
  count=ReadBlob(image,1,&pcx_info.identifier);
311
1.29k
  for (id=1; id < MaxNumberScenes; id++)
312
1.29k
  {
313
1.29k
    int
314
1.29k
      bits_per_pixel;
315
316
    /*
317
      Verify PCX identifier.
318
    */
319
1.29k
    pcx_info.version=(unsigned char) ReadBlobByte(image);
320
1.29k
    if ((count != 1) || (pcx_info.identifier != 0x0a))
321
1.04k
      ThrowPCXException(CorruptImageError,"ImproperImageHeader");
322
1.04k
    pcx_info.encoding=(unsigned char) ReadBlobByte(image);
323
1.04k
    bits_per_pixel=ReadBlobByte(image);
324
1.04k
    if (bits_per_pixel == -1)
325
1.03k
      ThrowPCXException(CorruptImageError,"ImproperImageHeader");
326
1.03k
    pcx_info.bits_per_pixel=(unsigned char) bits_per_pixel;
327
1.03k
    pcx_info.left=ReadBlobLSBShort(image);
328
1.03k
    pcx_info.top=ReadBlobLSBShort(image);
329
1.03k
    pcx_info.right=ReadBlobLSBShort(image);
330
1.03k
    pcx_info.bottom=ReadBlobLSBShort(image);
331
1.03k
    pcx_info.horizontal_resolution=ReadBlobLSBShort(image);
332
1.03k
    pcx_info.vertical_resolution=ReadBlobLSBShort(image);
333
1.03k
    if (EOFBlob(image) != MagickFalse)
334
1.01k
      ThrowPCXException(CorruptImageError,"UnexpectedEndOfFile");
335
    /*
336
      Read PCX raster colormap.
337
    */
338
1.01k
    if ((pcx_info.right < pcx_info.left) || (pcx_info.bottom < pcx_info.top) ||
339
1.00k
        ((pcx_info.bits_per_pixel != 1) && (pcx_info.bits_per_pixel != 2) &&
340
418
         (pcx_info.bits_per_pixel != 4) && (pcx_info.bits_per_pixel != 8)))
341
987
      ThrowPCXException(CorruptImageError,"ImproperImageHeader");
342
987
    image->columns=(size_t) (pcx_info.right-pcx_info.left)+1UL;
343
987
    image->rows=(size_t) (pcx_info.bottom-pcx_info.top)+1UL;
344
987
    image->depth=pcx_info.bits_per_pixel;
345
987
    image->units=PixelsPerInchResolution;
346
987
    image->resolution.x=(double) pcx_info.horizontal_resolution;
347
987
    image->resolution.y=(double) pcx_info.vertical_resolution;
348
987
    image->colors=16;
349
987
    if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
350
0
      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
351
0
        break;
352
987
    if ((MagickSizeType) (image->columns*image->rows/255) > GetBlobSize(image))
353
942
      ThrowPCXException(CorruptImageError,"InsufficientImageDataInFile");
354
942
    status=SetImageExtent(image,image->columns,image->rows,exception);
355
942
    if (status == MagickFalse)
356
889
      ThrowPCXException(exception->severity,exception->reason);
357
889
    (void) SetImageBackgroundColor(image,exception);
358
889
    (void) memset(pcx_colormap,0,sizeof(pcx_colormap));
359
889
    count=ReadBlob(image,3*image->colors,pcx_colormap);
360
889
    if (count != (ssize_t) (3*image->colors))
361
780
      ThrowPCXException(CorruptImageError,"ImproperImageHeader");
362
780
    pcx_info.reserved=(unsigned char) ReadBlobByte(image);
363
780
    pcx_info.planes=(unsigned char) ReadBlobByte(image);
364
780
    if (pcx_info.planes == 0)
365
772
      ThrowPCXException(CorruptImageError,"ImproperImageHeader");
366
772
    if (pcx_info.planes > 6)
367
753
      ThrowPCXException(CorruptImageError,"ImproperImageHeader");
368
753
    if ((pcx_info.bits_per_pixel*pcx_info.planes) >= 64)
369
753
      ThrowPCXException(CorruptImageError,"ImproperImageHeader");
370
753
    one=1;
371
753
    if ((pcx_info.bits_per_pixel != 8) || (pcx_info.planes == 1))
372
613
      if ((pcx_info.version == 3) || (pcx_info.version == 5) ||
373
411
          ((pcx_info.bits_per_pixel*pcx_info.planes) == 1))
374
318
        image->colors=(size_t) MagickMin(one << (1UL*
375
753
          (pcx_info.bits_per_pixel*pcx_info.planes)),256UL);
376
753
    if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
377
753
      ThrowPCXException(ResourceLimitError,"MemoryAllocationFailed");
378
753
    if ((pcx_info.bits_per_pixel >= 8) && (pcx_info.planes != 1))
379
140
      image->storage_class=DirectClass;
380
753
    p=pcx_colormap;
381
20.8k
    for (i=0; i < (ssize_t) image->colors; i++)
382
20.0k
    {
383
20.0k
      image->colormap[i].red=ScaleCharToQuantum(*p++);
384
20.0k
      image->colormap[i].green=ScaleCharToQuantum(*p++);
385
20.0k
      image->colormap[i].blue=ScaleCharToQuantum(*p++);
386
20.0k
    }
387
753
    pcx_info.bytes_per_line=ReadBlobLSBShort(image);
388
753
    pcx_info.palette_info=ReadBlobLSBShort(image);
389
753
    pcx_info.horizontal_screensize=ReadBlobLSBShort(image);
390
753
    pcx_info.vertical_screensize=ReadBlobLSBShort(image);
391
41.4k
    for (i=0; i < 54; i++)
392
40.6k
      (void) ReadBlobByte(image);
393
    /*
394
      Read image data.
395
    */
396
753
    if (HeapOverflowSanityCheckGetSize(image->rows,(size_t) pcx_info.bytes_per_line,&pcx_packets) != MagickFalse)
397
728
      ThrowPCXException(CorruptImageError,"ImproperImageHeader");
398
728
    if (HeapOverflowSanityCheckGetSize(pcx_packets,(size_t) pcx_info.planes,&pcx_packets) != MagickFalse)
399
728
      ThrowPCXException(CorruptImageError,"ImproperImageHeader");
400
728
    if ((size_t) (pcx_info.bits_per_pixel*pcx_info.planes*image->columns) > (pcx_packets*8U))
401
710
      ThrowPCXException(CorruptImageError,"ImproperImageHeader");
402
710
    if ((MagickSizeType) (pcx_packets/32+128) > GetBlobSize(image))
403
645
      ThrowPCXException(CorruptImageError,"ImproperImageHeader");
404
645
    scanline=(unsigned char *) AcquireQuantumMemory(MagickMax(image->columns,
405
645
      pcx_info.bytes_per_line),MagickMax(pcx_info.planes,8)*sizeof(*scanline));
406
645
    pixel_info=AcquireVirtualMemory(pcx_packets,2*sizeof(*pixels));
407
645
    if ((scanline == (unsigned char *) NULL) ||
408
645
        (pixel_info == (MemoryInfo *) NULL))
409
0
      {
410
0
        if (scanline != (unsigned char *) NULL)
411
0
          scanline=(unsigned char *) RelinquishMagickMemory(scanline);
412
0
        if (pixel_info != (MemoryInfo *) NULL)
413
0
          pixel_info=RelinquishVirtualMemory(pixel_info);
414
0
        ThrowPCXException(ResourceLimitError,"MemoryAllocationFailed");
415
0
      }
416
645
    (void) memset(scanline,0,(size_t) MagickMax(image->columns,
417
645
      pcx_info.bytes_per_line)*MagickMax(pcx_info.planes,8)*sizeof(*scanline));
418
645
    pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
419
645
    (void) memset(pixels,0,(size_t) pcx_packets*(2*sizeof(*pixels)));
420
    /*
421
      Uncompress image data.
422
    */
423
645
    p=pixels;
424
645
    if (pcx_info.encoding == 0)
425
7.22k
      while (pcx_packets != 0)
426
7.20k
      {
427
7.20k
        packet=(unsigned char) ReadBlobByte(image);
428
7.20k
        if (EOFBlob(image) != MagickFalse)
429
7.16k
          ThrowPCXException(CorruptImageError,"UnexpectedEndOfFile");
430
7.16k
        *p++=packet;
431
7.16k
        pcx_packets--;
432
7.16k
      }
433
589
    else
434
88.4k
      while (pcx_packets != 0)
435
87.9k
      {
436
87.9k
        packet=(unsigned char) ReadBlobByte(image);
437
87.9k
        if (EOFBlob(image) != MagickFalse)
438
87.8k
          ThrowPCXException(CorruptImageError,"UnexpectedEndOfFile");
439
87.8k
        if ((packet & 0xc0) != 0xc0)
440
52.5k
          {
441
52.5k
            *p++=packet;
442
52.5k
            pcx_packets--;
443
52.5k
            continue;
444
52.5k
          }
445
35.3k
        count=(ssize_t) (packet & 0x3f);
446
35.3k
        packet=(unsigned char) ReadBlobByte(image);
447
35.3k
        if (EOFBlob(image) != MagickFalse)
448
35.3k
          ThrowPCXException(CorruptImageError,"UnexpectedEndOfFile");
449
1.94M
        for ( ; count != 0; count--)
450
1.91M
        {
451
1.91M
          *p++=packet;
452
1.91M
          pcx_packets--;
453
1.91M
          if (pcx_packets == 0)
454
443
            break;
455
1.91M
        }
456
35.3k
      }
457
532
    if (image->storage_class == DirectClass)
458
106
      image->alpha_trait=pcx_info.planes > 3 ? BlendPixelTrait :
459
106
        UndefinedPixelTrait;
460
426
    else
461
426
      if ((pcx_info.version == 5) ||
462
300
          ((pcx_info.bits_per_pixel*pcx_info.planes) == 1))
463
211
        {
464
          /*
465
            Initialize image colormap.
466
          */
467
211
          if (image->colors > 256)
468
211
            ThrowPCXException(CorruptImageError,"ColormapExceeds256Colors");
469
211
          if ((pcx_info.bits_per_pixel*pcx_info.planes) == 1)
470
90
            {
471
              /*
472
                Monochrome colormap.
473
              */
474
90
              image->colormap[0].red=(Quantum) 0;
475
90
              image->colormap[0].green=(Quantum) 0;
476
90
              image->colormap[0].blue=(Quantum) 0;
477
90
              image->colormap[1].red=QuantumRange;
478
90
              image->colormap[1].green=QuantumRange;
479
90
              image->colormap[1].blue=QuantumRange;
480
90
            }
481
121
          else
482
121
            if (image->colors > 16)
483
72
              {
484
                /*
485
                  256 color images have their color map at the end of the file.
486
                */
487
72
                offset=SeekBlob(image,(MagickOffsetType) GetBlobSize(image)-3*
488
72
                  image->colors-1,SEEK_SET);
489
72
                pcx_info.colormap_signature=(unsigned char) ReadBlobByte(image);
490
72
                count=ReadBlob(image,3*image->colors,pcx_colormap);
491
72
                p=pcx_colormap;
492
7.36k
                for (i=0; i < (ssize_t) image->colors; i++)
493
7.29k
                {
494
7.29k
                  image->colormap[i].red=ScaleCharToQuantum(*p++);
495
7.29k
                  image->colormap[i].green=ScaleCharToQuantum(*p++);
496
7.29k
                  image->colormap[i].blue=ScaleCharToQuantum(*p++);
497
7.29k
                }
498
72
            }
499
211
        }
500
    /*
501
      Convert PCX raster image to pixel packets.
502
    */
503
80.8k
    for (y=0; y < (ssize_t) image->rows; y++)
504
80.3k
    {
505
80.3k
      p=pixels+(y*pcx_info.bytes_per_line*pcx_info.planes);
506
80.3k
      q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
507
80.3k
      if (q == (Quantum *) NULL)
508
0
        break;
509
80.3k
      r=scanline;
510
80.3k
      if (image->storage_class == DirectClass)
511
66.8k
        for (i=0; i < pcx_info.planes; i++)
512
52.8k
        {
513
52.8k
          r=scanline+i;
514
799k
          for (x=0; x < (ssize_t) pcx_info.bytes_per_line; x++)
515
746k
          {
516
746k
            switch (i)
517
746k
            {
518
256k
              case 0:
519
256k
              {
520
256k
                *r=(*p++);
521
256k
                break;
522
0
              }
523
256k
              case 1:
524
256k
              {
525
256k
                *r=(*p++);
526
256k
                break;
527
0
              }
528
81.7k
              case 2:
529
81.7k
              {
530
81.7k
                *r=(*p++);
531
81.7k
                break;
532
0
              }
533
80.5k
              case 3:
534
151k
              default:
535
151k
              {
536
151k
                *r=(*p++);
537
151k
                break;
538
80.5k
              }
539
746k
            }
540
746k
            r+=(ptrdiff_t) pcx_info.planes;
541
746k
          }
542
52.8k
        }
543
66.3k
      else
544
66.3k
        if (pcx_info.planes > 1)
545
5.54k
          {
546
1.92M
            for (x=0; x < (ssize_t) image->columns; x++)
547
1.92M
              *r++=0;
548
21.4k
            for (i=0; i < pcx_info.planes; i++)
549
15.9k
            {
550
15.9k
              r=scanline;
551
404k
              for (x=0; x < (ssize_t) pcx_info.bytes_per_line; x++)
552
388k
              {
553
388k
                 bits=(*p++);
554
3.49M
                 for (mask=0x80; mask != 0; mask>>=1)
555
3.10M
                 {
556
3.10M
                   if (bits & mask)
557
2.87M
                     *r|=1 << i;
558
3.10M
                   r++;
559
3.10M
                 }
560
388k
               }
561
15.9k
            }
562
5.54k
          }
563
60.7k
        else
564
60.7k
          switch (pcx_info.bits_per_pixel)
565
60.7k
          {
566
6.83k
            case 1:
567
6.83k
            {
568
6.83k
              ssize_t
569
6.83k
                bit;
570
571
289k
              for (x=0; x < ((ssize_t) image->columns-7); x+=8)
572
282k
              {
573
2.54M
                for (bit=7; bit >= 0; bit--)
574
2.25M
                  *r++=(unsigned char) ((*p) & (0x01 << bit) ? 0x00 : 0x01);
575
282k
                p++;
576
282k
              }
577
6.83k
              if ((image->columns % 8) != 0)
578
3.62k
                {
579
23.7k
                  for (bit=7; bit >= (ssize_t) (8-(image->columns % 8)); bit--)
580
20.1k
                    *r++=(unsigned char) ((*p) & (0x01 << bit) ? 0x00 : 0x01);
581
3.62k
                  p++;
582
3.62k
                }
583
6.83k
              break;
584
0
            }
585
48.3k
            case 2:
586
48.3k
            {
587
3.69M
              for (x=0; x < ((ssize_t) image->columns-3); x+=4)
588
3.64M
              {
589
3.64M
                *r++=(*p >> 6) & 0x3;
590
3.64M
                *r++=(*p >> 4) & 0x3;
591
3.64M
                *r++=(*p >> 2) & 0x3;
592
3.64M
                *r++=(*p) & 0x3;
593
3.64M
                p++;
594
3.64M
              }
595
48.3k
              if ((image->columns % 4) != 0)
596
45.3k
                {
597
157k
                  for (i=3; i >= (ssize_t) (4-(image->columns % 4)); i--)
598
112k
                    *r++=(unsigned char) ((*p >> (i*2)) & 0x03);
599
45.3k
                  p++;
600
45.3k
                }
601
48.3k
              break;
602
0
            }
603
4.94k
            case 4:
604
4.94k
            {
605
780k
              for (x=0; x < ((ssize_t) image->columns-1); x+=2)
606
775k
              {
607
775k
                *r++=(*p >> 4) & 0xf;
608
775k
                *r++=(*p) & 0xf;
609
775k
                p++;
610
775k
              }
611
4.94k
              if ((image->columns % 2) != 0)
612
2.58k
                *r++=(*p++ >> 4) & 0xf;
613
4.94k
              break;
614
0
            }
615
672
            case 8:
616
672
            {
617
672
              (void) memcpy(r,p,image->columns);
618
672
              break;
619
0
            }
620
0
            default:
621
0
              break;
622
60.7k
          }
623
      /*
624
        Transfer image scanline.
625
      */
626
80.3k
      r=scanline;
627
28.0M
      for (x=0; x < (ssize_t) image->columns; x++)
628
28.0M
      {
629
28.0M
        if (image->storage_class == PseudoClass)
630
20.5M
          SetPixelIndex(image,*r++,q);
631
7.46M
        else
632
7.46M
          {
633
7.46M
            SetPixelRed(image,ScaleCharToQuantum(*r++),q);
634
7.46M
            SetPixelGreen(image,ScaleCharToQuantum(*r++),q);
635
7.46M
            SetPixelBlue(image,ScaleCharToQuantum(*r++),q);
636
7.46M
            if (image->alpha_trait != UndefinedPixelTrait)
637
7.36M
              SetPixelAlpha(image,ScaleCharToQuantum(*r++),q);
638
7.46M
          }
639
28.0M
        q+=(ptrdiff_t) GetPixelChannels(image);
640
28.0M
      }
641
80.3k
      if (SyncAuthenticPixels(image,exception) == MagickFalse)
642
0
        break;
643
80.3k
      if (image->previous == (Image *) NULL)
644
80.3k
        {
645
80.3k
          status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
646
80.3k
            image->rows);
647
80.3k
          if (status == MagickFalse)
648
0
            break;
649
80.3k
        }
650
80.3k
    }
651
532
    if (image->storage_class == PseudoClass)
652
426
      (void) SyncImage(image,exception);
653
532
    scanline=(unsigned char *) RelinquishMagickMemory(scanline);
654
532
    pixel_info=RelinquishVirtualMemory(pixel_info);
655
532
    if (EOFBlob(image) != MagickFalse)
656
32
      {
657
32
        ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
658
32
          image->filename);
659
32
        break;
660
32
      }
661
    /*
662
      Proceed to next image.
663
    */
664
500
    if (image_info->number_scenes != 0)
665
0
      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
666
0
        break;
667
500
    if (page_table == (MagickOffsetType *) NULL)
668
499
      break;
669
1
    if (page_table[id] == 0)
670
0
      break;
671
1
    offset=SeekBlob(image,(MagickOffsetType) page_table[id],SEEK_SET);
672
1
    if (offset < 0)
673
1
      ThrowPCXException(CorruptImageError,"ImproperImageHeader");
674
1
    count=ReadBlob(image,1,&pcx_info.identifier);
675
1
    if ((count != 0) && (pcx_info.identifier == 0x0a))
676
0
      {
677
        /*
678
          Allocate next image structure.
679
        */
680
0
        AcquireNextImage(image_info,image,exception);
681
0
        if (GetNextImageInList(image) == (Image *) NULL)
682
0
          {
683
0
            status=MagickFalse;
684
0
            break;
685
0
          }
686
0
        image=SyncNextImageInList(image);
687
0
        status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
688
0
          GetBlobSize(image));
689
0
        if (status == MagickFalse)
690
0
          break;
691
0
      }
692
1
  }
693
531
  if (page_table != (MagickOffsetType *) NULL)
694
0
    page_table=(MagickOffsetType *) RelinquishMagickMemory(page_table);
695
531
  if (CloseBlob(image) == MagickFalse)
696
0
    status=MagickFalse;
697
531
  if (status == MagickFalse)
698
0
    return(DestroyImageList(image));
699
531
  return(GetFirstImageInList(image));
700
531
}
701

702
/*
703
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
704
%                                                                             %
705
%                                                                             %
706
%                                                                             %
707
%   R e g i s t e r P C X I m a g e                                           %
708
%                                                                             %
709
%                                                                             %
710
%                                                                             %
711
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
712
%
713
%  RegisterPCXImage() adds attributes for the PCX image format to
714
%  the list of supported formats.  The attributes include the image format
715
%  tag, a method to read and/or write the format, whether the format
716
%  supports the saving of more than one frame to the same file or blob,
717
%  whether the format supports native in-memory I/O, and a brief
718
%  description of the format.
719
%
720
%  The format of the RegisterPCXImage method is:
721
%
722
%      size_t RegisterPCXImage(void)
723
%
724
*/
725
ModuleExport size_t RegisterPCXImage(void)
726
9
{
727
9
  MagickInfo
728
9
    *entry;
729
730
9
  entry=AcquireMagickInfo("PCX","DCX","ZSoft IBM PC multi-page Paintbrush");
731
9
  entry->decoder=(DecodeImageHandler *) ReadPCXImage;
732
9
  entry->encoder=(EncodeImageHandler *) WritePCXImage;
733
9
  entry->flags|=CoderDecoderSeekableStreamFlag;
734
9
  entry->flags|=CoderEncoderSeekableStreamFlag;
735
9
  entry->magick=(IsImageFormatHandler *) IsDCX;
736
9
  (void) RegisterMagickInfo(entry);
737
9
  entry=AcquireMagickInfo("PCX","PCX","ZSoft IBM PC Paintbrush");
738
9
  entry->decoder=(DecodeImageHandler *) ReadPCXImage;
739
9
  entry->encoder=(EncodeImageHandler *) WritePCXImage;
740
9
  entry->magick=(IsImageFormatHandler *) IsPCX;
741
9
  entry->flags^=CoderAdjoinFlag;
742
9
  entry->flags|=CoderDecoderSeekableStreamFlag;
743
9
  entry->flags|=CoderEncoderSeekableStreamFlag;
744
9
  (void) RegisterMagickInfo(entry);
745
9
  return(MagickImageCoderSignature);
746
9
}
747

748
/*
749
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
750
%                                                                             %
751
%                                                                             %
752
%                                                                             %
753
%   U n r e g i s t e r P C X I m a g e                                       %
754
%                                                                             %
755
%                                                                             %
756
%                                                                             %
757
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
758
%
759
%  UnregisterPCXImage() removes format registrations made by the
760
%  PCX module from the list of supported formats.
761
%
762
%  The format of the UnregisterPCXImage method is:
763
%
764
%      UnregisterPCXImage(void)
765
%
766
*/
767
ModuleExport void UnregisterPCXImage(void)
768
0
{
769
0
  (void) UnregisterMagickInfo("DCX");
770
0
  (void) UnregisterMagickInfo("PCX");
771
0
}
772

773
/*
774
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
775
%                                                                             %
776
%                                                                             %
777
%                                                                             %
778
%   W r i t e P C X I m a g e                                                 %
779
%                                                                             %
780
%                                                                             %
781
%                                                                             %
782
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
783
%
784
%  WritePCXImage() writes an image in the ZSoft IBM PC Paintbrush file
785
%  format.
786
%
787
%  The format of the WritePCXImage method is:
788
%
789
%      MagickBooleanType WritePCXImage(const ImageInfo *image_info,
790
%        Image *image,ExceptionInfo *exception)
791
%
792
%  A description of each parameter follows.
793
%
794
%    o image_info: the image info.
795
%
796
%    o image:  The image.
797
%
798
%    o exception: return any errors or warnings in this structure.
799
%
800
*/
801
802
static MagickBooleanType PCXWritePixels(PCXInfo *pcx_info,
803
  const unsigned char *pixels,Image *image)
804
76.0k
{
805
76.0k
  const unsigned char
806
76.0k
    *q;
807
808
76.0k
  ssize_t
809
76.0k
    count,
810
76.0k
    i,
811
76.0k
    x;
812
813
76.0k
  unsigned char
814
76.0k
    packet,
815
76.0k
    previous;
816
817
76.0k
  q=pixels;
818
186k
  for (i=0; i < (ssize_t) pcx_info->planes; i++)
819
110k
  {
820
110k
    if (pcx_info->encoding == 0)
821
0
      {
822
0
        for (x=0; x < (ssize_t) pcx_info->bytes_per_line; x++)
823
0
          (void) WriteBlobByte(image,(unsigned char) (*q++));
824
0
      }
825
110k
    else
826
110k
      {
827
110k
        previous=(*q++);
828
110k
        count=1;
829
47.4M
        for (x=0; x < (ssize_t) (pcx_info->bytes_per_line-1); x++)
830
47.3M
        {
831
47.3M
          packet=(*q++);
832
47.3M
          if ((packet == previous) && (count < 63))
833
36.0M
            {
834
36.0M
              count++;
835
36.0M
              continue;
836
36.0M
            }
837
11.2M
          if ((count > 1) || ((previous & 0xc0) == 0xc0))
838
4.15M
            {
839
4.15M
              count|=0xc0;
840
4.15M
              (void) WriteBlobByte(image,(unsigned char) count);
841
4.15M
            }
842
11.2M
          (void) WriteBlobByte(image,previous);
843
11.2M
          previous=packet;
844
11.2M
          count=1;
845
11.2M
        }
846
110k
        if ((count > 1) || ((previous & 0xc0) == 0xc0))
847
81.1k
          {
848
81.1k
            count|=0xc0;
849
81.1k
            (void) WriteBlobByte(image,(unsigned char) count);
850
81.1k
          }
851
110k
        (void) WriteBlobByte(image,previous);
852
110k
      }
853
110k
  }
854
76.0k
  return (MagickTrue);
855
76.0k
}
856
857
static MagickBooleanType WritePCXImage(const ImageInfo *image_info,Image *image,
858
  ExceptionInfo *exception)
859
391
{
860
391
  const Quantum
861
391
    *p;
862
863
391
  MagickBooleanType
864
391
    status;
865
866
391
  MagickOffsetType
867
391
    offset,
868
391
    *page_table,
869
391
    scene;
870
871
391
  MemoryInfo
872
391
    *pixel_info;
873
874
391
  PCXInfo
875
391
    pcx_info;
876
877
391
  size_t
878
391
    number_scenes,
879
391
    length;
880
881
391
  ssize_t
882
391
    i,
883
391
    x,
884
391
    y;
885
886
391
  unsigned char
887
391
    *pcx_colormap,
888
391
    *pixels,
889
391
    *q;
890
891
  /*
892
    Open output image file.
893
  */
894
391
  assert(image_info != (const ImageInfo *) NULL);
895
391
  assert(image_info->signature == MagickCoreSignature);
896
391
  assert(image != (Image *) NULL);
897
391
  assert(image->signature == MagickCoreSignature);
898
391
  assert(exception != (ExceptionInfo *) NULL);
899
391
  assert(exception->signature == MagickCoreSignature);
900
391
  if (IsEventLogging() != MagickFalse)
901
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
902
391
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
903
391
  if (status == MagickFalse)
904
0
    return(status);
905
391
  number_scenes=GetImageListLength(image);
906
391
  if (number_scenes > MaxNumberScenes)
907
391
    ThrowWriterException(ResourceLimitError,"ListLengthExceedsLimit");
908
391
  page_table=(MagickOffsetType *) NULL;
909
391
  if ((LocaleCompare(image_info->magick,"DCX") == 0) ||
910
391
      ((GetNextImageInList(image) != (Image *) NULL) &&
911
0
       (image_info->adjoin != MagickFalse)))
912
0
    {
913
      /*
914
        Write the DCX page table.
915
      */
916
0
      (void) WriteBlobLSBLong(image,0x3ADE68B1L);
917
0
      page_table=(MagickOffsetType *) AcquireQuantumMemory(MaxNumberScenes+1,
918
0
        sizeof(*page_table));
919
0
      if (page_table == (MagickOffsetType *) NULL)
920
0
        ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
921
0
      for (scene=0; scene < MaxNumberScenes; scene++)
922
0
        (void) WriteBlobLSBLong(image,0x00000000L);
923
0
    }
924
391
  scene=0;
925
391
  do
926
391
  {
927
391
    if (page_table != (MagickOffsetType *) NULL)
928
0
      page_table[scene]=TellBlob(image);
929
    /*
930
      Initialize PCX raster file header.
931
    */
932
391
    pcx_info.identifier=0x0a;
933
391
    pcx_info.version=5;
934
391
    pcx_info.encoding=image_info->compression == NoCompression ? 0 : 1;
935
391
    pcx_info.bits_per_pixel=8;
936
391
    if ((image->storage_class == PseudoClass) &&
937
301
        (SetImageMonochrome(image,exception) != MagickFalse))
938
109
      pcx_info.bits_per_pixel=1;
939
282
    else
940
282
      if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
941
0
        (void) TransformImageColorspace(image,sRGBColorspace,exception);
942
391
    pcx_info.left=0;
943
391
    pcx_info.top=0;
944
391
    pcx_info.right=(unsigned short) (image->columns-1);
945
391
    pcx_info.bottom=(unsigned short) (image->rows-1);
946
391
    switch (image->units)
947
391
    {
948
0
      case UndefinedResolution:
949
391
      case PixelsPerInchResolution:
950
391
      default:
951
391
      {
952
391
        pcx_info.horizontal_resolution=CastDoubleToUShort(image->resolution.x);
953
391
        pcx_info.vertical_resolution=CastDoubleToUShort(image->resolution.y);
954
391
        break;
955
391
      }
956
0
      case PixelsPerCentimeterResolution:
957
0
      {
958
0
        pcx_info.horizontal_resolution=CastDoubleToUShort(2.54*image->resolution.x+0.5);
959
0
        pcx_info.vertical_resolution=CastDoubleToUShort(2.54*image->resolution.y+0.5);
960
0
        break;
961
391
      }
962
391
    }
963
391
    pcx_info.reserved=0;
964
391
    pcx_info.planes=1;
965
391
    if ((image->storage_class == DirectClass) || (image->colors > 256))
966
90
      {
967
90
        pcx_info.planes=3;
968
90
        if (image->alpha_trait != UndefinedPixelTrait)
969
40
          pcx_info.planes++;
970
90
      }
971
391
    length=(((size_t) image->columns*pcx_info.bits_per_pixel+7)/8);
972
391
    if ((image->columns > 65535UL) || (image->rows > 65535UL) ||
973
391
        (length > 65535UL))
974
0
      {
975
0
        if (page_table != (MagickOffsetType *) NULL)
976
0
          page_table=(MagickOffsetType *) RelinquishMagickMemory(page_table);
977
0
        ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
978
0
      }
979
391
    pcx_info.bytes_per_line=(unsigned short) length;
980
391
    pcx_info.palette_info=1;
981
391
    pcx_info.colormap_signature=0x0c;
982
    /*
983
      Write PCX header.
984
    */
985
391
    (void) WriteBlobByte(image,pcx_info.identifier);
986
391
    (void) WriteBlobByte(image,pcx_info.version);
987
391
    (void) WriteBlobByte(image,pcx_info.encoding);
988
391
    (void) WriteBlobByte(image,pcx_info.bits_per_pixel);
989
391
    (void) WriteBlobLSBShort(image,pcx_info.left);
990
391
    (void) WriteBlobLSBShort(image,pcx_info.top);
991
391
    (void) WriteBlobLSBShort(image,pcx_info.right);
992
391
    (void) WriteBlobLSBShort(image,pcx_info.bottom);
993
391
    (void) WriteBlobLSBShort(image,pcx_info.horizontal_resolution);
994
391
    (void) WriteBlobLSBShort(image,pcx_info.vertical_resolution);
995
    /*
996
      Dump colormap to file.
997
    */
998
391
    pcx_colormap=(unsigned char *) AcquireQuantumMemory(256UL,
999
391
      3*sizeof(*pcx_colormap));
1000
391
    if (pcx_colormap == (unsigned char *) NULL)
1001
0
      {
1002
0
        if (page_table != (MagickOffsetType *) NULL)
1003
0
          page_table=(MagickOffsetType *) RelinquishMagickMemory(page_table);
1004
0
        ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1005
0
      }
1006
391
    (void) memset(pcx_colormap,0,3*256*sizeof(*pcx_colormap));
1007
391
    q=pcx_colormap;
1008
391
    if ((image->storage_class == PseudoClass) && (image->colors <= 256))
1009
5.59k
      for (i=0; i < (ssize_t) image->colors; i++)
1010
5.29k
      {
1011
5.29k
        *q++=ScaleQuantumToChar((Quantum) image->colormap[i].red);
1012
5.29k
        *q++=ScaleQuantumToChar((Quantum) image->colormap[i].green);
1013
5.29k
        *q++=ScaleQuantumToChar((Quantum) image->colormap[i].blue);
1014
5.29k
      }
1015
391
    (void) WriteBlob(image,3*16,(const unsigned char *) pcx_colormap);
1016
391
    (void) WriteBlobByte(image,pcx_info.reserved);
1017
391
    (void) WriteBlobByte(image,pcx_info.planes);
1018
391
    (void) WriteBlobLSBShort(image,pcx_info.bytes_per_line);
1019
391
    (void) WriteBlobLSBShort(image,pcx_info.palette_info);
1020
23.0k
    for (i=0; i < 58; i++)
1021
22.6k
      (void) WriteBlobByte(image,'\0');
1022
391
    length=(size_t) pcx_info.bytes_per_line;
1023
391
    pixel_info=AcquireVirtualMemory(length,pcx_info.planes*sizeof(*pixels));
1024
391
    if (pixel_info == (MemoryInfo *) NULL)
1025
0
      {
1026
0
        pcx_colormap=(unsigned char *) RelinquishMagickMemory(pcx_colormap);
1027
0
        if (page_table != (MagickOffsetType *) NULL)
1028
0
          page_table=(MagickOffsetType *) RelinquishMagickMemory(page_table);
1029
0
        ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1030
0
      }
1031
391
    pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
1032
391
    q=pixels;
1033
391
    if ((image->storage_class == DirectClass) || (image->colors > 256))
1034
90
      {
1035
        /*
1036
          Convert DirectClass image to PCX raster pixels.
1037
        */
1038
13.5k
        for (y=0; y < (ssize_t) image->rows; y++)
1039
13.4k
        {
1040
13.4k
          q=pixels;
1041
61.8k
          for (i=0; i < pcx_info.planes; i++)
1042
48.3k
          {
1043
48.3k
            p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1044
48.3k
            if (p == (const Quantum *) NULL)
1045
0
              break;
1046
48.3k
            switch ((int) i)
1047
48.3k
            {
1048
13.4k
              case 0:
1049
13.4k
              {
1050
7.47M
                for (x=0; x < (ssize_t) pcx_info.bytes_per_line; x++)
1051
7.46M
                {
1052
7.46M
                  *q++=ScaleQuantumToChar(GetPixelRed(image,p));
1053
7.46M
                  p+=(ptrdiff_t) GetPixelChannels(image);
1054
7.46M
                }
1055
13.4k
                break;
1056
0
              }
1057
13.4k
              case 1:
1058
13.4k
              {
1059
7.47M
                for (x=0; x < (ssize_t) pcx_info.bytes_per_line; x++)
1060
7.46M
                {
1061
7.46M
                  *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
1062
7.46M
                  p+=(ptrdiff_t) GetPixelChannels(image);
1063
7.46M
                }
1064
13.4k
                break;
1065
0
              }
1066
13.4k
              case 2:
1067
13.4k
              {
1068
7.47M
                for (x=0; x < (ssize_t) pcx_info.bytes_per_line; x++)
1069
7.46M
                {
1070
7.46M
                  *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
1071
7.46M
                  p+=(ptrdiff_t) GetPixelChannels(image);
1072
7.46M
                }
1073
13.4k
                break;
1074
0
              }
1075
7.96k
              case 3:
1076
7.96k
              default:
1077
7.96k
              {
1078
7.37M
                for (x=(ssize_t) pcx_info.bytes_per_line; x != 0; x--)
1079
7.36M
                {
1080
7.36M
                  *q++=ScaleQuantumToChar((Quantum) (GetPixelAlpha(image,p)));
1081
7.36M
                  p+=(ptrdiff_t) GetPixelChannels(image);
1082
7.36M
                }
1083
7.96k
                break;
1084
7.96k
              }
1085
48.3k
            }
1086
48.3k
          }
1087
13.4k
          if (PCXWritePixels(&pcx_info,pixels,image) == MagickFalse)
1088
0
            break;
1089
13.4k
          if (image->previous == (Image *) NULL)
1090
13.4k
            {
1091
13.4k
              status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1092
13.4k
                image->rows);
1093
13.4k
              if (status == MagickFalse)
1094
0
                break;
1095
13.4k
            }
1096
13.4k
        }
1097
90
      }
1098
301
    else
1099
301
      {
1100
301
        if (pcx_info.bits_per_pixel > 1)
1101
50.9k
          for (y=0; y < (ssize_t) image->rows; y++)
1102
50.7k
          {
1103
50.7k
            p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1104
50.7k
            if (p == (const Quantum *) NULL)
1105
0
              break;
1106
50.7k
            q=pixels;
1107
17.3M
            for (x=0; x < (ssize_t) image->columns; x++)
1108
17.3M
            {
1109
17.3M
              *q++=(unsigned char) ((ssize_t) GetPixelIndex(image,p));
1110
17.3M
              p+=(ptrdiff_t) GetPixelChannels(image);
1111
17.3M
            }
1112
50.7k
            if (PCXWritePixels(&pcx_info,pixels,image) == MagickFalse)
1113
0
              break;
1114
50.7k
            if (image->previous == (Image *) NULL)
1115
50.7k
              {
1116
50.7k
                status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1117
50.7k
                  y,image->rows);
1118
50.7k
                if (status == MagickFalse)
1119
0
                  break;
1120
50.7k
              }
1121
50.7k
          }
1122
109
        else
1123
109
          {
1124
109
            unsigned char
1125
109
              bit,
1126
109
              byte;
1127
1128
            /*
1129
              Convert PseudoClass image to a PCX monochrome image.
1130
            */
1131
11.9k
            for (y=0; y < (ssize_t) image->rows; y++)
1132
11.8k
            {
1133
11.8k
              p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1134
11.8k
              if (p == (const Quantum *) NULL)
1135
0
                break;
1136
11.8k
              bit=0;
1137
11.8k
              byte=0;
1138
11.8k
              q=pixels;
1139
2.98M
              for (x=0; x < (ssize_t) image->columns; x++)
1140
2.97M
              {
1141
2.97M
                byte<<=1;
1142
2.97M
                if (GetPixelLuma(image,p) < ((double) QuantumRange/2.0))
1143
1.73M
                  byte|=0x01;
1144
2.97M
                bit++;
1145
2.97M
                if (bit == 8)
1146
368k
                  {
1147
368k
                    *q++=byte;
1148
368k
                    bit=0;
1149
368k
                    byte=0;
1150
368k
                  }
1151
2.97M
                p+=(ptrdiff_t) GetPixelChannels(image);
1152
2.97M
              }
1153
11.8k
              if (bit != 0)
1154
7.56k
                *q++=byte << (8-bit);
1155
11.8k
              if (PCXWritePixels(&pcx_info,pixels,image) == MagickFalse)
1156
0
                break;
1157
11.8k
              if (image->previous == (Image *) NULL)
1158
11.8k
                {
1159
11.8k
                  status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1160
11.8k
                    y,image->rows);
1161
11.8k
                  if (status == MagickFalse)
1162
0
                    break;
1163
11.8k
                }
1164
11.8k
            }
1165
109
          }
1166
301
        (void) WriteBlobByte(image,pcx_info.colormap_signature);
1167
301
        (void) WriteBlob(image,3*256,pcx_colormap);
1168
301
      }
1169
391
    pixel_info=RelinquishVirtualMemory(pixel_info);
1170
391
    pcx_colormap=(unsigned char *) RelinquishMagickMemory(pcx_colormap);
1171
391
    if (page_table == (MagickOffsetType *) NULL)
1172
391
      break;
1173
0
    if (GetNextImageInList(image) == (Image *) NULL)
1174
0
      break;
1175
0
    image=SyncNextImageInList(image);
1176
0
    status=SetImageProgress(image,SaveImagesTag,scene++,number_scenes);
1177
0
    if (status == MagickFalse)
1178
0
      break;
1179
0
  } while (image_info->adjoin != MagickFalse);
1180
391
  if (page_table != (MagickOffsetType *) NULL)
1181
0
    {
1182
      /*
1183
        Write the DCX page table.
1184
      */
1185
0
      page_table[scene+1]=0;
1186
0
      offset=SeekBlob(image,0L,SEEK_SET);
1187
0
      if (offset < 0)
1188
0
        {
1189
0
          page_table=(MagickOffsetType *) RelinquishMagickMemory(page_table);
1190
0
          ThrowWriterException(CorruptImageError,"ImproperImageHeader");
1191
0
        }
1192
0
      (void) WriteBlobLSBLong(image,0x3ADE68B1L);
1193
0
      for (i=0; i <= (ssize_t) scene; i++)
1194
0
        (void) WriteBlobLSBLong(image,(unsigned int) page_table[i]);
1195
0
      page_table=(MagickOffsetType *) RelinquishMagickMemory(page_table);
1196
0
    }
1197
391
  if (status == MagickFalse)
1198
0
    {
1199
0
      char
1200
0
        *message;
1201
1202
0
      message=GetExceptionMessage(errno);
1203
0
      (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
1204
0
        "UnableToWriteFile","`%s': %s",image->filename,message);
1205
0
      message=DestroyString(message);
1206
0
    }
1207
391
  if (CloseBlob(image) == MagickFalse)
1208
0
    status=MagickFalse;
1209
391
  return(status);
1210
391
}