Coverage Report

Created: 2026-02-14 07:11

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/license/                                         %
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
957
{
205
2.37k
#define MaxNumberScenes  1024
206
957
#define ThrowPCXException(severity,tag) \
207
532
{ \
208
532
  if (scanline != (unsigned char *) NULL) \
209
532
    scanline=(unsigned char *) RelinquishMagickMemory(scanline); \
210
532
  if (pixel_info != (MemoryInfo *) NULL) \
211
532
    pixel_info=RelinquishVirtualMemory(pixel_info); \
212
532
  if (page_table != (MagickOffsetType *) NULL) \
213
532
    page_table=(MagickOffsetType *) RelinquishMagickMemory(page_table); \
214
532
  ThrowReaderException(severity,tag); \
215
0
}
216
217
957
  Image
218
957
    *image;
219
220
957
  int
221
957
    bits,
222
957
    id,
223
957
    mask;
224
225
957
  MagickBooleanType
226
957
    status;
227
228
957
  MagickOffsetType
229
957
    offset,
230
957
    *page_table;
231
232
957
  MemoryInfo
233
957
    *pixel_info;
234
235
957
  PCXInfo
236
957
    pcx_info;
237
238
957
  Quantum
239
957
    *q;
240
241
957
  size_t
242
957
    one,
243
957
    pcx_packets;
244
245
957
  ssize_t
246
957
    count,
247
957
    i,
248
957
    x,
249
957
    y;
250
251
957
  unsigned char
252
957
    *p,
253
957
    packet,
254
957
    pcx_colormap[768],
255
957
    *pixels,
256
957
    *r,
257
957
    *scanline;
258
259
  /*
260
    Open image file.
261
  */
262
957
  assert(image_info != (const ImageInfo *) NULL);
263
957
  assert(image_info->signature == MagickCoreSignature);
264
957
  assert(exception != (ExceptionInfo *) NULL);
265
957
  assert(exception->signature == MagickCoreSignature);
266
957
  if (IsEventLogging() != MagickFalse)
267
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
268
0
      image_info->filename);
269
957
  image=AcquireImage(image_info,exception);
270
957
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
271
957
  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
957
  page_table=(MagickOffsetType *) NULL;
280
957
  scanline=(unsigned char *) NULL;
281
957
  pixel_info=(MemoryInfo *) NULL;
282
957
  if (LocaleCompare(image_info->magick,"DCX") == 0)
283
1
    {
284
1
      size_t
285
1
        magic;
286
287
      /*
288
        Read the DCX page table.
289
      */
290
1
      magic=ReadBlobLSBLong(image);
291
1
      if (magic != 987654321)
292
1
        ThrowPCXException(CorruptImageError,"ImproperImageHeader");
293
1
      page_table=(MagickOffsetType *) AcquireQuantumMemory(MaxNumberScenes,
294
1
        sizeof(*page_table));
295
1
      if (page_table == (MagickOffsetType *) NULL)
296
1
        ThrowPCXException(ResourceLimitError,"MemoryAllocationFailed");
297
1.02k
      for (id=0; id < MaxNumberScenes; id++)
298
1.02k
      {
299
1.02k
        page_table[id]=(MagickOffsetType) ReadBlobLSBLong(image);
300
1.02k
        if (page_table[id] == 0)
301
0
          break;
302
1.02k
      }
303
1
    }
304
957
  if (page_table != (MagickOffsetType *) NULL)
305
1
    {
306
1
      offset=SeekBlob(image,(MagickOffsetType) page_table[0],SEEK_SET);
307
1
      if (offset < 0)
308
1
        ThrowPCXException(CorruptImageError,"ImproperImageHeader");
309
1
    }
310
957
  count=ReadBlob(image,1,&pcx_info.identifier);
311
957
  for (id=1; id < MaxNumberScenes; id++)
