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