1 /* Copyright (C) 2001-2012 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied,
8    modified or distributed except as expressly authorized under the terms
9    of the license contained in the file LICENSE in this distribution.
10 
11    Refer to licensing information at http://www.artifex.com or contact
12    Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134, San Rafael,
13    CA  94903, U.S.A., +1(415)492-9861, for further information.
14 */
15 
16 
17 /* PCX file format drivers */
18 #include "gdevprn.h"
19 #include "gdevpccm.h"
20 #include "gxlum.h"
21 
22 /* Thanks to Phil Conrad for donating the original version */
23 /* of these drivers to Aladdin Enterprises. */
24 
25 /* ------ The device descriptors ------ */
26 
27 /*
28  * Default X and Y resolution.
29  */
30 #define X_DPI 72
31 #define Y_DPI 72
32 
33 /* Monochrome. */
34 
35 static dev_proc_print_page(pcxmono_print_page);
36 
37 /* Use the default RGB->color map, so we get black=0, white=1. */
38 static const gx_device_procs pcxmono_procs =
39 prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
40                 gx_default_map_rgb_color, gx_default_map_color_rgb);
41 const gx_device_printer gs_pcxmono_device =
42 prn_device(pcxmono_procs, "pcxmono",
43            DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
44            X_DPI, Y_DPI,
45            0, 0, 0, 0,		/* margins */
46            1, pcxmono_print_page);
47 
48 /* Chunky 8-bit gray scale. */
49 
50 static dev_proc_print_page(pcx256_print_page);
51 
52 static const gx_device_procs pcxgray_procs =
53 prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
54               gx_default_gray_map_rgb_color, gx_default_gray_map_color_rgb);
55 const gx_device_printer gs_pcxgray_device =
56 {prn_device_body(gx_device_printer, pcxgray_procs, "pcxgray",
57                  DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
58                  X_DPI, Y_DPI,
59                  0, 0, 0, 0,	/* margins */
60                  1, 8, 255, 255, 256, 256, pcx256_print_page)
61 };
62 
63 /* 4-bit planar (EGA/VGA-style) color. */
64 
65 static dev_proc_print_page(pcx16_print_page);
66 
67 static const gx_device_procs pcx16_procs =
68 prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
69                 pc_4bit_map_rgb_color, pc_4bit_map_color_rgb);
70 const gx_device_printer gs_pcx16_device =
71 {prn_device_body(gx_device_printer, pcx16_procs, "pcx16",
72                  DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
73                  X_DPI, Y_DPI,
74                  0, 0, 0, 0,	/* margins */
75                  3, 4, 1, 1, 2, 2, pcx16_print_page)
76 };
77 
78 /* Chunky 8-bit (SuperVGA-style) color. */
79 /* (Uses a fixed palette of 3,3,2 bits.) */
80 
81 static const gx_device_procs pcx256_procs =
82 prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
83                 pc_8bit_map_rgb_color, pc_8bit_map_color_rgb);
84 const gx_device_printer gs_pcx256_device =
85 {prn_device_body(gx_device_printer, pcx256_procs, "pcx256",
86                  DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
87                  X_DPI, Y_DPI,
88                  0, 0, 0, 0,	/* margins */
89                  3, 8, 5, 5, 6, 6, pcx256_print_page)
90 };
91 
92 /* 24-bit color, 3 8-bit planes. */
93 
94 static dev_proc_print_page(pcx24b_print_page);
95 
96 static const gx_device_procs pcx24b_procs =
97 prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
98                 gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb);
99 const gx_device_printer gs_pcx24b_device =
100 prn_device(pcx24b_procs, "pcx24b",
101            DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
102            X_DPI, Y_DPI,
103            0, 0, 0, 0,		/* margins */
104            24, pcx24b_print_page);
105 
106 /* 4-bit chunky CMYK color. */
107 
108 static dev_proc_print_page(pcxcmyk_print_page);
109 
110 static const gx_device_procs pcxcmyk_procs =
111 {
112     gdev_prn_open,
113     NULL,			/* get_initial_matrix */
114     NULL,			/* sync_output */
115     gdev_prn_output_page,
116     gdev_prn_close,
117     NULL,			/* map_rgb_color */
118     cmyk_1bit_map_color_rgb,
119     NULL,			/* fill_rectangle */
120     NULL,			/* tile_rectangle */
121     NULL,			/* copy_mono */
122     NULL,			/* copy_color */
123     NULL,			/* draw_line */
124     NULL,			/* get_bits */
125     gdev_prn_get_params,
126     gdev_prn_put_params,
127     cmyk_1bit_map_cmyk_color,
128     NULL,			/* get_xfont_procs */
129     NULL,			/* get_xfont_device */
130     NULL,			/* map_rgb_alpha_color */
131     gx_page_device_get_page_device
132 };
133 const gx_device_printer gs_pcxcmyk_device =
134 {prn_device_body(gx_device_printer, pcxcmyk_procs, "pcxcmyk",
135                  DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
136                  X_DPI, Y_DPI,
137                  0, 0, 0, 0,	/* margins */
138                  4, 4, 1, 1, 2, 2, pcxcmyk_print_page)
139 };
140 
141 /* ------ Private definitions ------ */
142 
143 /* All two-byte quantities are stored LSB-first! */
144 #if arch_is_big_endian
145 #  define assign_ushort(a,v) a = ((v) >> 8) + ((v) << 8)
146 #else
147 #  define assign_ushort(a,v) a = (v)
148 #endif
149 
150 typedef struct pcx_header_s {
151     byte manuf;			/* always 0x0a */
152     byte version;
153 #define version_2_5			0
154 #define version_2_8_with_palette	2
155 #define version_2_8_without_palette	3
156 #define version_3_0 /* with palette */	5
157     byte encoding;		/* 1=RLE */
158     byte bpp;			/* bits per pixel per plane */
159     ushort x1;			/* X of upper left corner */
160     ushort y1;			/* Y of upper left corner */
161     ushort x2;			/* x1 + width - 1 */
162     ushort y2;			/* y1 + height - 1 */
163     ushort hres;		/* horz. resolution (dots per inch) */
164     ushort vres;		/* vert. resolution (dots per inch) */
165     byte palette[16 * 3];	/* color palette */
166     byte reserved;
167     byte nplanes;		/* number of color planes */
168     ushort bpl;			/* number of bytes per line (uncompressed) */
169     ushort palinfo;
170 #define palinfo_color	1
171 #define palinfo_gray	2
172     byte xtra[58];		/* fill out header to 128 bytes */
173 } pcx_header;
174 
175 /* Define the prototype header. */
176 static const pcx_header pcx_header_prototype =
177 {
178     10,				/* manuf */
179     0,				/* version (variable) */
180     1,				/* encoding */
181     0,				/* bpp (variable) */
182     00, 00,			/* x1, y1 */
183     00, 00,			/* x2, y2 (variable) */
184     00, 00,			/* hres, vres (variable) */
185     {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* palette (variable) */
186      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
187      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
188      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
189     0,				/* reserved */
190     0,				/* nplanes (variable) */
191     00,				/* bpl (variable) */
192     00,				/* palinfo (variable) */
193     {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* xtra */
194      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
195      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
196      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
197 };
198 
199 /*
200  * Define the DCX header.  We don't actually use this yet.
201  * All quantities are stored little-endian!
202  bytes 0-3: ID = 987654321
203  bytes 4-7: file offset of page 1
204  [... up to 1023 entries ...]
205  bytes N-N+3: 0 to mark end of page list
206  * This is followed by the pages in order, each of which is a PCX file.
207  */
208 #define dcx_magic 987654321
209 #define dcx_max_pages 1023
210 
211 /* Forward declarations */
212 static void pcx_write_rle(const byte *, const byte *, int, FILE *);
213 static int pcx_write_page(gx_device_printer *, FILE *, pcx_header *, bool);
214 
215 /* Write a monochrome PCX page. */
216 static int
pcxmono_print_page(gx_device_printer * pdev,FILE * file)217 pcxmono_print_page(gx_device_printer * pdev, FILE * file)
218 {
219     pcx_header header;
220 
221     header = pcx_header_prototype;
222     header.version = version_2_8_with_palette;
223     header.bpp = 1;
224     header.nplanes = 1;
225     assign_ushort(header.palinfo, palinfo_gray);
226     /* Set the first two entries of the short palette. */
227     memcpy((byte *) header.palette, "\000\000\000\377\377\377", 6);
228     return pcx_write_page(pdev, file, &header, false);
229 }
230 
231 /* Write an "old" PCX page. */
232 static const byte pcx_ega_palette[16 * 3] =
233 {
234     0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0x00, 0xaa, 0xaa,
235     0xaa, 0x00, 0x00, 0xaa, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0xaa, 0xaa, 0xaa,
236     0x55, 0x55, 0x55, 0x55, 0x55, 0xff, 0x55, 0xff, 0x55, 0x55, 0xff, 0xff,
237     0xff, 0x55, 0x55, 0xff, 0x55, 0xff, 0xff, 0xff, 0x55, 0xff, 0xff, 0xff
238 };
239 static int
pcx16_print_page(gx_device_printer * pdev,FILE * file)240 pcx16_print_page(gx_device_printer * pdev, FILE * file)
241 {
242     pcx_header header;
243 
244     header = pcx_header_prototype;
245     header.version = version_2_8_with_palette;
246     header.bpp = 1;
247     header.nplanes = 4;
248     /* Fill the EGA palette appropriately. */
249     memcpy((byte *) header.palette, pcx_ega_palette,
250            sizeof(pcx_ega_palette));
251     return pcx_write_page(pdev, file, &header, true);
252 }
253 
254 /* Write a "new" PCX page. */
255 static int
pcx256_print_page(gx_device_printer * pdev,FILE * file)256 pcx256_print_page(gx_device_printer * pdev, FILE * file)
257 {
258     pcx_header header;
259     int code;
260 
261     header = pcx_header_prototype;
262     header.version = version_3_0;
263     header.bpp = 8;
264     header.nplanes = 1;
265     assign_ushort(header.palinfo,
266                   (pdev->color_info.num_components > 1 ?
267                    palinfo_color : palinfo_gray));
268     code = pcx_write_page(pdev, file, &header, false);
269     if (code >= 0) {		/* Write out the palette. */
270         fputc(0x0c, file);
271         code = pc_write_palette((gx_device *) pdev, 256, file);
272     }
273     return code;
274 }
275 
276 /* Write a 24-bit color PCX page. */
277 static int
pcx24b_print_page(gx_device_printer * pdev,FILE * file)278 pcx24b_print_page(gx_device_printer * pdev, FILE * file)
279 {
280     pcx_header header;
281 
282     header = pcx_header_prototype;
283     header.version = version_3_0;
284     header.bpp = 8;
285     header.nplanes = 3;
286     assign_ushort(header.palinfo, palinfo_color);
287     return pcx_write_page(pdev, file, &header, true);
288 }
289 
290 /* Write a 4-bit chunky CMYK color PCX page. */
291 static const byte pcx_cmyk_palette[16 * 3] =
292 {
293     0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x0f, 0x0f, 0x00,
294     0xff, 0x00, 0xff, 0x0f, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x0f, 0x00, 0x00,
295     0x00, 0xff, 0xff, 0x00, 0x0f, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x00,
296     0x00, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x1f, 0x1f, 0x1f, 0x0f, 0x0f, 0x0f,
297 };
298 static int
pcxcmyk_print_page(gx_device_printer * pdev,FILE * file)299 pcxcmyk_print_page(gx_device_printer * pdev, FILE * file)
300 {
301     pcx_header header;
302 
303     header = pcx_header_prototype;
304     header.version = 2;
305     header.bpp = 4;
306     header.nplanes = 1;
307     /* Fill the palette appropriately. */
308     memcpy((byte *) header.palette, pcx_cmyk_palette,
309            sizeof(pcx_cmyk_palette));
310     return pcx_write_page(pdev, file, &header, false);
311 }
312 
313 /* Write out a page in PCX format. */
314 /* This routine is used for all formats. */
315 /* The caller has set header->bpp, nplanes, and palette. */
316 static int
pcx_write_page(gx_device_printer * pdev,FILE * file,pcx_header * phdr,bool planar)317 pcx_write_page(gx_device_printer * pdev, FILE * file, pcx_header * phdr,
318                bool planar)
319 {
320     int raster = gdev_prn_raster(pdev);
321     uint rsize = ROUND_UP((pdev->width * phdr->bpp + 7) >> 3, 2);	/* PCX format requires even */
322     int height = pdev->height;
323     int depth = pdev->color_info.depth;
324     uint lsize = raster + rsize;
325     byte *line = gs_alloc_bytes(pdev->memory, lsize, "pcx file buffer");
326     byte *plane = line + raster;
327     int y;
328     int code = 0;		/* return code */
329 
330     if (line == 0)		/* can't allocate line buffer */
331         return_error(gs_error_VMerror);
332 
333     /* Fill in the other variable entries in the header struct. */
334 
335     assign_ushort(phdr->x2, pdev->width - 1);
336     assign_ushort(phdr->y2, height - 1);
337     assign_ushort(phdr->hres, (int)pdev->x_pixels_per_inch);
338     assign_ushort(phdr->vres, (int)pdev->y_pixels_per_inch);
339     assign_ushort(phdr->bpl, (planar || depth == 1 ? rsize :
340                               raster + (raster & 1)));
341 
342     /* Write the header. */
343 
344     if (fwrite((const char *)phdr, 1, 128, file) < 128) {
345         code = gs_error_ioerror;
346         goto pcx_done;
347     }
348     /* Write the contents of the image. */
349     for (y = 0; y < height; y++) {
350         byte *row;
351         byte *end;
352 
353         code = gdev_prn_get_bits(pdev, y, line, &row);
354         if (code < 0)
355             break;
356         end = row + raster;
357         if (!planar) {		/* Just write the bits. */
358             if (raster & 1) {	/* Round to even, with predictable padding. */
359                 *end = end[-1];
360                 ++end;
361             }
362             pcx_write_rle(row, end, 1, file);
363         } else
364             switch (depth) {
365 
366                 case 4:
367                     {
368                         byte *pend = plane + rsize;
369                         int shift;
370 
371                         for (shift = 0; shift < 4; shift++) {
372                             register byte *from, *to;
373                             register int bright = 1 << shift;
374                             register int bleft = bright << 4;
375 
376                             for (from = row, to = plane;
377                                  from < end; from += 4
378                                 ) {
379                                 *to++ =
380                                     (from[0] & bleft ? 0x80 : 0) |
381                                     (from[0] & bright ? 0x40 : 0) |
382                                     (from[1] & bleft ? 0x20 : 0) |
383                                     (from[1] & bright ? 0x10 : 0) |
384                                     (from[2] & bleft ? 0x08 : 0) |
385                                     (from[2] & bright ? 0x04 : 0) |
386                                     (from[3] & bleft ? 0x02 : 0) |
387                                     (from[3] & bright ? 0x01 : 0);
388                             }
389                             /* We might be one byte short of rsize. */
390                             if (to < pend)
391                                 *to = to[-1];
392                             pcx_write_rle(plane, pend, 1, file);
393                         }
394                     }
395                     break;
396 
397                 case 24:
398                     {
399                         int pnum;
400 
401                         for (pnum = 0; pnum < 3; ++pnum) {
402                             pcx_write_rle(row + pnum, row + raster, 3, file);
403                             if (pdev->width & 1)
404                                 fputc(0, file);		/* pad to even */
405                         }
406                     }
407                     break;
408 
409                 default:
410                     code = gs_note_error(gs_error_rangecheck);
411                     goto pcx_done;
412 
413             }
414     }
415 
416   pcx_done:
417     gs_free_object(pdev->memory, line, "pcx file buffer");
418 
419     return code;
420 }
421 
422 /* ------ Internal routines ------ */
423 
424 /* Write one line in PCX run-length-encoded format. */
425 static void
pcx_write_rle(const byte * from,const byte * end,int step,FILE * file)426 pcx_write_rle(const byte * from, const byte * end, int step, FILE * file)
427 {				/*
428                                  * The PCX format theoretically allows encoding runs of 63
429                                  * identical bytes, but some readers can't handle repetition
430                                  * counts greater than 15.
431                                  */
432 #define MAX_RUN_COUNT 15
433     int max_run = step * MAX_RUN_COUNT;
434 
435     while (from < end) {
436         byte data = *from;
437 
438         from += step;
439         if (data != *from || from == end) {
440             if (data >= 0xc0)
441                 putc(0xc1, file);
442         } else {
443             const byte *start = from;
444 
445             while ((from < end) && (*from == data))
446                 from += step;
447             /* Now (from - start) / step + 1 is the run length. */
448             while (from - start >= max_run) {
449                 putc(0xc0 + MAX_RUN_COUNT, file);
450                 putc(data, file);
451                 start += max_run;
452             }
453             if (from > start || data >= 0xc0)
454                 putc((from - start) / step + 0xc1, file);
455         }
456         putc(data, file);
457     }
458 #undef MAX_RUN_COUNT
459 }
460