312
957
  {
313
957
    int
314
957
      bits_per_pixel;
315
316
    /*
317
      Verify PCX identifier.
318
    */
319
957
    pcx_info.version=(unsigned char) ReadBlobByte(image);
320
957
    if ((count != 1) || (pcx_info.identifier != 0x0a))
321
907
      ThrowPCXException(CorruptImageError,"ImproperImageHeader");
322
907
    pcx_info.encoding=(unsigned char) ReadBlobByte(image);
323
907
    bits_per_pixel=ReadBlobByte(image);
324
907
    if (bits_per_pixel == -1)
325
904
      ThrowPCXException(CorruptImageError,"ImproperImageHeader");
326
904
    pcx_info.bits_per_pixel=(unsigned char) bits_per_pixel;
327
904
    pcx_info.left=ReadBlobLSBShort(image);
328
904
    pcx_info.top=ReadBlobLSBShort(image);
329
904
    pcx_info.right=ReadBlobLSBShort(image);
330
904
    pcx_info.bottom=ReadBlobLSBShort(image);
331
904
    pcx_info.horizontal_resolution=ReadBlobLSBShort(image);
332
904
    pcx_info.vertical_resolution=ReadBlobLSBShort(image);
333
904
    if (EOFBlob(image) != MagickFalse)
334
884
      ThrowPCXException(CorruptImageError,"UnexpectedEndOfFile");
335
    /*
336
      Read PCX raster colormap.
337
    */
338
884
    if ((pcx_info.right < pcx_info.left) || (pcx_info.bottom < pcx_info.top) ||
339
882
        ((pcx_info.bits_per_pixel != 1) && (pcx_info.bits_per_pixel != 2) &&
340
391
         (pcx_info.bits_per_pixel != 4) && (pcx_info.bits_per_pixel != 8)))
341
866
      ThrowPCXException(CorruptImageError,"ImproperImageHeader");
342
866
    image->columns=(size_t) (pcx_info.right-pcx_info.left)+1UL;
343
866
    image->rows=(size_t) (pcx_info.bottom-pcx_info.top)+1UL;
344
866
    image->depth=pcx_info.bits_per_pixel;
345
866
    image->units=PixelsPerInchResolution;
346
866
    image->resolution.x=(double) pcx_info.horizontal_resolution;
347
866
    image->resolution.y=(double) pcx_info.vertical_resolution;
348
866
    image->colors=16;
349
866
    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
866
    if ((MagickSizeType) (image->columns*image->rows/255) > GetBlobSize(image))
353
828
      ThrowPCXException(CorruptImageError,"InsufficientImageDataInFile");
354
828
    status=SetImageExtent(image,image->columns,image->rows,exception);
355
828
    if (status == MagickFalse)
356
777
      ThrowPCXException(exception->severity,exception->reason);
357
777
    (void) SetImageBackgroundColor(image,exception);
358
777
    (void) memset(pcx_colormap,0,sizeof(pcx_colormap));
359
777
    count=ReadBlob(image,3*image->colors,pcx_colormap);
360
777
    if (count != (ssize_t) (3*image->colors))
361
679
      ThrowPCXException(CorruptImageError,"ImproperImageHeader");
362
679
    pcx_info.reserved=(unsigned char) ReadBlobByte(image);
363
679
    pcx_info.planes=(unsigned char) ReadBlobByte(image);
364
679
    if (pcx_info.planes == 0)
365
671
      ThrowPCXException(CorruptImageError,"ImproperImageHeader");
366
671
    if (pcx_info.planes > 6)
367
659
      ThrowPCXException(CorruptImageError,"ImproperImageHeader");
368
659
    if ((pcx_info.bits_per_pixel*pcx_info.planes) >= 64)
369
659
      ThrowPCXException(CorruptImageError,"ImproperImageHeader");
370
659
    one=1;
371
659
    if ((pcx_info.bits_per_pixel != 8) || (pcx_info.planes == 1))
372
525
      if ((pcx_info.version == 3) || (pcx_info.version == 5) ||
373
318
          ((pcx_info.bits_per_pixel*pcx_info.planes) == 1))
374
308
        image->colors=(size_t) MagickMin(one << (1UL*
375
659
          (pcx_info.bits_per_pixel*pcx_info.planes)),256UL);
376
659
    if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
377
659
      ThrowPCXException(ResourceLimitError,"MemoryAllocationFailed");
378
659
    if ((pcx_info.bits_per_pixel >= 8) && (pcx_info.planes != 1))
379
134
      image->storage_class=DirectClass;
380
659
    p=pcx_colormap;
381
19.7k
    for (i=0; i < (ssize_t) image->colors; i++)
382
19.1k
    {
383
19.1k
      image->colormap[i].red=ScaleCharToQuantum(*p++);
384
19.1k
      image->colormap[i].green=ScaleCharToQuantum(*p++);
385
19.1k
      image->colormap[i].blue=ScaleCharToQuantum(*p++);
386
19.1k
    }
387
659
    pcx_info.bytes_per_line=ReadBlobLSBShort(image);
388
659
    pcx_info.palette_info=ReadBlobLSBShort(image);
389
659
    pcx_info.horizontal_screensize=ReadBlobLSBShort(image);
390
659
    pcx_info.vertical_screensize=ReadBlobLSBShort(image);
391
36.2k
    for (i=0; i < 54; i++)
392
35.5k
      (void) ReadBlobByte(image);
393
    /*
394
      Read image data.
395
    */
396
659
    if (HeapOverflowSanityCheckGetSize(image->rows,(size_t) pcx_info.bytes_per_line,&pcx_packets) != MagickFalse)
397
641
      ThrowPCXException(CorruptImageError,"ImproperImageHeader");
398
641
    if (HeapOverflowSanityCheckGetSize(pcx_packets,(size_t) pcx_info.planes,&pcx_packets) != MagickFalse)
399
641
      ThrowPCXException(CorruptImageError,"ImproperImageHeader");
400
641
    if ((size_t) (pcx_info.bits_per_pixel*pcx_info.planes*image->columns) > (pcx_packets*8U))
401
624
      ThrowPCXException(CorruptImageError,"ImproperImageHeader");
402
624
    if ((MagickSizeType) (pcx_packets/32+128) > GetBlobSize(image))
403
570
      ThrowPCXException(CorruptImageError,"ImproperImageHeader");
404
570
    {
405
570
      size_t bytes_per_line = image->columns*pcx_info.bits_per_pixel;
406
570
      if (bytes_per_line != 0)
407
570
        bytes_per_line+=7U;
408
570
      if (bytes_per_line != 0)
409
570
        bytes_per_line/=8U;
410
570
      if ((bytes_per_line == 0) || (pcx_info.bytes_per_line < bytes_per_line))
411
529
        ThrowPCXException(CorruptImageError,"ImproperImageHeader");
412
529
    }
413
529
    scanline=(unsigned char *) AcquireQuantumMemory(MagickMax(image->columns,
414
529
      pcx_info.bytes_per_line),MagickMax(pcx_info.planes,8)*sizeof(*scanline));
415
529
    pixel_info=AcquireVirtualMemory(pcx_packets,2*sizeof(*pixels));
416
529
    if ((scanline == (unsigned char *) NULL) ||
417
529
        (pixel_info == (MemoryInfo *) NULL))
418
0
      {
419
0
        if (scanline != (unsigned char *) NULL)
420
0
          scanline=(unsigned char *) RelinquishMagickMemory(scanline);
421
0
        if (pixel_info != (MemoryInfo *) NULL)
422
0
          pixel_info=RelinquishVirtualMemory(pixel_info);
423
0
        ThrowPCXException(ResourceLimitError,"MemoryAllocationFailed");
424
0
      }
425
529
    (void) memset(scanline,0,(size_t) MagickMax(image->columns,
426
529
      pcx_info.bytes_per_line)*MagickMax(pcx_info.planes,8)*sizeof(*scanline));
427
529
    pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
428
529
    (void) memset(pixels,0,(size_t) pcx_packets*(2*sizeof(*pixels)));
429
    /*
430
      Uncompress image data.
431
    */
432
529
    p=pixels;
433
529
    if (pcx_info.encoding == 0)
434
13.0k
      while (pcx_packets != 0)
435
13.0k
      {
436
13.0k
        packet=(unsigned char) ReadBlobByte(image);
437
13.0k
        if (EOFBlob(image) != MagickFalse)
438
13.0k
          ThrowPCXException(CorruptImageError,"UnexpectedEndOfFile");
439
13.0k
        *p++=packet;
440
13.0k
        pcx_packets--;
441
13.0k
      }
442
484
    else
443
117k
      while (pcx_packets != 0)
444
117k
      {
445
117k
        packet=(unsigned char) ReadBlobByte(image);
446
117k
        if (EOFBlob(image) != MagickFalse)
447
117k
          ThrowPCXException(CorruptImageError,"UnexpectedEndOfFile");
448
117k
        if ((packet & 0xc0) != 0xc0)
449
59.9k
          {
450
59.9k
            *p++=packet;
451
59.9k
            pcx_packets--;
452
59.9k
            continue;
453
59.9k
          }
454
57.0k
        count=(ssize_t) (packet & 0x3f);
455
57.0k
        packet=(unsigned char) ReadBlobByte(image);
456
57.0k
        if (EOFBlob(image) != MagickFalse)
457
57.0k
          ThrowPCXException(CorruptImageError,"UnexpectedEndOfFile");
458
3.13M
        for ( ; count != 0; count--)
459
3.07M
        {
460
3.07M
          *p++=packet;
461
3.07M
          pcx_packets--;
462
3.07M
          if (pcx_packets == 0)
463
358
            break;
464
3.07M
        }
465
57.0k
      }
466
425
    if (image->storage_class == DirectClass)
467
93
      image->alpha_trait=pcx_info.planes > 3 ? BlendPixelTrait :
468
93
        UndefinedPixelTrait;
469
332
    else
470
332
      if ((pcx_info.version == 5) ||
471
201
          ((pcx_info.bits_per_pixel*pcx_info.planes) == 1))
472
201
        {
473
          /*
474
            Initialize image colormap.
475
          */
476
201
          if (image->colors > 256)
477
201
            ThrowPCXException(CorruptImageError,"ColormapExceeds256Colors");
478
201
          if ((pcx_info.bits_per_pixel*pcx_info.planes) == 1)
479
84
            {
480
              /*
481
                Monochrome colormap.
482
              */
483
84
              image->colormap[0].red=(Quantum) 0;
484
84
              image->colormap[0].green=(Quantum) 0;
485
84
              image->colormap[0].blue=(Quantum) 0;
486
84
              image->colormap[1].red=QuantumRange;
487
84
              image->colormap[1].green=QuantumRange;
488
84
              image->colormap[1].blue=QuantumRange;
489
84
            }
490
117
          else
491
117
            if (image->colors > 16)
492
63
              {
493
                /*
494
                  256 color images have their color map at the end of the file.
495
                */
496
63
                offset=SeekBlob(image,(MagickOffsetType) GetBlobSize(image)-3*
497
63
                  image->colors-1,SEEK_SET);
498
63
                pcx_info.colormap_signature=(unsigned char) ReadBlobByte(image);
499
63
                count=ReadBlob(image,3*image->colors,pcx_colormap);
500
63
                p=pcx_colormap;
501
7.83k
                for (i=0; i < (ssize_t) image->colors; i++)
502
7.77k
                {
503
7.77k
                  image->colormap[i].red=ScaleCharToQuantum(*p++);
504
7.77k
                  image->colormap[i].green=ScaleCharToQuantum(*p++);
505
7.77k
                  image->colormap[i].blue=ScaleCharToQuantum(*p++);
506
7.77k
                }
507
63
            }
508
201
        }
509
    /*
510
      Convert PCX raster image to pixel packets.
511
    */
512
71.5k
    for (y=0; y < (ssize_t) image->rows; y++)
513
71.1k
    {
514
71.1k
      p=pixels+(y*pcx_info.bytes_per_line*pcx_info.planes);
515
71.1k
      q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
516
71.1k
      if (q == (Quantum *) NULL)
517
0
        break;
518
71.1k
      r=scanline;
519
71.1k
      if (image->storage_class == DirectClass)
520
30.2k
        for (i=0; i < pcx_info.planes; i++)
521
21.0k
        {
522
21.0k
          r=scanline+i;
523
227k
          for (x=0; x < (ssize_t) pcx_info.bytes_per_line; x++)
524
206k
          {
525
206k
            switch (i)
526
206k
            {
527
99.3k
              case 0:
528
99.3k
              {
529
99.3k
                *r=(*p++);
530
99.3k
                break;
531
0
              }
532
99.3k
              case 1:
533
99.3k
              {
534
99.3k
                *r=(*p++);
535
99.3k
                break;
536
0
              }
537
3.45k
              case 2:
538
3.45k
              {
539
3.45k
                *r=(*p++);
540
3.45k
                break;
541
0
              }
542
3.09k
              case 3:
543
4.48k
              default:
544
4.48k
              {
545
4.48k
                *r=(*p++);
546
4.48k
                break;
547
3.09k
              }
548
206k
            }
549
206k
            r+=(ptrdiff_t) pcx_info.planes;
550
206k
          }
551
21.0k
        }
552
61.9k
      else
553
61.9k
        if (pcx_info.planes > 1)
554
13.6k
          {
555
252k
            for (x=0; x < (ssize_t) image->columns; x++)
556
238k
              *r++=0;
557
44.3k
            for (i=0; i < pcx_info.planes; i++)
558
30.6k
            {
559
30.6k
              r=scanline;
560
579k
              for (x=0; x < (ssize_t) pcx_info.bytes_per_line; x++)
561
548k
              {
562
548k
                 bits=(*p++);
563
4.94M
                 for (mask=0x80; mask != 0; mask>>=1)
564
4.39M
                 {
565
4.39M
                   if (bits & mask)
566
3.75M
                     *r|=1 << i;
567
4.39M
                   r++;
568
4.39M
                 }
569
548k
               }
570
30.6k
            }
571
13.6k
          }
572
48.2k
        else
573
48.2k
          switch (pcx_info.bits_per_pixel)
574
48.2k
          {
575
13.3k
            case 1:
576
13.3k
            {
577
13.3k
              ssize_t
578
13.3k
                bit;
579
580
550k
              for (x=0; x < ((ssize_t) image->columns-7); x+=8)
581
537k
              {
582
4.83M
                for (bit=7; bit >= 0; bit--)
583
4.29M
                  *r++=(unsigned char) ((*p) & (0x01 << bit) ? 0x00 : 0x01);
584
537k
                p++;
585
537k
              }
586
13.3k
              if ((image->columns % 8) != 0)
587
10.9k
                {
588
77.2k
                  for (bit=7; bit >= (ssize_t) (8-(image->columns % 8)); bit--)
589
66.3k
                    *r++=(unsigned char) ((*p) & (0x01 << bit) ? 0x00 : 0x01);
590
10.9k
                  p++;
591
10.9k
                }
592
13.3k
              break;
593
0
            }
594
32.7k
            case 2:
595
32.7k
            {
596
594k
              for (x=0; x < ((ssize_t) image->columns-3); x+=4)
597
561k
              {
598
561k
                *r++=(*p >> 6) & 0x3;
599
561k
                *r++=(*p >> 4) & 0x3;
600
561k
                *r++=(*p >> 2) & 0x3;
601
561k
                *r++=(*p) & 0x3;
602
561k
                p++;
603
561k
              }
604
32.7k
              if ((image->columns % 4) != 0)
605
30.3k
                {
606
101k
                  for (i=3; i >= (ssize_t) (4-(image->columns % 4)); i--)
607
71.0k
                    *r++=(unsigned char) ((*p >> (i*2)) & 0x03);
608
30.3k
                  p++;
609
30.3k
                }
610
32.7k
              break;
611
0
            }
612
1.65k
            case 4:
613
1.65k
            {
614
5.47k
              for (x=0; x < ((ssize_t) image->columns-1); x+=2)
615
3.81k
              {
616
3.81k
                *r++=(*p >> 4) & 0xf;
617
3.81k
                *r++=(*p) & 0xf;
618
3.81k
                p++;
619
3.81k
              }
620
1.65k
              if ((image->columns % 2) != 0)
621
1.32k
                *r++=(*p++ >> 4) & 0xf;
622
1.65k
              break;
623
0
            }
624
564
            case 8:
625
564
            {
626
564
              (void) memcpy(r,p,image->columns);
627
564
              break;
628
0
            }
629
0
            default:
630
0
              break;
631
48.2k
          }
632
      /*
633
        Transfer image scanline.
634
      */
635
71.1k
      r=scanline;
636
7.02M
      for (x=0; x < (ssize_t) image->columns; x++)
637
6.95M
      {
638
6.95M
        if (image->storage_class == PseudoClass)
639
6.93M
          SetPixelIndex(image,*r++,q);
640
19.2k
        else
641
19.2k
          {
642
19.2k
            SetPixelRed(image,ScaleCharToQuantum(*r++),q);
643
19.2k
            SetPixelGreen(image,ScaleCharToQuantum(*r++),q);
644
19.2k
            SetPixelBlue(image,ScaleCharToQuantum(*r++),q);
645
19.2k
            if (image->alpha_trait != UndefinedPixelTrait)
646
1.91k
              SetPixelAlpha(image,ScaleCharToQuantum(*r++),q);
647
19.2k
          }
648
6.95M
        q+=(ptrdiff_t) GetPixelChannels(image);
649
6.95M
      }
650
71.1k
      if (SyncAuthenticPixels(image,exception) == MagickFalse)
651
0
        break;
652
71.1k
      if (image->previous == (Image *) NULL)
653
71.1k
        {
654
71.1k
          status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
655
71.1k
            image->rows);
656
71.1k
          if (status == MagickFalse)
657
0
            break;
658
71.1k
        }
659
71.1k
    }
