1 /* Copyright (C) 1992, 1993, 1994, 1997, 1999 artofcode LLC. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify it
4 under the terms of the GNU General Public License as published by the
5 Free Software Foundation; either version 2 of the License, or (at your
6 option) any later version.
7
8 This program is distributed in the hope that it will be useful, but
9 WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along
14 with this program; if not, write to the Free Software Foundation, Inc.,
15 59 Temple Place, Suite 330, Boston, MA, 02111-1307.
16
17 */
18
19 /*$Id: gdevmgr.c,v 1.2.6.1.2.1 2003/01/17 00:49:01 giles Exp $*/
20 /* MGR device driver */
21 #include "gdevprn.h"
22 #include "gdevpccm.h"
23 #include "gdevmgr.h"
24
25 /* Structure for MGR devices, which extend the generic printer device. */
26 struct gx_device_mgr_s {
27 gx_device_common;
28 gx_prn_device_common;
29 /* Add MGR specific variables */
30 int mgr_depth;
31 };
32 typedef struct gx_device_mgr_s gx_device_mgr;
33
34 static struct nclut clut[256];
35
36 private unsigned int clut2mgr(P2(int, int));
37 private void swap_bwords(P2(unsigned char *, int));
38
39 /* ------ The device descriptors ------ */
40
41 /*
42 * Default X and Y resolution.
43 */
44 #define X_DPI 72
45 #define Y_DPI 72
46
47 /* Macro for generating MGR device descriptors. */
48 #define mgr_prn_device(procs, dev_name, num_comp, depth, mgr_depth,\
49 max_gray, max_rgb, dither_gray, dither_rgb, print_page)\
50 { prn_device_body(gx_device_mgr, procs, dev_name,\
51 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, X_DPI, Y_DPI,\
52 0, 0, 0, 0,\
53 num_comp, depth, max_gray, max_rgb, dither_gray, dither_rgb,\
54 print_page),\
55 mgr_depth\
56 }
57
58 /* For all mgr variants we do some extra things at opening time. */
59 /* private dev_proc_open_device(gdev_mgr_open); */
60 #define gdev_mgr_open gdev_prn_open /* no we don't! */
61
62 /* And of course we need our own print-page routines. */
63 private dev_proc_print_page(mgr_print_page);
64 private dev_proc_print_page(mgrN_print_page);
65 private dev_proc_print_page(cmgrN_print_page);
66
67 /* The device procedures */
68 private gx_device_procs mgr_procs =
69 prn_procs(gdev_mgr_open, gdev_prn_output_page, gdev_prn_close);
70 private gx_device_procs mgrN_procs =
71 prn_color_procs(gdev_mgr_open, gdev_prn_output_page, gdev_prn_close,
72 gx_default_gray_map_rgb_color, gx_default_gray_map_color_rgb);
73 private gx_device_procs cmgr4_procs =
74 prn_color_procs(gdev_mgr_open, gdev_prn_output_page, gdev_prn_close,
75 pc_4bit_map_rgb_color, pc_4bit_map_color_rgb);
76 private gx_device_procs cmgr8_procs =
77 prn_color_procs(gdev_mgr_open, gdev_prn_output_page, gdev_prn_close,
78 mgr_8bit_map_rgb_color, mgr_8bit_map_color_rgb);
79
80 /* The device descriptors themselves */
81 gx_device_mgr far_data gs_mgrmono_device =
82 mgr_prn_device( mgr_procs, "mgrmono", 1, 1, 1, 1, 0, 2, 0, mgr_print_page);
83 gx_device_mgr far_data gs_mgrgray2_device =
84 mgr_prn_device(mgrN_procs, "mgrgray2",1, 8, 2, 255, 0, 4, 0, mgrN_print_page);
85 gx_device_mgr far_data gs_mgrgray4_device =
86 mgr_prn_device(mgrN_procs, "mgrgray4",1, 8, 4, 255, 0,16, 0, mgrN_print_page);
87 gx_device_mgr far_data gs_mgrgray8_device =
88 mgr_prn_device(mgrN_procs, "mgrgray8",1, 8, 8, 255, 0, 0, 0, mgrN_print_page);
89 gx_device_mgr far_data gs_mgr4_device =
90 mgr_prn_device(cmgr4_procs, "mgr4", 3, 8, 4, 1, 1, 4, 3, cmgrN_print_page);
91 gx_device_mgr far_data gs_mgr8_device =
92 mgr_prn_device(cmgr8_procs, "mgr8", 3, 8, 8, 255, 255, 6, 5, cmgrN_print_page);
93
94 /* ------ Internal routines ------ */
95
96 /* Define a "cursor" that keeps track of where we are in the page. */
97 typedef struct mgr_cursor_s {
98 gx_device_mgr *dev;
99 int bpp; /* bits per pixel */
100 uint line_size; /* bytes per scan line */
101 byte *data; /* output row buffer */
102 int lnum; /* row within page */
103 } mgr_cursor;
104
105 /* Begin an MGR output page. */
106 /* Write the header information and initialize the cursor. */
107 private int
mgr_begin_page(gx_device_mgr * bdev,FILE * pstream,mgr_cursor * pcur)108 mgr_begin_page(gx_device_mgr *bdev, FILE *pstream, mgr_cursor *pcur)
109 { struct b_header head;
110 uint line_size =
111 gdev_prn_raster((gx_device_printer *)bdev) + 3;
112 byte *data = (byte *)gs_malloc(line_size, 1, "mgr_begin_page");
113 if ( data == 0 )
114 return_error(gs_error_VMerror);
115
116 /* Write the header */
117 B_PUTHDR8(&head, bdev->width, bdev->height, bdev->mgr_depth);
118 fprintf(pstream, "");
119 if ( fwrite(&head, 1, sizeof(head), pstream) < sizeof(head) )
120 return_error(gs_error_ioerror);
121 fflush(pstream);
122
123 /* Initialize the cursor. */
124 pcur->dev = bdev;
125 pcur->bpp = bdev->color_info.depth;
126 pcur->line_size = line_size;
127 pcur->data = data;
128 pcur->lnum = 0;
129 return 0;
130 }
131
132 /* Advance to the next row. Return 0 if more, 1 if done. */
133 private int
mgr_next_row(mgr_cursor * pcur)134 mgr_next_row(mgr_cursor *pcur)
135 { if ( pcur->lnum >= pcur->dev->height )
136 { gs_free((char *)pcur->data, pcur->line_size, 1,
137 "mgr_next_row(done)");
138 return 1;
139 }
140 gdev_prn_copy_scan_lines((gx_device_printer *)pcur->dev,
141 pcur->lnum++, pcur->data, pcur->line_size);
142 return 0;
143 }
144
145 /* ------ Individual page printing routines ------ */
146
147 #define bdev ((gx_device_mgr *)pdev)
148
149 /* Print a monochrome page. */
150 private int
mgr_print_page(gx_device_printer * pdev,FILE * pstream)151 mgr_print_page(gx_device_printer *pdev, FILE *pstream)
152 { mgr_cursor cur;
153 int mgr_wide;
154 int code = mgr_begin_page(bdev, pstream, &cur);
155 if ( code < 0 ) return code;
156
157 mgr_wide = bdev->width;
158 if (mgr_wide & 7)
159 mgr_wide += 8 - (mgr_wide & 7);
160
161 while ( !(code = mgr_next_row(&cur)) )
162 { if ( fwrite(cur.data, sizeof(char), mgr_wide / 8, pstream) <
163 mgr_wide / 8)
164 return_error(gs_error_ioerror);
165 }
166 return (code < 0 ? code : 0);
167 }
168
169
170 /* Print a gray-mapped page. */
171 static unsigned char bgreytable[16], bgreybacktable[16];
172 static unsigned char bgrey256table[256], bgrey256backtable[256];
173 private int
mgrN_print_page(gx_device_printer * pdev,FILE * pstream)174 mgrN_print_page(gx_device_printer *pdev, FILE *pstream)
175 { mgr_cursor cur;
176 int i = 0, j, k, mgr_wide;
177 uint mgr_line_size;
178 byte *bp, *data = NULL, *dp;
179
180 int code = mgr_begin_page(bdev, pstream, &cur);
181 if ( code < 0 ) return code;
182
183 mgr_wide = bdev->width;
184 if ( bdev->mgr_depth == 2 && mgr_wide & 3 )
185 mgr_wide += 4 - (mgr_wide & 3);
186 if ( bdev->mgr_depth == 4 && mgr_wide & 1 )
187 mgr_wide++;
188 mgr_line_size = mgr_wide / ( 8 / bdev->mgr_depth );
189
190 if ( bdev->mgr_depth == 4 )
191 for ( i = 0; i < 16; i++ ) {
192 bgreytable[i] = mgrlut[LUT_BGREY][RGB_RED][i];
193 bgreybacktable[bgreytable[i]] = i;
194 }
195
196 if ( bdev->mgr_depth == 8 ) {
197 for ( i = 0; i < 16; i++ ) {
198 bgrey256table[i] = mgrlut[LUT_BGREY][RGB_RED][i] << 4;
199 bgrey256backtable[bgrey256table[i]] = i;
200 }
201 for ( i = 16,j = 0; i < 256; i++ ) {
202 for ( k = 0; k < 16; k++ )
203 if ( j == mgrlut[LUT_BGREY][RGB_RED][k] << 4 ) {
204 j++;
205 break;
206 }
207 bgrey256table[i] = j;
208 bgrey256backtable[j++] = i;
209 }
210 }
211
212 if ( bdev->mgr_depth != 8 )
213 data = (byte *)gs_malloc(mgr_line_size, 1, "mgrN_print_page");
214
215 while ( !(code = mgr_next_row(&cur)) )
216 {
217 switch (bdev->mgr_depth) {
218 case 2:
219 for (i = 0,dp = data,bp = cur.data; i < mgr_line_size; i++) {
220 *dp = *(bp++) & 0xc0;
221 *dp |= (*(bp++) & 0xc0) >> 2;
222 *dp |= (*(bp++) & 0xc0) >> 4;
223 *(dp++) |= (*(bp++) & 0xc0) >> 6;
224 }
225 if ( fwrite(data, sizeof(byte), mgr_line_size, pstream) < mgr_line_size )
226 return_error(gs_error_ioerror);
227 break;
228
229 case 4:
230 for (i = 0,dp = data, bp = cur.data; i < mgr_line_size; i++) {
231 *dp = bgreybacktable[*(bp++) >> 4] << 4;
232 *(dp++) |= bgreybacktable[*(bp++) >> 4];
233 }
234 if ( fwrite(data, sizeof(byte), mgr_line_size, pstream) < mgr_line_size )
235 return_error(gs_error_ioerror);
236 break;
237
238 case 8:
239 for (i = 0,bp = cur.data; i < mgr_line_size; i++, bp++)
240 *bp = bgrey256backtable[*bp];
241 if ( fwrite(cur.data, sizeof(cur.data[0]), mgr_line_size, pstream)
242 < mgr_line_size )
243 return_error(gs_error_ioerror);
244 break;
245 }
246 }
247 if (bdev->mgr_depth != 8)
248 gs_free((char *)data, mgr_line_size, 1, "mgrN_print_page(done)");
249
250 if (bdev->mgr_depth == 2) {
251 for (i = 0; i < 4; i++) {
252 clut[i].colnum = i;
253 clut[i].red = clut[i].green = clut[i].blue = clut2mgr(i, 2);
254 }
255 }
256 if (bdev->mgr_depth == 4) {
257 for (i = 0; i < 16; i++) {
258 clut[i].colnum = i;
259 clut[i].red = clut[i].green = clut[i].blue = clut2mgr(bgreytable[i], 4);
260 }
261 }
262 if (bdev->mgr_depth == 8) {
263 for (i = 0; i < 256; i++) {
264 clut[i].colnum = i;
265 clut[i].red = clut[i].green = clut[i].blue = clut2mgr(bgrey256table[i], 8);
266 }
267 }
268 #if !arch_is_big_endian
269 swap_bwords( (unsigned char *) clut, sizeof( struct nclut ) * i );
270 #endif
271 if ( fwrite(&clut, sizeof(struct nclut), i, pstream) < i )
272 return_error(gs_error_ioerror);
273 return (code < 0 ? code : 0);
274 }
275
276 /* Print a color page. */
277 private int
cmgrN_print_page(gx_device_printer * pdev,FILE * pstream)278 cmgrN_print_page(gx_device_printer *pdev, FILE *pstream)
279 { mgr_cursor cur;
280 int i = 0, j, mgr_wide, r, g, b, colors8 = 0;
281 uint mgr_line_size;
282 byte *bp, *data, *dp;
283 ushort prgb[3];
284 unsigned char table[256], backtable[256];
285
286 int code = mgr_begin_page(bdev, pstream, &cur);
287 if ( code < 0 ) return code;
288
289 mgr_wide = bdev->width;
290 if (bdev->mgr_depth == 4 && mgr_wide & 1)
291 mgr_wide++;
292 mgr_line_size = mgr_wide / (8 / bdev->mgr_depth);
293 data = (byte *)gs_malloc(mgr_line_size, 1, "cmgrN_print_page");
294
295 if ( bdev->mgr_depth == 8 ) {
296 memset( table, 0, sizeof(table) );
297 for ( r = 0; r <= 6; r++ )
298 for ( g = 0; g <= 6; g++ )
299 for ( b = 0; b <= 6; b++ )
300 if ( r == g && g == b )
301 table[ r + (256-7) ] = 1;
302 else
303 table[ (r << 5) + (g << 2) + (b >> 1) ] = 1;
304 for ( i = j = 0; i < sizeof(table); i++ )
305 if ( table[i] == 1 ) {
306 backtable[i] = j;
307 table[j++] = i;
308 }
309 colors8 = j;
310 }
311 while ( !(code = mgr_next_row(&cur)) )
312 {
313 switch (bdev->mgr_depth) {
314 case 4:
315 for (i = 0,dp = data, bp = cur.data; i < mgr_line_size; i++) {
316 *dp = *(bp++) << 4;
317 *(dp++) |= *(bp++) & 0x0f;
318 }
319 if ( fwrite(data, sizeof(byte), mgr_line_size, pstream) < mgr_line_size )
320 return_error(gs_error_ioerror);
321 break;
322
323 case 8:
324 for (i = 0,bp = cur.data; i < mgr_line_size; i++, bp++)
325 *bp = backtable[*bp] + MGR_RESERVEDCOLORS;
326 if ( fwrite(cur.data, sizeof(cur.data[0]), mgr_line_size, pstream) < mgr_line_size )
327 return_error(gs_error_ioerror);
328 break;
329 }
330 }
331 gs_free((char *)data, mgr_line_size, 1, "cmgrN_print_page(done)");
332
333 if (bdev->mgr_depth == 4) {
334 for (i = 0; i < 16; i++) {
335 pc_4bit_map_color_rgb((gx_device *)0, (gx_color_index) i, prgb);
336 clut[i].colnum = i;
337 clut[i].red = clut2mgr(prgb[0], 16);
338 clut[i].green = clut2mgr(prgb[1], 16);
339 clut[i].blue = clut2mgr(prgb[2], 16);
340 }
341 }
342 if (bdev->mgr_depth == 8) {
343 for (i = 0; i < colors8; i++) {
344 mgr_8bit_map_color_rgb((gx_device *)0, (gx_color_index)
345 table[i], prgb);
346 clut[i].colnum = MGR_RESERVEDCOLORS + i;
347 clut[i].red = clut2mgr(prgb[0], 16);
348 clut[i].green = clut2mgr(prgb[1], 16);
349 clut[i].blue = clut2mgr(prgb[2], 16);
350 }
351 }
352 #if !arch_is_big_endian
353 swap_bwords( (unsigned char *) clut, sizeof( struct nclut ) * i );
354 #endif
355 if ( fwrite(&clut, sizeof(struct nclut), i, pstream) < i )
356 return_error(gs_error_ioerror);
357 return (code < 0 ? code : 0);
358 }
359
360
361 /* Color mapping routines for 8-bit color with a fixed palette */
362 /* (3 bits of R, 3 bits of G, 2 bits of B). */
363 /* We have to trade off even spacing of colors along each axis */
364 /* against the desire to have real gray shades; */
365 /* MGR compromises by using a 7x7x4 "cube" with extra gray shades */
366 /* (1/6, 1/2, and 5/6), instead of the obvious 8x8x4. */
367
368 gx_color_index
mgr_8bit_map_rgb_color(gx_device * dev,gx_color_value r,gx_color_value g,gx_color_value b)369 mgr_8bit_map_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g,
370 gx_color_value b)
371 { uint rv = r / (gx_max_color_value / 7 + 1);
372 uint gv = g / (gx_max_color_value / 7 + 1);
373 uint bv = b / (gx_max_color_value / 7 + 1);
374 return (gx_color_index)
375 (rv == gv && gv == bv ? rv + (256-7) :
376 (rv << 5) + (gv << 2) + (bv >> 1));
377 }
378 int
mgr_8bit_map_color_rgb(gx_device * dev,gx_color_index color,gx_color_value prgb[3])379 mgr_8bit_map_color_rgb(gx_device *dev, gx_color_index color,
380 gx_color_value prgb[3])
381 { static const gx_color_value ramp[8] =
382 { 0, gx_max_color_value / 6, gx_max_color_value / 3,
383 gx_max_color_value / 2, 2 * (gx_max_color_value / 3),
384 5 * (gx_max_color_value / 6), gx_max_color_value,
385 /* The 8th entry is not actually ever used, */
386 /* except to fill out the palette. */
387 gx_max_color_value
388 };
389 #define icolor (uint)color
390 if ( icolor >= 256-7 )
391 { prgb[0] = prgb[1] = prgb[2] = ramp[icolor - (256-7)];
392 }
393 else
394 { prgb[0] = ramp[(icolor >> 5) & 7];
395 prgb[1] = ramp[(icolor >> 2) & 7];
396 prgb[2] = ramp[(icolor & 3) << 1];
397 }
398 #undef icolor
399 return 0;
400 }
401
402
403 /* convert the 8-bit look-up table into the standard MGR look-up table */
404 private unsigned int
clut2mgr(register int v,register int bits)405 clut2mgr(
406 register int v, /* value in clut */
407 register int bits /* number of bits in clut */
408 )
409 {
410 register unsigned int i;
411
412 i = (unsigned int) 0xffffffff / ((1<<bits)-1);
413 return((v*i)/0x10000);
414 }
415
416
417 /*
418 * s w a p _ b w o r d s
419 */
420 private void
swap_bwords(register unsigned char * p,int n)421 swap_bwords(register unsigned char *p, int n)
422 {
423 register unsigned char c;
424
425 n /= 2;
426
427 for (; n > 0; n--, p += 2) {
428 c = p[0];
429 p[0] = p[1];
430 p[1] = c;
431 }
432 }
433