1 /* Copyright (C) 1991, 1995, 1996, 1997, 1998, 1999 Aladdin Enterprises. All rights reserved. 2 3 This file is part of AFPL Ghostscript. 4 5 AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author or 6 distributor accepts any responsibility for the consequences of using it, or 7 for whether it serves any particular purpose or works at all, unless he or 8 she says so in writing. Refer to the Aladdin Free Public License (the 9 "License") for full details. 10 11 Every copy of AFPL Ghostscript must include a copy of the License, normally 12 in a plain ASCII text file named PUBLIC. The License grants you the right 13 to copy, modify and redistribute AFPL Ghostscript, but only under certain 14 conditions described in the License. Among other things, the License 15 requires that the copyright notice and this notice be preserved on all 16 copies. 17 */ 18 19 /*$Id: gdevbit.c,v 1.2 2000/09/19 19:00:11 lpd Exp $ */ 20 /* "Plain bits" devices to measure rendering time. */ 21 #include "math_.h" 22 #include "gdevprn.h" 23 #include "gsparam.h" 24 #include "gscrd.h" 25 #include "gscrdp.h" 26 #include "gxlum.h" 27 #include "gdevdcrd.h" 28 29 /* Define the device parameters. */ 30 #ifndef X_DPI 31 # define X_DPI 72 32 #endif 33 #ifndef Y_DPI 34 # define Y_DPI 72 35 #endif 36 37 /* The device descriptor */ 38 private dev_proc_map_rgb_color(bit_mono_map_rgb_color); 39 private dev_proc_map_rgb_color(bit_forcemono_map_rgb_color); 40 private dev_proc_map_color_rgb(bit_map_color_rgb); 41 private dev_proc_map_cmyk_color(bit_map_cmyk_color); 42 private dev_proc_get_params(bit_get_params); 43 private dev_proc_put_params(bit_put_params); 44 private dev_proc_print_page(bit_print_page); 45 46 #define bit_procs(map_rgb_color, map_cmyk_color)\ 47 { gdev_prn_open,\ 48 gx_default_get_initial_matrix,\ 49 NULL, /* sync_output */\ 50 gdev_prn_output_page,\ 51 gdev_prn_close,\ 52 map_rgb_color,\ 53 bit_map_color_rgb,\ 54 NULL, /* fill_rectangle */\ 55 NULL, /* tile_rectangle */\ 56 NULL, /* copy_mono */\ 57 NULL, /* copy_color */\ 58 NULL, /* draw_line */\ 59 NULL, /* get_bits */\ 60 bit_get_params,\ 61 bit_put_params,\ 62 map_cmyk_color,\ 63 NULL, /* get_xfont_procs */\ 64 NULL, /* get_xfont_device */\ 65 NULL, /* map_rgb_alpha_color */\ 66 gx_page_device_get_page_device /* get_page_device */\ 67 } 68 69 /* 70 * The following macro is used in get_params and put_params to determine the 71 * num_components for the current device. It works using the device name 72 * character after "bit" which is either '\0', 'r', or 'c'. Any new devices 73 * that are added to this module must modify this macro to return the 74 * correct num_components. This is needed to support the ForceMono 75 * parameter, which alters dev->num_components. 76 */ 77 #define REAL_NUM_COMPONENTS(dev) (dev->dname[3] == 'c' ? 4 : \ 78 dev->dname[3] == 'r' ? 3 : 1) 79 80 private const gx_device_procs bitmono_procs = 81 bit_procs(bit_mono_map_rgb_color, NULL); 82 const gx_device_printer gs_bit_device = 83 {prn_device_body(gx_device_printer, bitmono_procs, "bit", 84 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, 85 X_DPI, Y_DPI, 86 0, 0, 0, 0, /* margins */ 87 1, 1, 1, 0, 2, 1, bit_print_page) 88 }; 89 90 private const gx_device_procs bitrgb_procs = 91 bit_procs(gx_default_rgb_map_rgb_color, NULL); 92 const gx_device_printer gs_bitrgb_device = 93 {prn_device_body(gx_device_printer, bitrgb_procs, "bitrgb", 94 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, 95 X_DPI, Y_DPI, 96 0, 0, 0, 0, /* margins */ 97 3, 4, 1, 1, 2, 2, bit_print_page) 98 }; 99 100 private const gx_device_procs bitcmyk_procs = 101 bit_procs(bit_forcemono_map_rgb_color, bit_map_cmyk_color); 102 const gx_device_printer gs_bitcmyk_device = 103 {prn_device_body(gx_device_printer, bitcmyk_procs, "bitcmyk", 104 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, 105 X_DPI, Y_DPI, 106 0, 0, 0, 0, /* margins */ 107 4, 4, 1, 1, 2, 2, bit_print_page) 108 }; 109 110 /* Map gray to color. */ 111 /* Note that 1-bit monochrome is a special case. */ 112 private gx_color_index 113 bit_mono_map_rgb_color(gx_device * dev, gx_color_value red, 114 gx_color_value green, gx_color_value blue) 115 { 116 int bpc = dev->color_info.depth; 117 int drop = sizeof(gx_color_value) * 8 - bpc; 118 gx_color_value gray = 119 (red * (unsigned long)lum_red_weight + 120 green * (unsigned long)lum_green_weight + 121 blue * (unsigned long)lum_blue_weight + 122 (lum_all_weights / 2)) 123 / lum_all_weights; 124 125 return (bpc == 1 ? gx_max_color_value - gray : gray) >> drop; 126 } 127 128 /* Map RGB to gray shade. */ 129 /* Only used in CMYK mode when put_params has set ForceMono=1 */ 130 private gx_color_index 131 bit_forcemono_map_rgb_color(gx_device * dev, gx_color_value red, 132 gx_color_value green, gx_color_value blue) 133 { 134 gx_color_value color; 135 int bpc = dev->color_info.depth / 4; /* This function is used in CMYK mode */ 136 int drop = sizeof(gx_color_value) * 8 - bpc; 137 gx_color_value gray = red; 138 139 if ((red != green) || (green != blue)) 140 gray = (red * (unsigned long)lum_red_weight + 141 green * (unsigned long)lum_green_weight + 142 blue * (unsigned long)lum_blue_weight + 143 (lum_all_weights / 2)) 144 / lum_all_weights; 145 146 color = (gx_max_color_value - gray) >> drop; /* color is in K channel */ 147 return color; 148 } 149 150 /* Map color to RGB. This has 3 separate cases, but since it is rarely */ 151 /* used, we do a case test rather than providing 3 separate routines. */ 152 private int 153 bit_map_color_rgb(gx_device * dev, gx_color_index color, gx_color_value rgb[3]) 154 { 155 int depth = dev->color_info.depth; 156 int ncomp = REAL_NUM_COMPONENTS(dev); 157 int bpc = depth / ncomp; 158 uint mask = (1 << bpc) - 1; 159 160 #define cvalue(c) ((gx_color_value)((ulong)(c) * gx_max_color_value / mask)) 161 162 switch (ncomp) { 163 case 1: /* gray */ 164 rgb[0] = rgb[1] = rgb[2] = 165 (depth == 1 ? (color ? 0 : gx_max_color_value) : 166 cvalue(color)); 167 break; 168 case 3: /* RGB */ 169 { 170 gx_color_index cshift = color; 171 172 rgb[2] = cvalue(cshift & mask); 173 cshift >>= bpc; 174 rgb[1] = cvalue(cshift & mask); 175 rgb[0] = cvalue(cshift >> bpc); 176 } 177 break; 178 case 4: /* CMYK */ 179 /* Map CMYK back to RGB. */ 180 { 181 gx_color_index cshift = color; 182 uint c, m, y, k; 183 184 k = cshift & mask; 185 cshift >>= bpc; 186 y = cshift & mask; 187 cshift >>= bpc; 188 m = cshift & mask; 189 c = cshift >> bpc; 190 /* We use our improved conversion rule.... */ 191 rgb[0] = cvalue((mask - c) * (mask - k) / mask); 192 rgb[1] = cvalue((mask - m) * (mask - k) / mask); 193 rgb[2] = cvalue((mask - y) * (mask - k) / mask); 194 } 195 break; 196 } 197 return 0; 198 #undef cvalue 199 } 200 201 /* Map CMYK to color. */ 202 private gx_color_index 203 bit_map_cmyk_color(gx_device * dev, gx_color_value cyan, 204 gx_color_value magenta, gx_color_value yellow, gx_color_value black) 205 { 206 int bpc = dev->color_info.depth / 4; 207 int drop = sizeof(gx_color_value) * 8 - bpc; 208 gx_color_index color = 209 ((((((cyan >> drop) << bpc) + 210 (magenta >> drop)) << bpc) + 211 (yellow >> drop)) << bpc) + 212 (black >> drop); 213 214 return (color == gx_no_color_index ? color ^ 1 : color); 215 } 216 217 /* Get parameters. We provide a default CRD. */ 218 private int 219 bit_get_params(gx_device * pdev, gs_param_list * plist) 220 { 221 int code, ecode; 222 /* 223 * The following is a hack to get the original num_components. 224 * See comment above. 225 */ 226 int real_ncomps = REAL_NUM_COMPONENTS(pdev); 227 int ncomps = pdev->color_info.num_components; 228 int forcemono = (ncomps == real_ncomps ? 0 : 1); 229 230 /* 231 * Temporarily set num_components back to the "real" value to avoid 232 * confusing those that rely on it. 233 */ 234 pdev->color_info.num_components = real_ncomps; 235 236 ecode = gdev_prn_get_params(pdev, plist); 237 code = sample_device_crd_get_params(pdev, plist, "CRDDefault"); 238 if (code < 0) 239 ecode = code; 240 if ((code = param_write_int(plist, "ForceMono", &forcemono)) < 0) { 241 ecode = code; 242 } 243 244 /* Restore the working num_components */ 245 pdev->color_info.num_components = ncomps; 246 247 return ecode; 248 } 249 250 /* Set parameters. We allow setting the number of bits per component. */ 251 /* Also, ForceMono=1 forces monochrome output from RGB/CMYK devices. */ 252 private int 253 bit_put_params(gx_device * pdev, gs_param_list * plist) 254 { 255 gx_device_color_info save_info; 256 int ncomps = pdev->color_info.num_components; 257 int real_ncomps = REAL_NUM_COMPONENTS(pdev); 258 int bpc = pdev->color_info.depth / real_ncomps; 259 int v; 260 int ecode = 0; 261 int code; 262 static const byte depths[4][8] = { 263 {1, 2, 0, 4, 8, 0, 0, 8}, 264 {0}, 265 {4, 8, 0, 16, 16, 0, 0, 24}, 266 {4, 8, 0, 16, 32, 0, 0, 32} 267 }; 268 const char *vname; 269 270 /* 271 * Temporarily set num_components back to the "real" value to avoid 272 * confusing those that rely on it. 273 */ 274 pdev->color_info.num_components = real_ncomps; 275 276 if ((code = param_read_int(plist, (vname = "GrayValues"), &v)) != 1 || 277 (code = param_read_int(plist, (vname = "RedValues"), &v)) != 1 || 278 (code = param_read_int(plist, (vname = "GreenValues"), &v)) != 1 || 279 (code = param_read_int(plist, (vname = "BlueValues"), &v)) != 1 280 ) { 281 if (code < 0) 282 ecode = code; 283 else 284 switch (v) { 285 case 2: bpc = 1; break; 286 case 4: bpc = 2; break; 287 case 16: bpc = 4; break; 288 case 32: bpc = 5; break; 289 case 256: bpc = 8; break; 290 default: 291 param_signal_error(plist, vname, 292 ecode = gs_error_rangecheck); 293 } 294 } 295 296 switch (code = param_read_int(plist, (vname = "ForceMono"), &v)) { 297 case 0: 298 if (v == 1) { 299 ncomps = 1; 300 break; 301 } 302 else if (v == 0) { 303 ncomps = real_ncomps; 304 break; 305 } 306 code = gs_error_rangecheck; 307 default: 308 ecode = code; 309 param_signal_error(plist, vname, ecode); 310 case 1: 311 break; 312 } 313 if (ecode < 0) 314 return ecode; 315 316 /* 317 * Save the color_info in case gdev_prn_put_params fails, and for 318 * comparison. Note that depth is computed from real_ncomps. 319 */ 320 save_info = pdev->color_info; 321 pdev->color_info.depth = depths[real_ncomps - 1][bpc - 1]; 322 pdev->color_info.max_gray = pdev->color_info.max_color = 323 (pdev->color_info.dither_grays = 324 pdev->color_info.dither_colors = 325 (1 << bpc)) - 1; 326 ecode = gdev_prn_put_params(pdev, plist); 327 if (ecode < 0) { 328 pdev->color_info = save_info; 329 return ecode; 330 } 331 /* Now restore/change num_components. This is done after other */ 332 /* processing since it is used in gx_default_put_params */ 333 pdev->color_info.num_components = ncomps; 334 if (pdev->color_info.depth != save_info.depth || 335 pdev->color_info.num_components != save_info.num_components 336 ) { 337 gs_closedevice(pdev); 338 } 339 /* Reset the map_cmyk_color procedure if appropriate. */ 340 if (dev_proc(pdev, map_cmyk_color) == cmyk_1bit_map_cmyk_color || 341 dev_proc(pdev, map_cmyk_color) == cmyk_8bit_map_cmyk_color || 342 dev_proc(pdev, map_cmyk_color) == bit_map_cmyk_color) { 343 set_dev_proc(pdev, map_cmyk_color, 344 pdev->color_info.depth == 4 ? cmyk_1bit_map_cmyk_color : 345 pdev->color_info.depth == 32 ? cmyk_8bit_map_cmyk_color : 346 bit_map_cmyk_color); 347 } 348 return 0; 349 } 350 351 /* Send the page to the printer. */ 352 private int 353 bit_print_page(gx_device_printer * pdev, FILE * prn_stream) 354 { /* Just dump the bits on the file. */ 355 /* If the file is 'nul', don't even do the writes. */ 356 int line_size = gdev_mem_bytes_per_scan_line((gx_device *) pdev); 357 byte *in = gs_alloc_bytes(pdev->memory, line_size, "bit_print_page(in)"); 358 byte *data; 359 int nul = !strcmp(pdev->fname, "nul"); 360 int lnum = 0, bottom = pdev->height; 361 362 if (in == 0) 363 return_error(gs_error_VMerror); 364 for (; lnum < bottom; ++lnum) { 365 gdev_prn_get_bits(pdev, lnum, in, &data); 366 if (!nul) 367 fwrite(data, 1, line_size, prn_stream); 368 } 369 gs_free_object(pdev->memory, in, "bit_print_page(in)"); 370 return 0; 371 } 372