660
425
    if (image->storage_class == PseudoClass)
661
332
      (void) SyncImage(image,exception);
662
425
    scanline=(unsigned char *) RelinquishMagickMemory(scanline);
663
425
    pixel_info=RelinquishVirtualMemory(pixel_info);
664
425
    if (EOFBlob(image) != MagickFalse)
665
27
      {
666
27
        ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
667
27
          image->filename);
668
27
        break;
669
27
      }
670
    /*
671
      Proceed to next image.
672
    */
673
398
    if (image_info->number_scenes != 0)
674
0
      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
675
0
        break;
676
398
    if (page_table == (MagickOffsetType *) NULL)
677
398
      break;
678
0
    if (page_table[id] == 0)
679
0
      break;
680
0
    offset=SeekBlob(image,(MagickOffsetType) page_table[id],SEEK_SET);
681
0
    if (offset < 0)
682
0
      ThrowPCXException(CorruptImageError,"ImproperImageHeader");
683
0
    count=ReadBlob(image,1,&pcx_info.identifier);
684
0
    if ((count != 0) && (pcx_info.identifier == 0x0a))
685
0
      {
686
        /*
687
          Allocate next image structure.
688
        */
689
0
        AcquireNextImage(image_info,image,exception);
690
0
        if (GetNextImageInList(image) == (Image *) NULL)
691
0
          {
692
0
            status=MagickFalse;
693
0
            break;
694
0
          }
695
0
        image=SyncNextImageInList(image);
696
0
        status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
697
0
          GetBlobSize(image));
