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