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