698
0
        if (status == MagickFalse)
699
0
          break;
700
0
      }
701
0
  }
702
425
  if (page_table != (MagickOffsetType *) NULL)
703
0
    page_table=(MagickOffsetType *) RelinquishMagickMemory(page_table);
704
425
  if (CloseBlob(image) == MagickFalse)
705
0
    status=MagickFalse;
706
425
  if (status == MagickFalse)
707
0
    return(DestroyImageList(image));
708
425
  return(GetFirstImageInList(image));
709
425
}
710

711
/*
712
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
713
%                                                                             %
714
%                                                                             %
715
%                                                                             %
716
%   R e g i s t e r P C X I m a g e                                           %
717
%                                                                             %
718
%                                                                             %
719
%                                                                             %
720
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
721
%
722
%  RegisterPCXImage() adds attributes for the PCX image format to
723
%  the list of supported formats.  The attributes include the image format
724
%  tag, a method to read and/or write the format, whether the format
725
%  supports the saving of more than one frame to the same file or blob,
726
%  whether the format supports native in-memory I/O, and a brief
727
%  description of the format.
728
%
729
%  The format of the RegisterPCXImage method is:
730
%
731
%      size_t RegisterPCXImage(void)
732
%
733
*/
734
ModuleExport size_t RegisterPCXImage(void)
735
9
{
736
9
  MagickInfo
737
9
    *entry;
738
739
9
  entry=AcquireMagickInfo("PCX","DCX","ZSoft IBM PC multi-page Paintbrush");
740
9
  entry->decoder=(DecodeImageHandler *) ReadPCXImage;
741
9
  entry->encoder=(EncodeImageHandler *) WritePCXImage;
742
9
  entry->flags|=CoderDecoderSeekableStreamFlag;
743
9
  entry->flags|=CoderEncoderSeekableStreamFlag;
744
9
  entry->magick=(IsImageFormatHandler *) IsDCX;
745
9
  (void) RegisterMagickInfo(entry);
746
9
  entry=AcquireMagickInfo("PCX","PCX","ZSoft IBM PC Paintbrush");
747
9
  entry->decoder=(DecodeImageHandler *) ReadPCXImage;
748
9
  entry->encoder=(EncodeImageHandler *) WritePCXImage;
749
9
  entry->magick=(IsImageFormatHandler *) IsPCX;
750
9
  entry->flags^=CoderAdjoinFlag;
751
9
  entry->flags|=CoderDecoderSeekableStreamFlag;
752
9
  entry->flags|=CoderEncoderSeekableStreamFlag;
753
9
  (void) RegisterMagickInfo(entry);
754
9
  return(MagickImageCoderSignature);
755
9
}
756

