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