386BSD 0.1 development
[unix-history] / usr / othersrc / public / ghostscript-2.4.1 / gdevpcx.c
CommitLineData
1eff4643
WJ
1/* Copyright (C) 1992 Aladdin Enterprises. All rights reserved.
2 Distributed by Free Software Foundation, Inc.
3
4This file is part of Ghostscript.
5
6Ghostscript is distributed in the hope that it will be useful, but
7WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
8to anyone for the consequences of using it or for whether it serves any
9particular purpose or works at all, unless he says so in writing. Refer
10to the Ghostscript General Public License for full details.
11
12Everyone is granted permission to copy, modify and redistribute
13Ghostscript, but only under the conditions described in the Ghostscript
14General Public License. A copy of this license is supposed to have been
15given to you along with Ghostscript so you can know your rights and
16responsibilities. It should be in a file named COPYING. Among other
17things, the copyright notice and this notice must be preserved on all
18copies. */
19
20/* gdevpcx.c */
21/* PCX file format devices for Ghostscript */
22#include "gdevprn.h"
23#include "gserrors.h" /* REALLY? */
24#include "gdevpccm.h"
25
26/* Thanks to Phil Conrad for donating the original version */
27/* of these drivers to Aladdin Enterprises. */
28
29/* ------ The device descriptors ------ */
30
31/*
32 * Standard U.S. page width and height. A4 paper is 8.4" x 11.7".
33 */
34#define WIDTH_10THS 85
35#define HEIGHT_10THS 110
36
37/*
38 * Default X and Y resolution.
39 */
40#define X_DPI 72
41#define Y_DPI 72
42
43/* Monochrome. */
44
45private dev_proc_print_page(pcxmono_print_page);
46
47gx_device_printer gs_pcxmono_device =
48 prn_device(prn_std_procs, "pcxmono",
49 WIDTH_10THS, HEIGHT_10THS,
50 X_DPI, Y_DPI,
51 0,0,0,0, /* margins */
52 1, pcxmono_print_page);
53
54/* 4-bit planar (EGA/VGA-style) color. */
55
56private dev_proc_print_page(pcx16_print_page);
57
58private gx_device_procs pcx16_procs =
59 prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
60 pc_4bit_map_rgb_color, pc_4bit_map_color_rgb);
61gx_device_printer gs_pcx16_device =
62 prn_device(pcx16_procs, "pcx16",
63 WIDTH_10THS, HEIGHT_10THS,
64 X_DPI, Y_DPI,
65 0,0,0,0, /* margins */
66 4, pcx16_print_page);
67
68/* Chunky 8-bit (SuperVGA-style) color. */
69/* (Uses a fixed palette of 3,3,2 bits.) */
70
71private dev_proc_print_page(pcx256_print_page);
72
73private gx_device_procs pcx256_procs =
74 prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
75 pc_8bit_map_rgb_color, pc_8bit_map_color_rgb);
76gx_device_printer gs_pcx256_device =
77 prn_device(pcx256_procs, "pcx256",
78 WIDTH_10THS, HEIGHT_10THS,
79 X_DPI, Y_DPI,
80 0,0,0,0, /* margins */
81 8, pcx256_print_page);
82
83/* ------ Private definitions ------ */
84
85typedef struct pcx_header_s {
86 byte manuf; /* always 0x0a */
87 byte version; /* version info = 0,2,3,5 */
88 byte encoding; /* 1=RLE */
89 byte bpp; /* bits per pixel */
90 ushort x1; /* picture dimensions */
91 ushort y1;
92 ushort x2;
93 ushort y2;
94 ushort hres; /* horz. resolution */
95 ushort vres; /* vert. resolution */
96 byte palette[16*3]; /* color palette */
97 byte vmode; /* video mode for graphics board */
98 byte nplanes; /* number of color planes */
99 ushort bpl; /* number of bytes per line (uncompresses) */
100 ushort palinfo; /* palette info 1=color, 2=grey */
101 ushort shres; /* scanner horz. resolution */
102 ushort svres; /* scanner vert. resolution */
103 byte xtra[58]; /* fill out header to 128 bytes */
104} pcx_header;
105
106/*
107** version info for PCX is as follows
108**
109** 0 == 2.5
110** 2 == 2.8 w/palette info
111** 3 == 2.8 without palette info
112** 5 == 3.0
113**
114*/
115
116/* Forward declarations */
117private void pcx_write_rle(P3(byte *, byte *, FILE *));
118private int pcx_write_page(P4(gx_device_printer *, FILE *, pcx_header _ss *, int));
119
120/* Write an "old" PCX page. */
121static byte ega_palette[16*3] = {
122 0x00,0x00,0x00, 0x00,0x00,0xaa, 0x00,0xaa,0x00, 0x00,0xaa,0xaa,
123 0xaa,0x00,0x00, 0xaa,0x00,0xaa, 0xaa,0xaa,0x00, 0xaa,0xaa,0xaa,
124 0x55,0x55,0x55, 0x55,0x55,0xff, 0x55,0xff,0x55, 0x55,0xff,0xff,
125 0xff,0x55,0x55, 0xff,0x55,0xff, 0xff,0xff,0x55, 0xff,0xff,0xff
126};
127private int
128pcx16_print_page(gx_device_printer *pdev, FILE *file)
129{ pcx_header header;
130 header.version = 2;
131 header.bpp = 1;
132 header.nplanes = 4;
133 /* Fill the EGA palette appropriately. */
134 memcpy((byte *)header.palette, ega_palette, sizeof(ega_palette));
135 return pcx_write_page(pdev, file, &header, 1);
136}
137
138/* Write a "new" PCX page. */
139private int
140pcx256_print_page(gx_device_printer *pdev, FILE *file)
141{ pcx_header header;
142 int code;
143 header.version = 5;
144 header.bpp = 8;
145 header.nplanes = 1;
146 /* Clear the EGA palette */
147 memset((byte *)header.palette, 0, sizeof(header.palette));
148 code = pcx_write_page(pdev, file, &header, 0);
149 if ( code >= 0 )
150 { /* Write out the palette. */
151 fputc(0x0c, file);
152 code = pc_write_palette((gx_device *)pdev, 256, file);
153 }
154 return code;
155}
156
157/* Write a monochrome PCX page. */
158private int
159pcxmono_print_page(gx_device_printer *pdev, FILE *file)
160{ pcx_header header;
161 header.version = 2;
162 header.bpp = 1;
163 header.nplanes = 1;
164 /* Clear the EGA palette */
165 memset((byte *)header.palette, 0, sizeof(header.palette));
166 return pcx_write_page(pdev, file, &header, 0);
167}
168
169/* Write out a page in PCX format. */
170/* This routine is used for all three formats (monochrome, planar */
171/* "8-bit" actually 4-bit color, and chunky 8-bit color.) */
172private int
173pcx_write_page(gx_device_printer *pdev, FILE *file, pcx_header _ss *phdr,
174 int planar)
175{ int raster = gdev_prn_bytes_per_scan_line(pdev);
176 int height = pdev->height;
177 int depth = pdev->color_info.depth;
178 uint rsize = (pdev->width + 7) >> 3;
179 byte *row = (byte *)gs_malloc(raster + rsize, 1, "pcx file buffer");
180 byte *end = row + raster;
181 byte *plane = end;
182 int y;
183 int code = 0; /* return code */
184 if ( row == 0 ) /* can't allocate row buffer */
185 return gs_error_VMerror;
186
187 /* setup the header struct */
188
189 phdr->manuf = 10;
190 /* version and bpp were set by the caller */
191 phdr->encoding = 1; /* 1 for rle 8-bit encoding */
192 phdr->x1 = 0;
193 phdr->y1 = 0;
194 phdr->x2 = pdev->width-1;
195 phdr->y2 = height-1;
196 phdr->hres = (int)pdev->x_pixels_per_inch;
197 phdr->vres = (int)pdev->y_pixels_per_inch;
198 phdr->vmode = 0;
199 /* nplanes was set by the caller */
200 phdr->bpl = (planar && depth > 1 ? rsize : raster);
201 phdr->palinfo = (gx_device_has_color(pdev) ? 1 : 2);
202
203 /* Write the header. */
204
205 if ( fwrite((const char *)phdr, 1, 128, file) < 128 )
206 { code = gs_error_ioerror;
207 goto pcx_done;
208 }
209
210 /* Dump the contents of the image. */
211 for ( y = 0; y < height; y++ )
212 { gdev_prn_copy_scan_lines(pdev, y, row, raster);
213 switch ( depth )
214 {
215 case 1:
216 { /* PCX assumes 0=black, 1=white. */
217 register byte *bp;
218 for ( bp = row; bp < end; bp++ )
219 *bp = ~*bp;
220 pcx_write_rle(row, end, file);
221 }
222 break;
223 case 8:
224 { register int shift;
225
226 if ( !gx_device_has_color(pdev) )
227 { /* Can't map gray scale */
228 code = gs_error_undefinedresult;
229 goto pcx_done;
230 }
231
232 if ( !planar )
233 { /* Just write the bits */
234 pcx_write_rle(row, end, file);
235 break;
236 }
237
238 for ( shift = 0; shift < 4; shift++ )
239 { register byte *from, *to;
240 register int bmask = 1 << shift;
241 for ( from = row, to = plane;
242 from < end; from += 8
243 )
244 { *to++ =
245 ((((uint)from[0] & bmask) << 7) +
246 (((uint)from[1] & bmask) << 6) +
247 (((uint)from[2] & bmask) << 5) +
248 (((uint)from[3] & bmask) << 4) +
249 (((uint)from[4] & bmask) << 3) +
250 (((uint)from[5] & bmask) << 2) +
251 (((uint)from[6] & bmask) << 1) +
252 (((uint)from[7] & bmask)))
253 >> shift;
254 }
255 pcx_write_rle(plane, to, file);
256 }
257 }
258 break;
259
260 default:
261 code = gs_error_undefinedresult;
262 goto pcx_done;
263
264 }
265 }
266
267pcx_done:
268 gs_free((char *)row, raster + rsize, 1, "pcx file buffer");
269
270 return code;
271}
272
273/* ------ Internal routines ------ */
274
275/* Write one line in PCX run-length-encoded format. */
276private void
277pcx_write_rle(byte *from, byte *end, FILE *file)
278{ while ( from < end )
279 { byte data = *from++;
280 int count = 1;
281 while ( (from < end) && (*from == data) )
282 count++, from++;
283 while ( count > 63 )
284 { putc(0xff, file);
285 putc(data, file);
286 count -= 63;
287 }
288 if ( count != 1 || data >= 0xc0 )
289 { putc(count | 0xc0, file);
290 }
291 putc(data, file);
292 }
293}