757
/*
758
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
759
%                                                                             %
760
%                                                                             %
761
%                                                                             %
762
%   U n r e g i s t e r P C X I m a g e                                       %
763
%                                                                             %
764
%                                                                             %
765
%                                                                             %
766
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
767
%
768
%  UnregisterPCXImage() removes format registrations made by the
769
%  PCX module from the list of supported formats.
770
%
771
%  The format of the UnregisterPCXImage method is:
772
%
773
%      UnregisterPCXImage(void)
774
%
775
*/
776
ModuleExport void UnregisterPCXImage(void)
777
0
{
778
0
  (void) UnregisterMagickInfo("DCX");
779
0
  (void) UnregisterMagickInfo("PCX");
780
0
}
781

782
/*
783
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
784
%                                                                             %
785
%                                                                             %
786
%                                                                             %
787
%   W r i t e P C X I m a g e                                                 %
788
%                                                                             %
789
%                                                                             %
790
%                                                                             %
791
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
792
%
793
%  WritePCXImage() writes an image in the ZSoft IBM PC Paintbrush file
794
%  format.
795
%
796
%  The format of the WritePCXImage method is:
797
%
798
%      MagickBooleanType WritePCXImage(const ImageInfo *image_info,
799
%        Image *image,ExceptionInfo *exception)
800
%
801
%  A description of each parameter follows.
802
%
803
%    o image_info: the image info.
804
%
805
%    o image:  The image.
806
%
807
%    o exception: return any errors or warnings in this structure.
808
%
809
*/
810
811
static MagickBooleanType PCXWritePixels(PCXInfo *pcx_info,
812
  const unsigned char *pixels,Image *image)
813
70.3k
{
814
70.3k
  const unsigned char
815
70.3k
    *q;
816
817
70.3k
  ssize_t
818
70.3k
    count,
819
70.3k
    i,
820
70.3k
    x;
821
822
70.3k
  unsigned char
823
70.3k
    packet,
824
70.3k
    previous;
825
826
70.3k
  q=pixels;
827
160k
  for (i=0; i < (ssize_t) pcx_info->planes; i++)
828
89.8k
  {
829
89.8k
    if (pcx_info->encoding == 0)
830
0
      {
831
0
        for (x=0; x < (ssize_t) pcx_info->bytes_per_line; x++)
832
0
          (void) WriteBlobByte(image,(unsigned char) (*q++));
833
0
      }
834
89.8k
    else
835
89.8k
      {
836
89.8k
        previous=(*q++);
837
89.8k
        count=1;
838
3.16M
        for (x=0; x < (ssize_t) (pcx_info->bytes_per_line-1); x++)
839
3.07M
        {
840
3.07M
          packet=(*q++);
841
3.07M
          if ((packet == previous) && (count < 63))
842
1.64M
            {
843
1.64M
              count++;
844
1.64M
              continue;
845
1.64M
            }
846
1.42M
          if ((count > 1) || ((previous & 0xc0) == 0xc0))
847
506k
            {
848
506k
              count|=0xc0;
849
506k
              (void) WriteBlobByte(image,(unsigned char) count);
850
506k
            }
851
1.42M
          (void) WriteBlobByte(image,previous);
852
1.42M
          previous=packet;
853
1.42M
          count=1;
854
1.42M
        }
855
89.8k
        if ((count > 1) || ((previous & 0xc0) == 0xc0))
856
51.9k
          {
857
51.9k
            count|=0xc0;
858
51.9k
            (void) WriteBlobByte(image,(unsigned char) count);
859
51.9k
          }
860
89.8k
        (void) WriteBlobByte(image,previous);
861
89.8k
      }
862
89.8k
  }
863
70.3k
  return (MagickTrue);
864
70.3k
}
865
866
static MagickBooleanType WritePCXImage(const ImageInfo *image_info,Image *image,
867
  ExceptionInfo *exception)
