Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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