Coverage Report

Created: 2026-09-28 06:47

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