868
387
{
869
387
  const Quantum
870
387
    *p;
871
872
387
  MagickBooleanType
873
387
    status;
874
875
387
  MagickOffsetType
876
387
    offset,
877
387
    *page_table,
878
387
    scene;
879
880
387
  MemoryInfo
881
387
    *pixel_info;
882
883
387
  PCXInfo
884
387
    pcx_info;
885
886
387
  size_t
887
387
    number_scenes,
888
387
    length;
889
890
387
  ssize_t
891
387
    i,
892
387
    x,
893
387
    y;
894
895
387
  unsigned char
896
387
    *pcx_colormap,
897
387
    *pixels,
898
387
    *q;
899
900
  /*
901
    Open output image file.
902
  */
903
387
  assert(image_info != (const ImageInfo *) NULL);
904
387
  assert(image_info->signature == MagickCoreSignature);
905
387
  assert(image != (Image *) NULL);
906
387
  assert(image->signature == MagickCoreSignature);
907
387
  assert(exception != (ExceptionInfo *) NULL);
908
387
  assert(exception->signature == MagickCoreSignature);
909
387
  if (IsEventLogging() != MagickFalse)
910
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
911
387
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
912
387
  if (status == MagickFalse)
913
0
    return(status);
914
387
  number_scenes=GetImageListLength(image);
915
387
  if (number_scenes > MaxNumberScenes)
916
387
    ThrowWriterException(ResourceLimitError,"ListLengthExceedsLimit");
917
387
  page_table=(MagickOffsetType *) NULL;
918
387
  if ((LocaleCompare(image_info->magick,"DCX") == 0) ||
919
387
      ((GetNextImageInList(image) != (Image *) NULL) &&
920
0
       (image_info->adjoin != MagickFalse)))
921
0
    {
922
      /*
923
        Write the DCX page table.
924
      */
925
0
      (void) WriteBlobLSBLong(image,0x3ADE68B1L);
926
0
      page_table=(MagickOffsetType *) AcquireQuantumMemory(MaxNumberScenes+1,
927
0
        sizeof(*page_table));
928
0
      if (page_table == (MagickOffsetType *) NULL)
929
0
        ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
930
0
      for (scene=0; scene < MaxNumberScenes; scene++)
931
0
        (void) WriteBlobLSBLong(image,0x00000000L);
932
0
    }
933
387
  scene=0;
934
387
  do
935
387
  {
936
387
    if (page_table != (MagickOffsetType *) NULL)
937
0
      page_table[scene]=TellBlob(image);
938
    /*
939
      Initialize PCX raster file header.
940
    */
941
387
    pcx_info.identifier=0x0a;
942
387
    pcx_info.version=5;
943
387
    pcx_info.encoding=image_info->compression == NoCompression ? 0 : 1;
944
387
    pcx_info.bits_per_pixel=8;
945
387
    if ((image->storage_class == PseudoClass) &&
946
294
        (SetImageMonochrome(image,exception) != MagickFalse))
947
117
      pcx_info.bits_per_pixel=1;
948
270
    else
949
270
      if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
950
0
        (void) TransformImageColorspace(image,sRGBColorspace,exception);
951
387
    pcx_info.left=0;
952
387
    pcx_info.top=0;
953
387
    pcx_info.right=(unsigned short) (image->columns-1);
954
387
    pcx_info.bottom=(unsigned short) (image->rows-1);
955
387
    switch (image->units)
956
387
    {
957
0
      case UndefinedResolution:
958
387
      case PixelsPerInchResolution:
959
387
      default:
960
387
      {
961
387
        pcx_info.horizontal_resolution=CastDoubleToUShort(image->resolution.x);
962
387
        pcx_info.vertical_resolution=CastDoubleToUShort(image->resolution.y);
963
387
        break;
964
387
      }
965
0
      case PixelsPerCentimeterResolution:
966
0
      {
967
0
        pcx_info.horizontal_resolution=CastDoubleToUShort(2.54*image->resolution.x+0.5);
968
0
        pcx_info.vertical_resolution=CastDoubleToUShort(2.54*image->resolution.y+0.5);
969
0
        break;
970
387
      }
971
387
    }
972
387
    pcx_info.reserved=0;
973
387
    pcx_info.planes=1;
974
387
    if ((image->storage_class == DirectClass) || (image->colors > 256))
975
93
      {
976
93
        pcx_info.planes=3;
977
93
        if (image->alpha_trait != UndefinedPixelTrait)
978
43
          pcx_info.planes++;
979
93
      }
980
387
    length=(((size_t) image->columns*pcx_info.bits_per_pixel+7)/8);
981
387
    if ((image->columns > 65535UL) || (image->rows > 65535UL) ||
982
387
        (length > 65535UL))
983
0
      {
984
0
        if (page_table != (MagickOffsetType *) NULL)
985
0
          page_table=(MagickOffsetType *) RelinquishMagickMemory(page_table);
986
0
        ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
987
0
      }
988
387
    pcx_info.bytes_per_line=(unsigned short) length;
989
387
    pcx_info.palette_info=1;
990
387
    pcx_info.colormap_signature=0x0c;
991
    /*
992
      Write PCX header.
993
    */
994
387
    (void) WriteBlobByte(image,pcx_info.identifier);
995
387
    (void) WriteBlobByte(image,pcx_info.version);
996
387
    (void) WriteBlobByte(image,pcx_info.encoding);
997
387
    (void) WriteBlobByte(image,pcx_info.bits_per_pixel);
998
387
    (void) WriteBlobLSBShort(image,pcx_info.left);
999
387
    (void) WriteBlobLSBShort(image,pcx_info.top);
1000
387
    (void) WriteBlobLSBShort(image,pcx_info.right);
1001
387
    (void) WriteBlobLSBShort(image,pcx_info.bottom);
1002
387
    (void) WriteBlobLSBShort(image,pcx_info.horizontal_resolution);
1003
387
    (void) WriteBlobLSBShort(image,pcx_info.vertical_resolution);
1004
    /*
1005
      Dump colormap to file.
1006
    */
1007
387
    pcx_colormap=(unsigned char *) AcquireQuantumMemory(256UL,
1008
387
      3*sizeof(*pcx_colormap));
1009
387
    if (pcx_colormap == (unsigned char *) NULL)
1010
0
      {
1011
0
        if (page_table != (MagickOffsetType *) NULL)
1012
0
          page_table=(MagickOffsetType *) RelinquishMagickMemory(page_table);
1013
0
        ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1014
0
      }
1015
387
    (void) memset(pcx_colormap,0,3*256*sizeof(*pcx_colormap));
1016
387
    q=pcx_colormap;
1017
387
    if ((image->storage_class == PseudoClass) && (image->colors <= 256))
1018
6.63k
      for (i=0; i < (ssize_t) image->colors; i++)
1019
6.34k
      {
1020
6.34k
        *q++=ScaleQuantumToChar((Quantum) image->colormap[i].red);
1021
6.34k
        *q++=ScaleQuantumToChar((Quantum) image->colormap[i].green);
1022
6.34k
        *q++=ScaleQuantumToChar((Quantum) image->colormap[i].blue);
1023
6.34k
      }
1024
387
    (void) WriteBlob(image,3*16,(const unsigned char *) pcx_colormap);
1025
387
    (void) WriteBlobByte(image,pcx_info.reserved);
1026
387
    (void) WriteBlobByte(image,pcx_info.planes);
1027
387
    (void) WriteBlobLSBShort(image,pcx_info.bytes_per_line);
1028
387
    (void) WriteBlobLSBShort(image,pcx_info.palette_info);
1029
22.8k
    for (i=0; i < 58; i++)
1030
22.4k
      (void) WriteBlobByte(image,'\0');
1031
387
    length=(size_t) pcx_info.bytes_per_line;
1032
387
    pixel_info=AcquireVirtualMemory(length,pcx_info.planes*sizeof(*pixels));
1033
387
    if (pixel_info == (MemoryInfo *) NULL)
1034
0
      {
1035
0
        pcx_colormap=(unsigned char *) RelinquishMagickMemory(pcx_colormap);
1036
0
        if (page_table != (MagickOffsetType *) NULL)
1037
0
          page_table=(MagickOffsetType *) RelinquishMagickMemory(page_table);
1038
0
        ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1039
0
      }
1040
387
    pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
1041
387
    q=pixels;
1042
387
    if ((image->storage_class == DirectClass) || (image->colors > 256))
1043
93
      {
1044
        /*
1045
          Convert DirectClass image to PCX raster pixels.
1046
        */
1047
9.28k
        for (y=0; y < (ssize_t) image->rows; y++)
1048
9.18k
        {
1049
9.18k
          q=pixels;
1050
37.8k
          for (i=0; i < pcx_info.planes; i++)
1051
28.6k
          {
1052
28.6k
            p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1053
28.6k
            if (p == (const Quantum *) NULL)
1054
0
              break;
1055
28.6k
            switch ((int) i)
1056
28.6k
            {
1057
9.18k
              case 0:
1058
9.18k
              {
1059
28.4k
                for (x=0; x < (ssize_t) pcx_info.bytes_per_line; x++)
1060
19.2k
                {
1061
19.2k
                  *q++=ScaleQuantumToChar(GetPixelRed(image,p));
1062
19.2k
                  p+=(ptrdiff_t) GetPixelChannels(image);
1063
19.2k
                }
1064
9.18k
                break;
1065
0
              }
1066
9.18k
              case 1:
1067
9.18k
              {
1068
28.4k
                for (x=0; x < (ssize_t) pcx_info.bytes_per_line; x++)
1069
19.2k
                {
1070
19.2k
                  *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
1071
19.2k
                  p+=(ptrdiff_t) GetPixelChannels(image);
1072
19.2k
                }
1073
9.18k
                break;
1074
0
              }
1075
9.18k
              case 2:
1076
9.18k
              {
1077
28.4k
                for (x=0; x < (ssize_t) pcx_info.bytes_per_line; x++)
1078
19.2k
                {
1079
19.2k
                  *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
1080
19.2k
                  p+=(ptrdiff_t) GetPixelChannels(image);
1081
19.2k
                }
1082
9.18k
                break;
1083
0
              }
1084
1.12k
              case 3:
1085
1.12k
              default:
1086
1.12k
              {
1087
3.04k
                for (x=(ssize_t) pcx_info.bytes_per_line; x != 0; x--)
1088
1.91k
                {
1089
1.91k
                  *q++=ScaleQuantumToChar((Quantum) (GetPixelAlpha(image,p)));
1090
1.91k
                  p+=(ptrdiff_t) GetPixelChannels(image);
1091
1.91k
                }
1092
1.12k
                break;
1093
1.12k
              }
1094
28.6k
            }
1095
28.6k
          }
1096
9.18k
          if (PCXWritePixels(&pcx_info,pixels,image) == MagickFalse)
1097
0
            break;
1098
9.18k
          if (image->previous == (Image *) NULL)
1099
9.18k
            {
1100
9.18k
              status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1101
9.18k
                image->rows);
1102
9.18k
              if (status == MagickFalse)
1103
0
                break;
1104
9.18k
            }
1105
9.18k
        }
1106
93
      }
1107
294
    else
1108
294
      {
1109
294
        if (pcx_info.bits_per_pixel > 1)
1110
47.3k
          for (y=0; y < (ssize_t) image->rows; y++)
1111
47.1k
          {
1112
47.1k
            p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1113
47.1k
            if (p == (const Quantum *) NULL)
1114
0
              break;
1115
47.1k
            q=pixels;
1116
2.60M
            for (x=0; x < (ssize_t) image->columns; x++)
1117
2.55M
            {
1118
2.55M
              *q++=(unsigned char) ((ssize_t) GetPixelIndex(image,p));
1119
2.55M
              p+=(ptrdiff_t) GetPixelChannels(image);
1120
2.55M
            }
1121
47.1k
            if (PCXWritePixels(&pcx_info,pixels,image) == MagickFalse)
1122
0
              break;
1123
47.1k
            if (image->previous == (Image *) NULL)
1124
47.1k
              {
1125
47.1k
                status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1126
47.1k
                  y,image->rows);
1127
47.1k
                if (status == MagickFalse)
1128
0
                  break;
1129
47.1k
              }
1130
47.1k
          }
1131
117
        else
1132
117
          {
1133
117
            unsigned char
1134
117
              bit,
1135
117
              byte;
1136
1137
            /*
1138
              Convert PseudoClass image to a PCX monochrome image.
1139
            */
1140
14.0k
            for (y=0; y < (ssize_t) image->rows; y++)
1141
13.9k
            {
1142
13.9k
              p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1143
13.9k
              if (p == (const Quantum *) NULL)
1144
0
                break;
1145
13.9k
              bit=0;
1146
13.9k
              byte=0;
1147
13.9k
              q=pixels;
1148
4.38M
              for (x=0; x < (ssize_t) image->columns; x++)
1149
4.36M
              {
1150
4.36M
                byte<<=1;
1151
4.36M
                if (GetPixelLuma(image,p) < ((double) QuantumRange/2.0))
1152
3.53M
                  byte|=0x01;
1153
4.36M
                bit++;
1154
4.36M
                if (bit == 8)
1155
537k
                  {
1156
537k
                    *q++=byte;
1157
537k
                    bit=0;
1158
537k
                    byte=0;
1159
537k
                  }
1160
4.36M
                p+=(ptrdiff_t) GetPixelChannels(image);
1161
4.36M
              }
1162
13.9k
              if (bit != 0)
1163
11.5k
                *q++=byte << (8-bit);
1164
13.9k
              if (PCXWritePixels(&pcx_info,pixels,image) == MagickFalse)
1165
0
                break;
1166
13.9k
              if (image->previous == (Image *) NULL)
1167
13.9k
                {
1168
13.9k
                  status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1169
13.9k
                    y,image->rows);
1170
13.9k
                  if (status == MagickFalse)
1171
0
                    break;
1172
13.9k
                }
1173
13.9k
            }
1174
117
          }
