blob: c2a3d214ef95393a5d7ede3b537e0513aaea55c3 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
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% John Cristy %
17% July 1992 %
18% %
19% %
cristy1454be72011-12-19 01:52:48 +000020% Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% 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% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37*/
38
39/*
40 Include declarations.
41*/
cristy4c08aed2011-07-01 19:47:50 +000042#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"
cristy510d06a2011-07-06 23:43:54 +000051#include "MagickCore/colorspace-private.h"
cristy4c08aed2011-07-01 19:47:50 +000052#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/monitor.h"
60#include "MagickCore/monitor-private.h"
61#include "MagickCore/pixel-accessor.h"
62#include "MagickCore/quantum-private.h"
63#include "MagickCore/static.h"
64#include "MagickCore/string_.h"
65#include "MagickCore/module.h"
cristy3ed852e2009-09-05 21:47:34 +000066
67/*
68 Typedef declarations.
69*/
70typedef struct _PCXInfo
71{
72 unsigned char
73 identifier,
74 version,
75 encoding,
76 bits_per_pixel;
77
78 unsigned short
79 left,
80 top,
81 right,
82 bottom,
83 horizontal_resolution,
84 vertical_resolution;
85
86 unsigned char
87 reserved,
88 planes;
89
90 unsigned short
91 bytes_per_line,
92 palette_info;
93
94 unsigned char
95 colormap_signature;
96} PCXInfo;
97
98/*
99 Forward declarations.
100*/
101static MagickBooleanType
cristy1e178e72011-08-28 19:44:34 +0000102 WritePCXImage(const ImageInfo *,Image *,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000103
104/*
105%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
106% %
107% %
108% %
109% I s D C X %
110% %
111% %
112% %
113%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
114%
115% IsDCX() returns MagickTrue if the image format type, identified by the
116% magick string, is DCX.
117%
118% The format of the IsDCX method is:
119%
120% MagickBooleanType IsDCX(const unsigned char *magick,const size_t length)
121%
122% A description of each parameter follows:
123%
124% o magick: compare image format pattern against these bytes.
125%
126% o length: Specifies the length of the magick string.
127%
128%
129*/
130static MagickBooleanType IsDCX(const unsigned char *magick,const size_t length)
131{
132 if (length < 4)
133 return(MagickFalse);
134 if (memcmp(magick,"\261\150\336\72",4) == 0)
135 return(MagickTrue);
136 return(MagickFalse);
137}
138
139/*
140%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
141% %
142% %
143% %
144% I s P C X %
145% %
146% %
147% %
148%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
149%
150% IsPCX() returns MagickTrue if the image format type, identified by the
151% magick string, is PCX.
152%
153% The format of the IsPCX method is:
154%
155% MagickBooleanType IsPCX(const unsigned char *magick,const size_t length)
156%
157% A description of each parameter follows:
158%
159% o magick: compare image format pattern against these bytes.
160%
161% o length: Specifies the length of the magick string.
162%
163%
164*/
165static MagickBooleanType IsPCX(const unsigned char *magick,const size_t length)
166{
167 if (length < 2)
168 return(MagickFalse);
169 if (memcmp(magick,"\012\002",2) == 0)
170 return(MagickTrue);
171 if (memcmp(magick,"\012\005",2) == 0)
172 return(MagickTrue);
173 return(MagickFalse);
174}
175
176/*
177%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
178% %
179% %
180% %
181% R e a d P C X I m a g e %
182% %
183% %
184% %
185%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
186%
187% ReadPCXImage() reads a ZSoft IBM PC Paintbrush file and returns it.
188% It allocates the memory necessary for the new Image structure and returns
189% a pointer to the new image.
190%
191% The format of the ReadPCXImage method is:
192%
193% Image *ReadPCXImage(const ImageInfo *image_info,ExceptionInfo *exception)
194%
195% A description of each parameter follows:
196%
197% o image_info: the image info.
198%
199% o exception: return any errors or warnings in this structure.
200%
201*/
202
cristybb503372010-05-27 20:51:26 +0000203static inline ssize_t MagickAbsoluteValue(const ssize_t x)
cristy3ed852e2009-09-05 21:47:34 +0000204{
205 if (x < 0)
206 return(-x);
207 return(x);
208}
209
210static inline size_t MagickMax(const size_t x,const size_t y)
211{
212 if (x > y)
213 return(x);
214 return(y);
215}
216
217static inline size_t MagickMin(const size_t x,const size_t y)
218{
219 if (x < y)
220 return(x);
221 return(y);
222}
223
224static Image *ReadPCXImage(const ImageInfo *image_info,ExceptionInfo *exception)
225{
226 Image
227 *image;
228
229 int
230 bits,
231 id,
232 mask;
233
cristy3ed852e2009-09-05 21:47:34 +0000234 MagickBooleanType
235 status;
236
237 MagickOffsetType
238 offset,
239 *page_table;
240
241 PCXInfo
242 pcx_info;
243
cristybb503372010-05-27 20:51:26 +0000244 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000245 x;
246
cristy4c08aed2011-07-01 19:47:50 +0000247 register Quantum
cristy3ed852e2009-09-05 21:47:34 +0000248 *q;
249
cristybb503372010-05-27 20:51:26 +0000250 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000251 i;
252
253 register unsigned char
254 *p,
255 *r;
256
cristyaff6d802011-04-26 01:46:31 +0000257 size_t
258 one,
259 pcx_packets;
260
cristy3ed852e2009-09-05 21:47:34 +0000261 ssize_t
cristyaff6d802011-04-26 01:46:31 +0000262 count,
263 y;
cristy3ed852e2009-09-05 21:47:34 +0000264
265 unsigned char
266 packet,
267 *pcx_colormap,
268 *pcx_pixels,
269 *scanline;
270
cristy3ed852e2009-09-05 21:47:34 +0000271 /*
272 Open image file.
273 */
274 assert(image_info != (const ImageInfo *) NULL);
275 assert(image_info->signature == MagickSignature);
276 if (image_info->debug != MagickFalse)
277 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
278 image_info->filename);
279 assert(exception != (ExceptionInfo *) NULL);
280 assert(exception->signature == MagickSignature);
cristy9950d572011-10-01 18:22:35 +0000281 image=AcquireImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +0000282 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
283 if (status == MagickFalse)
284 {
285 image=DestroyImageList(image);
286 return((Image *) NULL);
287 }
288 /*
289 Determine if this a PCX file.
290 */
291 page_table=(MagickOffsetType *) NULL;
292 if (LocaleCompare(image_info->magick,"DCX") == 0)
293 {
cristybb503372010-05-27 20:51:26 +0000294 size_t
cristy3ed852e2009-09-05 21:47:34 +0000295 magic;
296
297 /*
298 Read the DCX page table.
299 */
300 magic=ReadBlobLSBLong(image);
301 if (magic != 987654321)
302 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
303 page_table=(MagickOffsetType *) AcquireQuantumMemory(1024UL,
304 sizeof(*page_table));
305 if (page_table == (MagickOffsetType *) NULL)
306 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
307 for (id=0; id < 1024; id++)
308 {
309 page_table[id]=(MagickOffsetType) ReadBlobLSBLong(image);
310 if (page_table[id] == 0)
311 break;
312 }
313 }
314 if (page_table != (MagickOffsetType *) NULL)
315 {
316 offset=SeekBlob(image,(MagickOffsetType) page_table[0],SEEK_SET);
317 if (offset < 0)
318 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
319 }
320 pcx_colormap=(unsigned char *) NULL;
321 count=ReadBlob(image,1,&pcx_info.identifier);
322 for (id=1; id < 1024; id++)
323 {
324 /*
325 Verify PCX identifier.
326 */
327 pcx_info.version=(unsigned char) ReadBlobByte(image);
328 if ((count == 0) || (pcx_info.identifier != 0x0a))
329 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
330 pcx_info.encoding=(unsigned char) ReadBlobByte(image);
331 pcx_info.bits_per_pixel=(unsigned char) ReadBlobByte(image);
332 pcx_info.left=ReadBlobLSBShort(image);
333 pcx_info.top=ReadBlobLSBShort(image);
334 pcx_info.right=ReadBlobLSBShort(image);
335 pcx_info.bottom=ReadBlobLSBShort(image);
336 pcx_info.horizontal_resolution=ReadBlobLSBShort(image);
337 pcx_info.vertical_resolution=ReadBlobLSBShort(image);
338 /*
339 Read PCX raster colormap.
340 */
cristybb503372010-05-27 20:51:26 +0000341 image->columns=(size_t) MagickAbsoluteValue((ssize_t) pcx_info.right-
cristy3ed852e2009-09-05 21:47:34 +0000342 pcx_info.left)+1UL;
cristybb503372010-05-27 20:51:26 +0000343 image->rows=(size_t) MagickAbsoluteValue((ssize_t) pcx_info.bottom-
cristy3ed852e2009-09-05 21:47:34 +0000344 pcx_info.top)+1UL;
345 if ((image->columns == 0) || (image->rows == 0) ||
346 (pcx_info.bits_per_pixel == 0))
347 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
348 image->depth=pcx_info.bits_per_pixel <= 8 ? 8U : MAGICKCORE_QUANTUM_DEPTH;
349 image->units=PixelsPerInchResolution;
cristy2a11bef2011-10-28 18:33:11 +0000350 image->resolution.x=(double) pcx_info.horizontal_resolution;
351 image->resolution.y=(double) pcx_info.vertical_resolution;
cristy3ed852e2009-09-05 21:47:34 +0000352 image->colors=16;
353 pcx_colormap=(unsigned char *) AcquireQuantumMemory(256UL,
354 3*sizeof(*pcx_colormap));
355 if (pcx_colormap == (unsigned char *) NULL)
356 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
357 count=ReadBlob(image,3*image->colors,pcx_colormap);
358 pcx_info.reserved=(unsigned char) ReadBlobByte(image);
359 pcx_info.planes=(unsigned char) ReadBlobByte(image);
cristyeaedf062010-05-29 22:36:02 +0000360 one=1;
cristy3ed852e2009-09-05 21:47:34 +0000361 if ((pcx_info.bits_per_pixel != 8) || (pcx_info.planes == 1))
362 if ((pcx_info.version == 3) || (pcx_info.version == 5) ||
363 ((pcx_info.bits_per_pixel*pcx_info.planes) == 1))
cristyeaedf062010-05-29 22:36:02 +0000364 image->colors=(size_t) MagickMin(one << (1UL*
cristy3ed852e2009-09-05 21:47:34 +0000365 (pcx_info.bits_per_pixel*pcx_info.planes)),256UL);
cristy018f07f2011-09-04 21:15:19 +0000366 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000367 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
368 if ((pcx_info.bits_per_pixel >= 8) && (pcx_info.planes != 1))
369 image->storage_class=DirectClass;
370 p=pcx_colormap;
cristybb503372010-05-27 20:51:26 +0000371 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +0000372 {
373 image->colormap[i].red=ScaleCharToQuantum(*p++);
374 image->colormap[i].green=ScaleCharToQuantum(*p++);
375 image->colormap[i].blue=ScaleCharToQuantum(*p++);
376 }
377 pcx_info.bytes_per_line=ReadBlobLSBShort(image);
378 pcx_info.palette_info=ReadBlobLSBShort(image);
379 for (i=0; i < 58; i++)
380 (void) ReadBlobByte(image);
381 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
382 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
383 break;
384 /*
385 Read image data.
386 */
cristybb503372010-05-27 20:51:26 +0000387 pcx_packets=(size_t) image->rows*pcx_info.bytes_per_line*
cristy3ed852e2009-09-05 21:47:34 +0000388 pcx_info.planes;
389 pcx_pixels=(unsigned char *) AcquireQuantumMemory(pcx_packets,
390 sizeof(*pcx_pixels));
391 scanline=(unsigned char *) AcquireQuantumMemory(MagickMax(image->columns,
392 pcx_info.bytes_per_line),MagickMax(8,pcx_info.planes)*sizeof(*scanline));
393 if ((pcx_pixels == (unsigned char *) NULL) ||
394 (scanline == (unsigned char *) NULL))
395 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
396 /*
397 Uncompress image data.
398 */
399 p=pcx_pixels;
400 if (pcx_info.encoding == 0)
401 while (pcx_packets != 0)
402 {
403 packet=(unsigned char) ReadBlobByte(image);
404 if (EOFBlob(image) != MagickFalse)
405 break;
406 *p++=packet;
407 pcx_packets--;
408 }
409 else
410 while (pcx_packets != 0)
411 {
412 packet=(unsigned char) ReadBlobByte(image);
413 if (EOFBlob(image) != MagickFalse)
414 break;
415 if ((packet & 0xc0) != 0xc0)
416 {
417 *p++=packet;
418 pcx_packets--;
419 continue;
420 }
421 count=(ssize_t) (packet & 0x3f);
422 packet=(unsigned char) ReadBlobByte(image);
423 if (EOFBlob(image) != MagickFalse)
424 break;
425 for ( ; count != 0; count--)
426 {
427 *p++=packet;
428 pcx_packets--;
429 if (pcx_packets == 0)
430 break;
431 }
432 }
433 if (image->storage_class == DirectClass)
434 image->matte=pcx_info.planes > 3 ? MagickTrue : MagickFalse;
435 else
436 if ((pcx_info.version == 5) ||
437 ((pcx_info.bits_per_pixel*pcx_info.planes) == 1))
438 {
439 /*
440 Initialize image colormap.
441 */
442 if (image->colors > 256)
443 ThrowReaderException(CorruptImageError,"ColormapExceeds256Colors");
444 if ((pcx_info.bits_per_pixel*pcx_info.planes) == 1)
445 {
446 /*
447 Monochrome colormap.
448 */
449 image->colormap[0].red=(Quantum) 0;
450 image->colormap[0].green=(Quantum) 0;
451 image->colormap[0].blue=(Quantum) 0;
452 image->colormap[1].red=(Quantum) QuantumRange;
453 image->colormap[1].green=(Quantum) QuantumRange;
454 image->colormap[1].blue=(Quantum) QuantumRange;
455 }
456 else
457 if (image->colors > 16)
458 {
459 /*
460 256 color images have their color map at the end of the file.
461 */
462 pcx_info.colormap_signature=(unsigned char) ReadBlobByte(image);
463 count=ReadBlob(image,3*image->colors,pcx_colormap);
464 p=pcx_colormap;
cristybb503372010-05-27 20:51:26 +0000465 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +0000466 {
467 image->colormap[i].red=ScaleCharToQuantum(*p++);
468 image->colormap[i].green=ScaleCharToQuantum(*p++);
469 image->colormap[i].blue=ScaleCharToQuantum(*p++);
470 }
471 }
472 pcx_colormap=(unsigned char *) RelinquishMagickMemory(pcx_colormap);
473 }
474 /*
475 Convert PCX raster image to pixel packets.
476 */
cristybb503372010-05-27 20:51:26 +0000477 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000478 {
479 p=pcx_pixels+(y*pcx_info.bytes_per_line*pcx_info.planes);
480 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000481 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000482 break;
cristy3ed852e2009-09-05 21:47:34 +0000483 r=scanline;
484 if (image->storage_class == DirectClass)
485 for (i=0; i < pcx_info.planes; i++)
486 {
487 r=scanline+i;
cristybb503372010-05-27 20:51:26 +0000488 for (x=0; x < (ssize_t) pcx_info.bytes_per_line; x++)
cristy3ed852e2009-09-05 21:47:34 +0000489 {
490 switch (i)
491 {
492 case 0:
493 {
494 *r=(*p++);
495 break;
496 }
497 case 1:
498 {
499 *r=(*p++);
500 break;
501 }
502 case 2:
503 {
504 *r=(*p++);
505 break;
506 }
507 case 3:
508 default:
509 {
510 *r=(*p++);
511 break;
512 }
513 }
514 r+=pcx_info.planes;
515 }
516 }
517 else
518 if (pcx_info.planes > 1)
519 {
cristybb503372010-05-27 20:51:26 +0000520 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000521 *r++=0;
522 for (i=0; i < pcx_info.planes; i++)
523 {
524 r=scanline;
cristybb503372010-05-27 20:51:26 +0000525 for (x=0; x < (ssize_t) pcx_info.bytes_per_line; x++)
cristy3ed852e2009-09-05 21:47:34 +0000526 {
527 bits=(*p++);
528 for (mask=0x80; mask != 0; mask>>=1)
529 {
530 if (bits & mask)
531 *r|=1 << i;
532 r++;
533 }
534 }
535 }
536 }
537 else
538 switch (pcx_info.bits_per_pixel)
539 {
540 case 1:
541 {
cristybb503372010-05-27 20:51:26 +0000542 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000543 bit;
544
cristybb503372010-05-27 20:51:26 +0000545 for (x=0; x < ((ssize_t) image->columns-7); x+=8)
cristy3ed852e2009-09-05 21:47:34 +0000546 {
547 for (bit=7; bit >= 0; bit--)
548 *r++=(unsigned char) ((*p) & (0x01 << bit) ? 0x01 : 0x00);
549 p++;
550 }
551 if ((image->columns % 8) != 0)
552 {
cristybb503372010-05-27 20:51:26 +0000553 for (bit=7; bit >= (ssize_t) (8-(image->columns % 8)); bit--)
cristy3ed852e2009-09-05 21:47:34 +0000554 *r++=(unsigned char) ((*p) & (0x01 << bit) ? 0x01 : 0x00);
555 p++;
556 }
557 break;
558 }
559 case 2:
560 {
cristybb503372010-05-27 20:51:26 +0000561 for (x=0; x < ((ssize_t) image->columns-3); x+=4)
cristy3ed852e2009-09-05 21:47:34 +0000562 {
563 *r++=(*p >> 6) & 0x3;
564 *r++=(*p >> 4) & 0x3;
565 *r++=(*p >> 2) & 0x3;
566 *r++=(*p) & 0x3;
567 p++;
568 }
569 if ((image->columns % 4) != 0)
570 {
cristybb503372010-05-27 20:51:26 +0000571 for (i=3; i >= (ssize_t) (4-(image->columns % 4)); i--)
cristy3ed852e2009-09-05 21:47:34 +0000572 *r++=(unsigned char) ((*p >> (i*2)) & 0x03);
573 p++;
574 }
575 break;
576 }
577 case 4:
578 {
cristybb503372010-05-27 20:51:26 +0000579 for (x=0; x < ((ssize_t) image->columns-1); x+=2)
cristy3ed852e2009-09-05 21:47:34 +0000580 {
581 *r++=(*p >> 4) & 0xf;
582 *r++=(*p) & 0xf;
583 p++;
584 }
585 if ((image->columns % 2) != 0)
586 *r++=(*p++ >> 4) & 0xf;
587 break;
588 }
589 case 8:
590 {
591 (void) CopyMagickMemory(r,p,image->columns);
592 break;
593 }
594 default:
595 break;
596 }
597 /*
598 Transfer image scanline.
599 */
600 r=scanline;
cristybb503372010-05-27 20:51:26 +0000601 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000602 {
603 if (image->storage_class == PseudoClass)
cristy4c08aed2011-07-01 19:47:50 +0000604 SetPixelIndex(image,*r++,q);
cristy3ed852e2009-09-05 21:47:34 +0000605 else
606 {
cristy4c08aed2011-07-01 19:47:50 +0000607 SetPixelRed(image,ScaleCharToQuantum(*r++),q);
608 SetPixelGreen(image,ScaleCharToQuantum(*r++),q);
609 SetPixelBlue(image,ScaleCharToQuantum(*r++),q);
cristy3ed852e2009-09-05 21:47:34 +0000610 if (image->matte != MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000611 SetPixelAlpha(image,ScaleCharToQuantum(*r++),q);
cristy3ed852e2009-09-05 21:47:34 +0000612 }
cristyed231572011-07-14 02:18:59 +0000613 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000614 }
615 if (SyncAuthenticPixels(image,exception) == MagickFalse)
616 break;
617 if (image->previous == (Image *) NULL)
618 {
cristycee97112010-05-28 00:44:52 +0000619 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
cristyaff6d802011-04-26 01:46:31 +0000620 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000621 if (status == MagickFalse)
622 break;
623 }
624 }
625 if (image->storage_class == PseudoClass)
cristyea1a8aa2011-10-20 13:24:06 +0000626 (void) SyncImage(image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000627 scanline=(unsigned char *) RelinquishMagickMemory(scanline);
628 if (pcx_colormap != (unsigned char *) NULL)
629 pcx_colormap=(unsigned char *) RelinquishMagickMemory(pcx_colormap);
630 pcx_pixels=(unsigned char *) RelinquishMagickMemory(pcx_pixels);
631 if (EOFBlob(image) != MagickFalse)
632 {
633 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
634 image->filename);
635 break;
636 }
637 /*
638 Proceed to next image.
639 */
640 if (image_info->number_scenes != 0)
641 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
642 break;
643 if (page_table == (MagickOffsetType *) NULL)
644 break;
645 if (page_table[id] == 0)
646 break;
647 offset=SeekBlob(image,(MagickOffsetType) page_table[id],SEEK_SET);
648 if (offset < 0)
649 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
650 count=ReadBlob(image,1,&pcx_info.identifier);
651 if ((count != 0) && (pcx_info.identifier == 0x0a))
652 {
653 /*
654 Allocate next image structure.
655 */
cristy9950d572011-10-01 18:22:35 +0000656 AcquireNextImage(image_info,image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000657 if (GetNextImageInList(image) == (Image *) NULL)
658 {
659 image=DestroyImageList(image);
660 return((Image *) NULL);
661 }
662 image=SyncNextImageInList(image);
663 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
664 GetBlobSize(image));
665 if (status == MagickFalse)
666 break;
667 }
668 }
669 if (page_table != (MagickOffsetType *) NULL)
670 page_table=(MagickOffsetType *) RelinquishMagickMemory(page_table);
671 (void) CloseBlob(image);
672 return(GetFirstImageInList(image));
673}
674
675/*
676%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
677% %
678% %
679% %
680% R e g i s t e r P C X I m a g e %
681% %
682% %
683% %
684%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
685%
686% RegisterPCXImage() adds attributes for the PCX image format to
687% the list of supported formats. The attributes include the image format
688% tag, a method to read and/or write the format, whether the format
689% supports the saving of more than one frame to the same file or blob,
690% whether the format supports native in-memory I/O, and a brief
691% description of the format.
692%
693% The format of the RegisterPCXImage method is:
694%
cristybb503372010-05-27 20:51:26 +0000695% size_t RegisterPCXImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000696%
697*/
cristybb503372010-05-27 20:51:26 +0000698ModuleExport size_t RegisterPCXImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000699{
700 MagickInfo
701 *entry;
702
703 entry=SetMagickInfo("DCX");
704 entry->decoder=(DecodeImageHandler *) ReadPCXImage;
705 entry->encoder=(EncodeImageHandler *) WritePCXImage;
706 entry->seekable_stream=MagickTrue;
707 entry->magick=(IsImageFormatHandler *) IsDCX;
708 entry->description=ConstantString("ZSoft IBM PC multi-page Paintbrush");
709 entry->module=ConstantString("PCX");
710 (void) RegisterMagickInfo(entry);
711 entry=SetMagickInfo("PCX");
712 entry->decoder=(DecodeImageHandler *) ReadPCXImage;
713 entry->encoder=(EncodeImageHandler *) WritePCXImage;
714 entry->magick=(IsImageFormatHandler *) IsPCX;
715 entry->adjoin=MagickFalse;
716 entry->seekable_stream=MagickTrue;
717 entry->description=ConstantString("ZSoft IBM PC Paintbrush");
718 entry->module=ConstantString("PCX");
719 (void) RegisterMagickInfo(entry);
720 return(MagickImageCoderSignature);
721}
722
723/*
724%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
725% %
726% %
727% %
728% U n r e g i s t e r P C X I m a g e %
729% %
730% %
731% %
732%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
733%
734% UnregisterPCXImage() removes format registrations made by the
735% PCX module from the list of supported formats.
736%
737% The format of the UnregisterPCXImage method is:
738%
739% UnregisterPCXImage(void)
740%
741*/
742ModuleExport void UnregisterPCXImage(void)
743{
744 (void) UnregisterMagickInfo("DCX");
745 (void) UnregisterMagickInfo("PCX");
746}
747
748/*
749%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
750% %
751% %
752% %
753% W r i t e P C X I m a g e %
754% %
755% %
756% %
757%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
758%
759% WritePCXImage() writes an image in the ZSoft IBM PC Paintbrush file
760% format.
761%
762% The format of the WritePCXImage method is:
763%
cristy1e178e72011-08-28 19:44:34 +0000764% MagickBooleanType WritePCXImage(const ImageInfo *image_info,
765% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000766%
767% A description of each parameter follows.
768%
769% o image_info: the image info.
770%
771% o image: The image.
772%
cristy1e178e72011-08-28 19:44:34 +0000773% o exception: return any errors or warnings in this structure.
cristy3ed852e2009-09-05 21:47:34 +0000774%
775*/
cristy1e178e72011-08-28 19:44:34 +0000776
cristy3ed852e2009-09-05 21:47:34 +0000777static MagickBooleanType PCXWritePixels(PCXInfo *pcx_info,
778 const unsigned char *pixels,Image *image)
779{
780 register const unsigned char
781 *q;
782
cristybb503372010-05-27 20:51:26 +0000783 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000784 i,
785 x;
786
787 ssize_t
788 count;
789
790 unsigned char
791 packet,
792 previous;
793
794 q=pixels;
cristybb503372010-05-27 20:51:26 +0000795 for (i=0; i < (ssize_t) pcx_info->planes; i++)
cristy3ed852e2009-09-05 21:47:34 +0000796 {
cristy1f9852b2010-09-04 15:05:36 +0000797 if (pcx_info->encoding == 0)
cristy3ed852e2009-09-05 21:47:34 +0000798 {
cristy1f9852b2010-09-04 15:05:36 +0000799 for (x=0; x < (ssize_t) pcx_info->bytes_per_line; x++)
800 (void) WriteBlobByte(image,(unsigned char) (*q++));
cristy3ed852e2009-09-05 21:47:34 +0000801 }
cristy1f9852b2010-09-04 15:05:36 +0000802 else
803 {
804 previous=(*q++);
805 count=1;
806 for (x=0; x < (ssize_t) (pcx_info->bytes_per_line-1); x++)
807 {
808 packet=(*q++);
809 if ((packet == previous) && (count < 63))
810 {
811 count++;
812 continue;
813 }
814 if ((count > 1) || ((previous & 0xc0) == 0xc0))
815 {
816 count|=0xc0;
817 (void) WriteBlobByte(image,(unsigned char) count);
818 }
819 (void) WriteBlobByte(image,previous);
820 previous=packet;
821 count=1;
822 }
823 if ((count > 1) || ((previous & 0xc0) == 0xc0))
824 {
825 count|=0xc0;
826 (void) WriteBlobByte(image,(unsigned char) count);
827 }
828 (void) WriteBlobByte(image,previous);
829 }
cristy3ed852e2009-09-05 21:47:34 +0000830 }
831 return (MagickTrue);
832}
833
cristy1e178e72011-08-28 19:44:34 +0000834static MagickBooleanType WritePCXImage(const ImageInfo *image_info,Image *image,
835 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000836{
cristy3ed852e2009-09-05 21:47:34 +0000837 MagickBooleanType
838 status;
839
840 MagickOffsetType
841 offset,
842 *page_table,
843 scene;
844
845 PCXInfo
846 pcx_info;
847
cristy4c08aed2011-07-01 19:47:50 +0000848 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +0000849 *p;
850
cristybb503372010-05-27 20:51:26 +0000851 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000852 i,
853 x;
854
855 register unsigned char
856 *q;
857
858 size_t
859 length;
860
cristyaff6d802011-04-26 01:46:31 +0000861 ssize_t
862 y;
863
cristy3ed852e2009-09-05 21:47:34 +0000864 unsigned char
865 *pcx_colormap,
866 *pcx_pixels;
867
868 /*
869 Open output image file.
870 */
871 assert(image_info != (const ImageInfo *) NULL);
872 assert(image_info->signature == MagickSignature);
873 assert(image != (Image *) NULL);
874 assert(image->signature == MagickSignature);
875 if (image->debug != MagickFalse)
876 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy3a37efd2011-08-28 20:31:03 +0000877 assert(exception != (ExceptionInfo *) NULL);
878 assert(exception->signature == MagickSignature);
cristy1e178e72011-08-28 19:44:34 +0000879 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +0000880 if (status == MagickFalse)
881 return(status);
cristy510d06a2011-07-06 23:43:54 +0000882 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy8d951092012-02-08 18:54:56 +0000883 (void) TransformImageColorspace(image,sRGBColorspace,exception);
cristy3ed852e2009-09-05 21:47:34 +0000884 page_table=(MagickOffsetType *) NULL;
885 if ((LocaleCompare(image_info->magick,"DCX") == 0) ||
886 ((GetNextImageInList(image) != (Image *) NULL) &&
887 (image_info->adjoin != MagickFalse)))
888 {
889 /*
890 Write the DCX page table.
891 */
892 (void) WriteBlobLSBLong(image,0x3ADE68B1L);
893 page_table=(MagickOffsetType *) AcquireQuantumMemory(1024UL,
894 sizeof(*page_table));
895 if (page_table == (MagickOffsetType *) NULL)
896 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
897 for (scene=0; scene < 1024; scene++)
898 (void) WriteBlobLSBLong(image,0x00000000L);
899 }
900 scene=0;
901 do
902 {
903 if (page_table != (MagickOffsetType *) NULL)
904 page_table[scene]=TellBlob(image);
905 /*
906 Initialize PCX raster file header.
907 */
908 pcx_info.identifier=0x0a;
909 pcx_info.version=5;
cristy1f9852b2010-09-04 15:05:36 +0000910 pcx_info.encoding=image_info->compression == NoCompression ? 0 : 1;
cristy3ed852e2009-09-05 21:47:34 +0000911 pcx_info.bits_per_pixel=8;
912 if ((image->storage_class == PseudoClass) &&
cristy1e178e72011-08-28 19:44:34 +0000913 (IsImageMonochrome(image,exception) != MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +0000914 pcx_info.bits_per_pixel=1;
915 pcx_info.left=0;
916 pcx_info.top=0;
917 pcx_info.right=(unsigned short) (image->columns-1);
918 pcx_info.bottom=(unsigned short) (image->rows-1);
919 switch (image->units)
920 {
921 case UndefinedResolution:
922 case PixelsPerInchResolution:
923 default:
924 {
cristy2a11bef2011-10-28 18:33:11 +0000925 pcx_info.horizontal_resolution=(unsigned short) image->resolution.x;
926 pcx_info.vertical_resolution=(unsigned short) image->resolution.y;
cristy3ed852e2009-09-05 21:47:34 +0000927 break;
928 }
929 case PixelsPerCentimeterResolution:
930 {
931 pcx_info.horizontal_resolution=(unsigned short)
cristy2a11bef2011-10-28 18:33:11 +0000932 (2.54*image->resolution.x+0.5);
cristy3ed852e2009-09-05 21:47:34 +0000933 pcx_info.vertical_resolution=(unsigned short)
cristy2a11bef2011-10-28 18:33:11 +0000934 (2.54*image->resolution.y+0.5);
cristy3ed852e2009-09-05 21:47:34 +0000935 break;
936 }
937 }
938 pcx_info.reserved=0;
939 pcx_info.planes=1;
940 if ((image->storage_class == DirectClass) || (image->colors > 256))
941 {
942 pcx_info.planes=3;
943 if (image->matte != MagickFalse)
944 pcx_info.planes++;
945 }
cristybb503372010-05-27 20:51:26 +0000946 pcx_info.bytes_per_line=(unsigned short) (((size_t) image->columns*
cristy3ed852e2009-09-05 21:47:34 +0000947 pcx_info.bits_per_pixel+7)/8);
948 pcx_info.palette_info=1;
949 pcx_info.colormap_signature=0x0c;
950 /*
951 Write PCX header.
952 */
953 (void) WriteBlobByte(image,pcx_info.identifier);
954 (void) WriteBlobByte(image,pcx_info.version);
955 (void) WriteBlobByte(image,pcx_info.encoding);
956 (void) WriteBlobByte(image,pcx_info.bits_per_pixel);
957 (void) WriteBlobLSBShort(image,pcx_info.left);
958 (void) WriteBlobLSBShort(image,pcx_info.top);
959 (void) WriteBlobLSBShort(image,pcx_info.right);
960 (void) WriteBlobLSBShort(image,pcx_info.bottom);
961 (void) WriteBlobLSBShort(image,pcx_info.horizontal_resolution);
962 (void) WriteBlobLSBShort(image,pcx_info.vertical_resolution);
963 /*
964 Dump colormap to file.
965 */
966 pcx_colormap=(unsigned char *) AcquireQuantumMemory(256UL,
967 3*sizeof(*pcx_colormap));
968 if (pcx_colormap == (unsigned char *) NULL)
969 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
970 (void) memset(pcx_colormap,0,3*256*sizeof(*pcx_colormap));
971 q=pcx_colormap;
972 if ((image->storage_class == PseudoClass) && (image->colors <= 256))
cristybb503372010-05-27 20:51:26 +0000973 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +0000974 {
975 *q++=ScaleQuantumToChar(image->colormap[i].red);
976 *q++=ScaleQuantumToChar(image->colormap[i].green);
977 *q++=ScaleQuantumToChar(image->colormap[i].blue);
978 }
979 (void) WriteBlob(image,3*16,(const unsigned char *) pcx_colormap);
980 (void) WriteBlobByte(image,pcx_info.reserved);
981 (void) WriteBlobByte(image,pcx_info.planes);
982 (void) WriteBlobLSBShort(image,pcx_info.bytes_per_line);
983 (void) WriteBlobLSBShort(image,pcx_info.palette_info);
984 for (i=0; i < 58; i++)
985 (void) WriteBlobByte(image,'\0');
986 length=(size_t) pcx_info.bytes_per_line;
cristy1f9852b2010-09-04 15:05:36 +0000987 pcx_pixels=(unsigned char *) AcquireQuantumMemory(length,pcx_info.planes*
988 sizeof(*pcx_pixels));
cristy3ed852e2009-09-05 21:47:34 +0000989 if (pcx_pixels == (unsigned char *) NULL)
990 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
991 q=pcx_pixels;
992 if ((image->storage_class == DirectClass) || (image->colors > 256))
993 {
cristy4c08aed2011-07-01 19:47:50 +0000994 const Quantum
cristy3ed852e2009-09-05 21:47:34 +0000995 *pixels;
996
997 /*
998 Convert DirectClass image to PCX raster pixels.
999 */
cristybb503372010-05-27 20:51:26 +00001000 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001001 {
cristy1e178e72011-08-28 19:44:34 +00001002 pixels=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001003 if (pixels == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001004 break;
1005 q=pcx_pixels;
1006 for (i=0; i < pcx_info.planes; i++)
1007 {
1008 p=pixels;
1009 switch ((int) i)
1010 {
1011 case 0:
1012 {
cristybb503372010-05-27 20:51:26 +00001013 for (x=0; x < (ssize_t) pcx_info.bytes_per_line; x++)
cristy3ed852e2009-09-05 21:47:34 +00001014 {
cristy4c08aed2011-07-01 19:47:50 +00001015 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
cristyed231572011-07-14 02:18:59 +00001016 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001017 }
1018 break;
1019 }
1020 case 1:
1021 {
cristybb503372010-05-27 20:51:26 +00001022 for (x=0; x < (ssize_t) pcx_info.bytes_per_line; x++)
cristy3ed852e2009-09-05 21:47:34 +00001023 {
cristy4c08aed2011-07-01 19:47:50 +00001024 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
cristyed231572011-07-14 02:18:59 +00001025 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001026 }
1027 break;
1028 }
1029 case 2:
1030 {
cristybb503372010-05-27 20:51:26 +00001031 for (x=0; x < (ssize_t) pcx_info.bytes_per_line; x++)
cristy3ed852e2009-09-05 21:47:34 +00001032 {
cristy4c08aed2011-07-01 19:47:50 +00001033 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
cristyed231572011-07-14 02:18:59 +00001034 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001035 }
1036 break;
1037 }
1038 case 3:
1039 default:
1040 {
cristybb503372010-05-27 20:51:26 +00001041 for (x=(ssize_t) pcx_info.bytes_per_line; x != 0; x--)
cristy3ed852e2009-09-05 21:47:34 +00001042 {
cristy4c08aed2011-07-01 19:47:50 +00001043 *q++=ScaleQuantumToChar((Quantum) (GetPixelAlpha(image,p)));
cristyed231572011-07-14 02:18:59 +00001044 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001045 }
1046 break;
1047 }
1048 }
1049 }
1050 if (PCXWritePixels(&pcx_info,pcx_pixels,image) == MagickFalse)
1051 break;
1052 if (image->previous == (Image *) NULL)
1053 {
cristycee97112010-05-28 00:44:52 +00001054 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1055 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001056 if (status == MagickFalse)
1057 break;
1058 }
1059 }
1060 }
1061 else
1062 {
1063 if (pcx_info.bits_per_pixel > 1)
cristybb503372010-05-27 20:51:26 +00001064 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001065 {
cristy1e178e72011-08-28 19:44:34 +00001066 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001067 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001068 break;
cristy3ed852e2009-09-05 21:47:34 +00001069 q=pcx_pixels;
cristybb503372010-05-27 20:51:26 +00001070 for (x=0; x < (ssize_t) image->columns; x++)
cristy4c08aed2011-07-01 19:47:50 +00001071 {
1072 *q++=(unsigned char) GetPixelIndex(image,p);
cristyed231572011-07-14 02:18:59 +00001073 p+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00001074 }
cristy3ed852e2009-09-05 21:47:34 +00001075 if (PCXWritePixels(&pcx_info,pcx_pixels,image) == MagickFalse)
1076 break;
1077 if (image->previous == (Image *) NULL)
1078 {
cristycee97112010-05-28 00:44:52 +00001079 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1080 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001081 if (status == MagickFalse)
1082 break;
1083 }
1084 }
1085 else
1086 {
cristy4c08aed2011-07-01 19:47:50 +00001087 Quantum
cristy3ed852e2009-09-05 21:47:34 +00001088 polarity;
1089
1090 register unsigned char
1091 bit,
1092 byte;
1093
1094 /*
1095 Convert PseudoClass image to a PCX monochrome image.
1096 */
cristy101ab702011-10-13 13:06:32 +00001097 polarity=(Quantum) (GetPixelInfoIntensity(
cristy3ed852e2009-09-05 21:47:34 +00001098 &image->colormap[0]) < ((Quantum) QuantumRange/2) ? 1 : 0);
1099 if (image->colors == 2)
cristy101ab702011-10-13 13:06:32 +00001100 polarity=(Quantum) (GetPixelInfoIntensity(&image->colormap[0]) <
1101 GetPixelInfoIntensity(&image->colormap[1]) ? 1 : 0);
cristybb503372010-05-27 20:51:26 +00001102 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001103 {
cristy1e178e72011-08-28 19:44:34 +00001104 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001105 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001106 break;
cristy3ed852e2009-09-05 21:47:34 +00001107 bit=0;
1108 byte=0;
1109 q=pcx_pixels;
cristybb503372010-05-27 20:51:26 +00001110 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001111 {
1112 byte<<=1;
cristy4c08aed2011-07-01 19:47:50 +00001113 if (GetPixelIndex(image,p) == polarity)
cristy3ed852e2009-09-05 21:47:34 +00001114 byte|=0x01;
1115 bit++;
1116 if (bit == 8)
1117 {
1118 *q++=byte;
1119 bit=0;
1120 byte=0;
1121 }
cristyed231572011-07-14 02:18:59 +00001122 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001123 }
1124 if (bit != 0)
1125 *q++=byte << (8-bit);
1126 if (PCXWritePixels(&pcx_info,pcx_pixels,image) == MagickFalse)
1127 break;
1128 if (image->previous == (Image *) NULL)
1129 {
cristy1f9852b2010-09-04 15:05:36 +00001130 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1131 y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001132 if (status == MagickFalse)
1133 break;
1134 }
1135 }
1136 }
1137 (void) WriteBlobByte(image,pcx_info.colormap_signature);
1138 (void) WriteBlob(image,3*256,pcx_colormap);
1139 }
1140 pcx_pixels=(unsigned char *) RelinquishMagickMemory(pcx_pixels);
1141 pcx_colormap=(unsigned char *) RelinquishMagickMemory(pcx_colormap);
cristyc044c482010-03-03 03:21:55 +00001142 if (page_table == (MagickOffsetType *) NULL)
1143 break;
1144 if (scene >= 1023)
1145 break;
cristy3ed852e2009-09-05 21:47:34 +00001146 if (GetNextImageInList(image) == (Image *) NULL)
1147 break;
1148 image=SyncNextImageInList(image);
1149 status=SetImageProgress(image,SaveImagesTag,scene++,
1150 GetImageListLength(image));
1151 if (status == MagickFalse)
1152 break;
cristy3ed852e2009-09-05 21:47:34 +00001153 } while (image_info->adjoin != MagickFalse);
1154 if (page_table != (MagickOffsetType *) NULL)
1155 {
1156 /*
1157 Write the DCX page table.
1158 */
1159 page_table[scene+1]=0;
1160 offset=SeekBlob(image,0L,SEEK_SET);
1161 if (offset < 0)
1162 ThrowWriterException(CorruptImageError,"ImproperImageHeader");
1163 (void) WriteBlobLSBLong(image,0x3ADE68B1L);
cristybb503372010-05-27 20:51:26 +00001164 for (i=0; i <= (ssize_t) scene; i++)
cristy0b29b252010-05-30 01:59:46 +00001165 (void) WriteBlobLSBLong(image,(unsigned int) page_table[i]);
cristy3ed852e2009-09-05 21:47:34 +00001166 page_table=(MagickOffsetType *) RelinquishMagickMemory(page_table);
1167 }
1168 if (status == MagickFalse)
1169 {
1170 char
1171 *message;
1172
1173 message=GetExceptionMessage(errno);
cristy1e178e72011-08-28 19:44:34 +00001174 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
1175 "UnableToWriteFile","`%s': %s",image->filename,message);
cristy3ed852e2009-09-05 21:47:34 +00001176 message=DestroyString(message);
1177 }
1178 (void) CloseBlob(image);
1179 return(MagickTrue);
1180}