1175
294
        (void) WriteBlobByte(image,pcx_info.colormap_signature);
1176
294
        (void) WriteBlob(image,3*256,pcx_colormap);
1177
294
      }
1178
387
    pixel_info=RelinquishVirtualMemory(pixel_info);
1179
387
    pcx_colormap=(unsigned char *) RelinquishMagickMemory(pcx_colormap);
1180
387
    if (page_table == (MagickOffsetType *) NULL)
1181
387
      break;
1182
0
    if (GetNextImageInList(image) == (Image *) NULL)
1183
0
      break;
1184
0
    image=SyncNextImageInList(image);
1185
0
    status=SetImageProgress(image,SaveImagesTag,scene++,number_scenes);
1186
0
    if (status == MagickFalse)
1187
0
      break;
1188
0
  } while (image_info->adjoin != MagickFalse);
1189
387
  if (page_table != (MagickOffsetType *) NULL)
1190
0
    {
1191
      /*
1192
        Write the DCX page table.
1193
      */
1194
0
      page_table[scene+1]=0;
1195
0
      offset=SeekBlob(image,0L,SEEK_SET);
1196
0
      if (offset < 0)
1197
0
        {
1198
0
          page_table=(MagickOffsetType *) RelinquishMagickMemory(page_table);
1199
0
          ThrowWriterException(CorruptImageError,"ImproperImageHeader");
1200
0
        }
1201
0
      (void) WriteBlobLSBLong(image,0x3ADE68B1L);
1202
0
      for (i=0; i <= (ssize_t) scene; i++)
1203
0
        (void) WriteBlobLSBLong(image,(unsigned int) page_table[i]);
1204
0
      page_table=(MagickOffsetType *) RelinquishMagickMemory(page_table);
1205
0
    }
1206
387
  if (status == MagickFalse)
1207
0
    {
1208
0
      char
1209
0
        *message;
1210
1211
0
      message=GetExceptionMessage(errno);
1212
0
      (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
1213
0
        "UnableToWriteFile","`%s': %s",image->filename,message);
1214
0
      message=DestroyString(message);
1215
0
    }
1216
387
  if (CloseBlob(image) == MagickFalse)
1217
0
    status=MagickFalse;
1218
387
  return(status);
1219
387
}