/* gdevcd8.c */ /* HP 850c, 855c & the like colour printer drivers */ /* These are currently not in the official distrib.*/ /* Please report all problems to uli@bonk.ethz.ch */ /* 11.11.96. Initial release of the driver */ /* 04.05.97 Version 1.1. For added feautures, */ /* resolved bugs and so forth, please see */ /* http://bonk.ethz.ch */ /* 25.08.97 Version 1.2. Resolved all but one of the known bugs, introduced a couple of perfomance improvements. Complete new color-transfer-function handling. (see gamma). Known Bugs: Dark colors are still pale. */ /* The current gs hp850 driver is meant to support all hp-color printers with C-RET and asymetrical resolution capabilities. Currently the driver supports only the the hp850, hp855, hp870 and hp890 printers with 300x300 dpi color (with and without RET) and 600x600dpi b/w. Furthermore, the hp690 is supported. However, you need to explicitly set -dRestStatus=0, otherwise you'll get garbage. The driver _must_ be invoked with the following switches: gs -r600 -dBitsPerPixel=32 (see the provided cmd-files as examples) Furthermore, the driver supports the following switches: -dPapertype= 0 plain paper [default] 1 bond paper 2 special paper 3 glossy film 4 transparency film -dQuality= -1 draft not recommended 0 normal not recommended 1 presentation [default] -dRetStatus= 0 C-RET off 1 C-RET on [default] -dMasterGamma= 3.0 [default = 1.0] __Note__: To take advantage of the calibrated color-transfer functions, be sure not to have any Gamma-Statements left! If you need to (i.e. overhead sheets), you still can use the gamma-functions, but they will override the built-in calibration. To use gamma in the traditional way, set MasterGamma to any value greater 1.0 and less 10.0. To adjust individual gamma-values, you have to additionally set MasterGamma to a value greater 1.0 and less 10.0 With the next release, gamma functions will be dropped. When using the driver, be aware that printing in 600dpi involves processing of large amounts of data (> 188MB !). Therefore, the driver is not what you would expect to be a fast driver ;-) This is no problem when printing a full sized color page (because printing itself is slow), but it's really annoying if yoy print only text pages. Maybe I can optimize the code for text-only pages in a later release. Right now, it is recommended to use the highest possible optimisation level your compiler offers.... For the time beeing, use the cdj550 device with -sBitsPerPixel=3 for fast proof-prints. If you simply wanna print 600dpi b/w data, use the cdj550 device with -sBitsPerPixel=8 (or 1). Since the printer itself is slow, it may help to set the process-priority of the gs-process to regular or even less. On a 486/100MHZ this is still sufficient to maintain a continuos data-flow. Note to OS/2 users: Simply put the gs-window into the background, or minimize it. Also make sure, that print01.sys is invoked without the /irq switch (great speed improvement under warp4). You may use -dQuality=0 or -1, however, this setting interfers in an undocumented way with the output of the dither routine, such that the midtones of colors may look ugly (I have no idea how to overcome this). Anyhow, printing with 600dpi is somewhat senseless if you don't have a high positionig precision of the print-head ;-) Using -dQuality=-1 makes more sense since it saves a lot of ink (but looks ugly). The printer default settings compensate for dot-gain by a calibrated color-transfer function. If this appears to be to light for your business-graphs, or for overhead-sheets, feel free to set -dMasterGamma=1.7. Furthermore, you may tweak the gammavalues independently by setting -dGammaValC, -dGammaValM, -dGammaValY or -dGammaValK (if not set, the values default to MasterGamma). If you want to learn more about gamma, see: ftp://ftp.inforamp.net/pub/users/poynton/doc/colour/GammaFAQ.pdf or ftp://ftp.igd.fhg.de/pub/doc/colour/GammaFAQ.pdf Further information, bugs, tips etc, can be found at my website. Have fun! Uli uli@bonk.ethz.ch http://bonk.ethz.ch */ /* Note to *nix users. Depending on how you transfered the files, you might need to remove some CR-codes used on intel-based machines: simply type: unzip -a hp850.zip */ /* to compile with gs5.x, simply add DEVICE_DEVS4=cdj850.dev to your makefile. */ /* To compile with gs4.03, include in your makefile something like: DEVICE_DEVS4=cdj850.dev create a file cdj850.dev with the following line: -dev cdj850 -include page -obj gdevcd8.obj gdevpcl.obj locate in devs.mak the line: cdeskjet_=gdevcdj.$(OBJ) $(HPPCL) and create below the line: cdeskjet8_=gdevcd8.$(OBJ) $(HPPCL) add to the device definitions the following two lines: cdj850.dev: $(cdeskjet8_) page.dev $(SETPDEV) cdj850 $(cdeskjet8_) and recompile. For all other gs-versions, see the appropriate gs-files */ #include "std.h" /* to stop stdlib.h redefining types */ #include /* for rand() */ #include #include "gdevprn.h" #include "gdevpcl.h" #include "gsparam.h" #include "gsstate.h" #include "gdevcd8.h" /* Conversion stuff. */ #include "gxlum.h" /*** *** The Hp850c driver is based on the dj550 one from George Cameron especially, the compression and dither routines are copied verbatim. 1 - cdj850: HP850 printer * uli@homer.geol.chemie.tu-muenchen.de ***/ /* * Drivers stuff. * */ #define DESKJET_PRINT_LIMIT 0.04 /* 'real' top margin? */ /* Margins are left, bottom, right, top. */ #define DESKJET_MARGINS_LETTER 0.25, 0.50, 0.25, 0.167 #define DESKJET_MARGINS_A4 0.13, 0.46, 0.13, 0.04 /* Define bits-per-pixel - default is 32-bit cmyk-mode */ #ifndef BITSPERPIXEL # define BITSPERPIXEL 32 #endif #define DOFFSET (dev_t_margin(pdev) - DESKJET_PRINT_LIMIT) /* Print position */ #define W sizeof(word) #define I sizeof(int) /* Printer types */ #define DJ850C 1 /* No. of ink jets (used to minimise head movements) */ #define HEAD_ROWS_MONO 50 #define HEAD_ROWS_COLOUR 16 /* Colour mapping procedures */ private dev_proc_map_cmyk_color (gdev_cmyk_map_cmyk_color); private dev_proc_map_rgb_color (gdev_cmyk_map_rgb_color); private dev_proc_map_color_rgb (gdev_cmyk_map_color_rgb); private dev_proc_map_rgb_color (gdev_pcl_map_rgb_color); private dev_proc_map_color_rgb (gdev_pcl_map_color_rgb); /* Print-page, parameters and miscellaneous procedures */ private dev_proc_open_device(dj850c_open); private dev_proc_get_params(cdj850_get_params); private dev_proc_put_params(cdj850_put_params); private dev_proc_print_page(dj850c_print_page); /* The device descriptors */ /* The basic structure for all printers. Note the presence of the cmyk, depth and correct fields even if soem are not used by all printers. */ #define prn_colour_device_body(dtype, procs, dname, w10, h10, xdpi, ydpi, lm, bm, rm, tm, ncomp, depth, mg, mc, dg, dc, print_page, cmyk, correct)\ prn_device_body(dtype, procs, dname, w10, h10, xdpi, ydpi, lm, bm, rm, tm, ncomp, depth, mg, mc, dg, dc, print_page), cmyk, depth /* default */, correct #define gx_prn_colour_device_common \ gx_prn_device_common; \ short cmyk; /* 0: not CMYK-capable, > 0: printing CMYK, */ \ /* < 0 : CMYK-capable, not printing CMYK */ \ uint default_depth; /* Used only for CMYK-capable printers now. */ \ uint correction typedef struct gx_device_cdj850_s gx_device_cdj850; struct gx_device_cdj850_s { gx_device_common; gx_prn_colour_device_common; int quality; /* -1 draft, 0 normal, 1 best */ int papertype; /* papertype [0,4] */ int retstatus; /* intensity values per pixel [2,4]*/ float mastergamma; /* Gammavalue applied to all colors */ float gammavalc; /* range to which gamma-correction is applied to bw values */ float gammavalm; /* amount of gamma correction for bw*/ float gammavaly; /* range to which gamma-correction i applied to color values */ float gammavalk; /* amount of gamma correction for color */ float blackcorrect; /* amount of gamma correction for color */ }; typedef struct { gx_device_common; gx_prn_colour_device_common; } gx_device_colour_prn; /* Use the cprn_device macro to access generic fields (like cmyk, default_depth and correction), and specific macros for specific devices. */ #define cprn_device ((gx_device_colour_prn*) pdev) #define cdj850 ((gx_device_cdj850 *)pdev) #define prn_cmyk_colour_device(dtype, procs, dev_name, x_dpi, y_dpi, bpp, print_page, correct)\ prn_colour_device_body(dtype, procs, dev_name,\ DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, x_dpi, y_dpi, 0, 0, 0, 0,\ ((bpp == 1 || bpp == 4) ? 1 : 4), bpp,\ (bpp > 8 ? 255 : 1), (1 << (bpp >> 2)) - 1, /* max_gray, max_color */\ (bpp > 8 ? 5 : 2), (bpp > 8 ? 5 : bpp > 1 ? 2 : 0),\ print_page, 1 /* cmyk */, correct) #define cdj_850_device(procs, dev_name, x_dpi, y_dpi, bpp, print_page, correction, quality, papertype, retstatus,mastergamma,gammavalc,gammavalm,gammavaly,gammavalk,blackcorrect)\ { prn_cmyk_colour_device(gx_device_cdj850, procs, dev_name, x_dpi, y_dpi, bpp, print_page, correction),\ quality,\ papertype,\ retstatus,\ mastergamma,\ gammavalc,\ gammavalm,\ gammavaly,\ gammavalk,\ blackcorrect\ } #define cmyk_colour_procs(proc_colour_open, proc_get_params, proc_put_params) {\ proc_colour_open,\ gx_default_get_initial_matrix,\ gx_default_sync_output,\ gdev_prn_output_page,\ gdev_prn_close,\ NULL /* map_rgb_color */,\ gdev_cmyk_map_color_rgb,\ NULL /* fill_rectangle */,\ NULL /* tile_rectangle */,\ NULL /* copy_mono */,\ NULL /* copy_color */,\ NULL /* draw_line */,\ gx_default_get_bits,\ proc_get_params,\ proc_put_params,\ gdev_cmyk_map_cmyk_color\ } private gx_device_procs cdj850_procs = cmyk_colour_procs(dj850c_open, cdj850_get_params, cdj850_put_params); gx_device_cdj850 far_data gs_cdj850_device = cdj_850_device(cdj850_procs, "cdj850", 600, 600, 32, dj850c_print_page, 0, 1, 0, 1, 1.0 , 0.0, 0.0, 0.0, 0.0, 1.0); /* Forward references */ private int gdev_pcl_mode9compress(P4(int, const byte *, const byte *, byte *)); private int hp_colour_open(P2(gx_device *, int)); private int hp850_colour_print_page(P3(gx_device_printer *, FILE *, int)); private int near cdj_put_param_int(P6(gs_param_list *, gs_param_name, int *, int, int, int)); private int near cdj_put_param_float(P6(gs_param_list *, gs_param_name, float *, float, float, int)); private int cdj_put_param_bpp(P5(gx_device *, gs_param_list *, int, int, int)); private int cdj_set_bpp(P3(gx_device *, int, int)); /* String parameters manipulation */ typedef struct { const char* p_name; int p_value; } stringParamDescription; /* Open the printer and set up the margins. */ private int dj850c_open(gx_device *pdev) { return hp_colour_open(pdev, DJ850C); } private int hp_colour_open(gx_device *pdev, int ptype) { /* Change the margins if necessary. */ static const float dj_a4[4] = { DESKJET_MARGINS_A4 }; static const float dj_letter[4] = { DESKJET_MARGINS_LETTER }; const float _ds *m = (float _ds*) 0; /* Set up colour params if put_params has not already done so */ if (pdev->color_info.num_components == 0) { int code = cdj_set_bpp(pdev, pdev->color_info.depth, pdev->color_info.num_components); if ( code < 0 ) return code; } switch (ptype) { case DJ850C: m = (gdev_pcl_paper_size(pdev) == PAPER_SIZE_A4 ? dj_a4 : dj_letter); break; default: break; } gx_device_set_margins(pdev, m, true); return gdev_prn_open(pdev); } /* Added parameters for DeskJet 850C */ private int cdj850_get_params(gx_device *pdev, gs_param_list *plist) { int code = gdev_prn_get_params(pdev, plist); if ( code < 0 || (code = param_write_int(plist, "Quality", &cdj850->quality)) < 0 || (code = param_write_int(plist, "Papertype", &cdj850->papertype)) < 0 || (code = param_write_int(plist, "RetStatus", &cdj850->retstatus)) < 0 || (code = param_write_float(plist, "MasterGamma", &cdj850->gammavalc)) < 0 || (code = param_write_float(plist, "GammaValC", &cdj850->gammavalc)) < 0 || (code = param_write_float(plist, "GammaValM", &cdj850->gammavalm)) < 0 || (code = param_write_float(plist, "GammaValY", &cdj850->gammavaly)) < 0 || (code = param_write_float(plist, "GammaValK", &cdj850->gammavalk)) < 0 || (code = param_write_float(plist, "BlackCorrect", &cdj850->blackcorrect)) < 0 ) return code; return code; } private int cdj850_put_params(gx_device *pdev, gs_param_list *plist) { int quality = cdj850->quality; int papertype = cdj850->papertype; int retstatus = cdj850->retstatus; float mastergamma = cdj850->mastergamma; float gammavalc = cdj850->gammavalc; float gammavalm = cdj850->gammavalm; float gammavaly = cdj850->gammavaly; float gammavalk = cdj850->gammavalk; float blackcorrect = cdj850->blackcorrect; int bpp = 0; int code = 0; code = cdj_put_param_int(plist, "BitsPerPixel", &bpp, 1, 32, code); code = cdj_put_param_int(plist, "Quality", &quality, 0, 2, code); code = cdj_put_param_int(plist, "Papertype", &papertype, 0, 4, code); code = cdj_put_param_int(plist, "RetStatus", &retstatus, 0, 2, code); code = cdj_put_param_float(plist, "MasterGamma", &mastergamma, 0.1, 9.0, code); code = cdj_put_param_float(plist, "GammaValC", &gammavalc, 0.0 , 9.0, code); code = cdj_put_param_float(plist, "GammaValM", &gammavalm, 0.0 , 9.0, code); code = cdj_put_param_float(plist, "GammaValY", &gammavaly, 0.0 , 9.0, code); code = cdj_put_param_float(plist, "GammaValK", &gammavalk, 0.0 , 9.0, code); code = cdj_put_param_float(plist, "BlackCorrect", &blackcorrect, 0.0 , 9.0, code); if ( code < 0 ) return code; code = cdj_put_param_bpp(pdev, plist, bpp, bpp, 4); if ( code < 0 ) return code; cdj850->quality = quality; cdj850->papertype = papertype; cdj850->retstatus = retstatus; cdj850->mastergamma = mastergamma; cdj850->gammavalc = gammavalc; cdj850->gammavalm = gammavalm; cdj850->gammavaly = gammavaly; cdj850->gammavalk = gammavalk; cdj850->blackcorrect = blackcorrect; return 0; } /* ------ Internal routines ------ */ /* The DeskJet850C can compress (mode 9) */ private int dj850c_print_page(gx_device_printer * pdev, FILE * prn_stream) { return hp850_colour_print_page(pdev, prn_stream, DJ850C); } /* MACROS FOR DITHERING (we use macros for compact source and faster code) */ /* Floyd-Steinberg dithering. Often results in a dramatic improvement in * subjective image quality, but can also produce dramatic increases in * amount of printer data generated and actual printing time!! Mode 9 2D * compression is still useful for fairly flat colour or blank areas but its * compression is much less effective in areas where the dithering has * effectively randomised the dot distribution. */ #define RSHIFT ((I * 8) - 16) #define SHIFT ((I * 8) - 13) #define MAXVALUE (255 << SHIFT) #define RANDOM (((rand() << RSHIFT) % (MAXVALUE / 2)) - MAXVALUE /4); #define MINVALUE 0 #define C 8 #define THRESHOLD (128 << SHIFT) /* --- needed for the hp850 -- */ #define SHIFTS ((I * 8) - 14) #define SHIFTM ((I * 8) - 13) #define SHIFTL ((I * 8) - 12) #define MAXVALUES (160 << SHIFTM) #define MAXVALUEM (255 << SHIFTM) #define MAXVALUEL (255 << SHIFTM) #define THRESHOLDS (128 << SHIFTM) #define THRESHOLDM (192 << SHIFTM) #define THRESHOLDL (250 << SHIFTM) /* --------------------------- */ /* the hp850 knows about 4 different color intensities per color */ #define FSdither8504(inP, outa, outb, errP, Err, Bit, Offset, Element)\ {\ oldErr = Err;\ Err = (*(errP + Element)\ + ((Err * 7 + C) >> 4)\ + ((int) *(inP + Element) << SHIFT));\ if ((Err > THRESHOLDS) && Err <= THRESHOLDM) {\ outa |= Bit;\ Err -= MAXVALUES;\ }\ if ((Err > THRESHOLDM) && Err <= THRESHOLDL) {\ outb |= Bit;\ Err -= MAXVALUEM;\ }\ if (Err > THRESHOLDL) {\ outa |= Bit;\ outb |= Bit;\ Err -= MAXVALUEL;\ }\ *(errP + (Element + Offset)) += ((Err * 3 + C) >> 4);\ *(errP + Element) = ((Err * 5 + oldErr + C) >> 4);\ } /* while printing on paper, we only use 3 -intensities */ #define FSdither8503(inP, outa, outb, errP, Err, Bit, Offset, Element)\ {\ oldErr = Err;\ Err = (*(errP + Element)\ + ((Err * 7 + C) >> 4)\ + ((int) *(inP + Element) << SHIFT));\ if ((Err > THRESHOLDS) && Err <= THRESHOLDM) {\ outa |= Bit;\ Err -= MAXVALUES;\ }\ if (Err > THRESHOLDM) {\ outb |= Bit;\ Err -= MAXVALUEM;\ }\ *(errP + (Element + Offset)) += ((Err * 3 + C) >> 4);\ *(errP + Element) = ((Err * 5 + oldErr + C) >> 4);\ } #define FSdither(inP, out, errP, Err, Bit, Offset, Element)\ {\ oldErr = Err;\ Err = (*(errP + Element)\ + ((Err * 7 + C) >> 4)\ + ((int)*(inP + Element) << SHIFT));\ if (Err > THRESHOLD) {\ out |= Bit;\ Err -= MAXVALUE;\ }\ *(errP + (Element + Offset)) += ((Err * 3 + C) >> 4);\ *(errP + Element) = ((Err * 5 + oldErr + C) >> 4);\ } /* Some convenient shorthand .. */ #define x_dpi (pdev->x_pixels_per_inch) #define y_dpi (pdev->y_pixels_per_inch) /* To calculate buffer size as next greater multiple of both parameter and W */ #define calc_buffsize(a, b) (((((a) + ((b) * W) - 1) / ((b) * W))) * W) /* some definitions needed later */ struct error_val_field { int c;/* Current value of Cyan error during dithering */ int m;/* Current value of Magenta error during dithering */ int y;/* Current value of Yellow error during dithering */ int k;/* Current value of Black error during dithering */ }; /* this structure holds all the pointers to the different values in all those data fields */ /* * The principal data pointers are stored as pairs of values, with * the selection being made by the 'scan' variable. The function of the * scan variable is overloaded, as it controls both the alternating * raster scan direction used in the Floyd-Steinberg dithering and also * the buffer alternation required for line-difference compression. * * Thus, the number of pointers required is as follows: */ struct ptr_arrays { byte * data[4] ; /* 4 600dpi data, scan direction and alternating buffers */ byte * data_c[4]; /* 4 300dpi data, as above, */ byte * plane_data[4][4]; /*4 b/w-planes, scan direction and alternating buffers */ byte * plane_data_c[4][8]; /* as above, but for 8 planes */ byte * out_data; /* output buffer for the b/w data, one 600dpi plane */ byte * test_data[4]; /* holds a copy of the last plane */ int * errors[2]; /* 2 b/w dithering erros (scan direction only) */ int * errors_c[2];/* 2 color dithering errors (scan direction only) */ word * storage; /* pointer to the beginning of the b/w-buffer */ word * storage_start; /* used for debugging */ word * storage_end; /* used for debugging */ word * storage_size; /* used for debugging */ }; /* Some miscallaneous variables */ struct misc_struct { int line_size ; /* size of scan_line */ int line_size_c ; /* size of rescaled scan_line */ int line_size_words; /* size of scan_line in words */ int paper_size ; /* size of paper */ int num_comps ; /* number of color components (1 - 4) */ int bits_per_pixel; /* bits per pixel 1,4,8,16,24,32 */ int storage_bpp ; /* = bits_per_pixel */ int expanded_bpp; /* = bits_per_pixel */ int plane_size ; /* size of b/w bit plane */ int plane_size_c ; /* size of color bit plane */ int databuff_size; /* size of databuffer for b/w data */ int databuff_size_c; /* size of databuffer for color data */ int errbuff_size ; /* size of error buffer b/w -data */ int errbuff_size_c ; /* size of error buffer color -data */ int outbuff_size; /* size of output buffer for b/w data */ int compression ; /* compression level should be 9 */ int scan; /* scan-line variable [0,1] */ int cscan; /* dito for the color-planes */ int is_two_pass ; /* checks if b/w data has already been printed */ int zero_row_count; /* How many empty lines */ uint storage_size_words; /* size of storage in words for b/w data */ uint storage_size_words_c; /* size of storage in words for c-data */ int is_color_data; /* indicates whether there is color data */ }; /* Here comes the hp850 output routine -------------------- */ private int hp850_colour_print_page(gx_device_printer * pdev, FILE * prn_stream, int ptype) { void do_gamma (P3(float mastergamma, float gammaval, byte * values)); void do_black_correction (P2(float kvalue, int * kcorrect)); void start_raster_mode (P4(gx_device_printer * pdev, int compression, int papersize, FILE * prn_stream)); void init_data_structure (P3(gx_device_printer * pdev, struct ptr_arrays * data_ptrs, struct misc_struct * misc_vars)); void calculate_memory_size (P2(gx_device_printer * pdev, struct misc_struct * misc_vars)); void send_scan_lines (P5(gx_device_printer * pdev, struct ptr_arrays * data_ptrs, struct misc_struct * misc_vars, struct error_val_field * error_values, FILE * prn_stream)); struct error_val_field error_values; struct ptr_arrays data_ptrs; struct misc_struct misc_vars; /* if mastergamma, don't use the biult in functions */ if (cdj850->mastergamma > 1.0) { /* prepare the bw lookup table */ do_gamma(cdj850->mastergamma, cdj850->gammavalk, &gammat.k[0]); /* prepare the color lookup table */ do_gamma(cdj850->mastergamma, cdj850->gammavalc, &gammat.c[0]); do_gamma(cdj850->mastergamma, cdj850->gammavalm, &gammat.m[0]); do_gamma(cdj850->mastergamma, cdj850->gammavaly, &gammat.y[0]); } /* prepare the black correction table for the unbunt mask */ do_black_correction(cdj850->blackcorrect, &gammat.correct[0]); /* Calculate the needed memory */ calculate_memory_size(pdev, &misc_vars); /* and allocate the memory */ /* Since we need 600 and 300 dpi, we set up several buffers: storage contains the data as copied from gs, as well as the plane-data and the out_row buffer. storagec will contain the rescaled color data. It also contains the plane_data for the color-planes - these are needed by the compression routine, but would be overwritten by the b/w-dithering. The color planes allow for overwriting the color-data by the error-data. Since we might use the 2bpp feature of the hp850 someday, it is sized like storage. storagee contains the errors from b/w fs-ditherng */ data_ptrs.storage = (ulong *) gs_malloc(misc_vars.storage_size_words, W, "hp850_colour_print_page"); /* if we can't allocate working area */ if ( data_ptrs.storage == 0 ) return_error(gs_error_VMerror); else { /* Initialise the needed pointers */ init_data_structure(pdev, &data_ptrs, &misc_vars); } /* Start Raster mode */ start_raster_mode (pdev, misc_vars.compression, misc_vars.paper_size, prn_stream); /* Send each scan line in turn */ send_scan_lines(pdev, &data_ptrs, &misc_vars, &error_values,prn_stream); fputs("0M", prn_stream); /* Reset compression */ fputs("\033*rC\033E", prn_stream); /* End Graphics, Reset */ fputs("\033&l0H", prn_stream); /* eject page */ /* Free Memory */ gs_free((char *) data_ptrs.storage, misc_vars.storage_size_words, W, "hp850_colour_print_page"); return 0; } /* send the scan lines to the printer */ void send_scan_lines (gx_device_printer * pdev, struct ptr_arrays * data_ptrs, struct misc_struct * misc_vars, struct error_val_field * error_values, FILE * prn_stream) { void init_error_buffer(P2(struct misc_struct * misc_vars, struct ptr_arrays * data_ptrs)); void print_non_blank_lines (P6(gx_device_printer * pdev, struct ptr_arrays * data_ptrs, struct misc_struct * misc_vars, struct error_val_field * error_values, FILE * prn_stream, int out_count)); int lnum; int lend; int num_blank_lines = 0; int last_line_empty = 0; word rmask = ~(word) 0 << ((-pdev->width * misc_vars->storage_bpp) & (W * 8 - 1)); lend = pdev->height - (dev_t_margin(pdev) + dev_b_margin(pdev)) * y_dpi; error_values->c = error_values->m = error_values->y = error_values->k = 0; /* init the error buffer */ init_error_buffer(misc_vars, data_ptrs); for (misc_vars->zero_row_count=0, lnum = 0; lnum < lend; lnum+=1) { word *data_words = (word *)data_ptrs->data[misc_vars->scan]; register word *end_data = data_words + misc_vars->line_size_words; int out_count = 0; gdev_prn_copy_scan_lines(pdev, lnum, data_ptrs->data[misc_vars->scan], misc_vars->line_size); /* Mask off 1-bits beyond the line width. */ end_data[-1] &= rmask; /* Remove trailing 0s. */ while (end_data > data_words && end_data[-1] == 0) end_data--; /* if complete line empty */ if (end_data == data_words){ last_line_empty++; /* since head-movement depends on 300dpi color-data, count only every second row */ if (last_line_empty > 1){ num_blank_lines++; last_line_empty = 0; } continue; } /* Skip blank lines if any */ if (num_blank_lines > 0) { fprintf(prn_stream, "%dy", num_blank_lines); num_blank_lines = 0; last_line_empty = 0; misc_vars->is_two_pass = 1; /* reset */ memset(data_ptrs->plane_data[0][0], 0, (misc_vars->plane_size * 2 * misc_vars->num_comps)); memset(data_ptrs->plane_data_c[0][0], 0, (misc_vars->plane_size_c * 2 * misc_vars->num_comps)); } else { /* all blank lines printed, now for the non-blank lines */ last_line_empty = 0; /* reset since this line is not empty */ misc_vars->is_color_data = 0; /* maybe we have color ? */ print_non_blank_lines (pdev, data_ptrs, misc_vars, error_values, prn_stream, out_count); } } /* End for lnum ... */ return ; } /* End send each scan line in turn */ /* Printing non-blank lines */ void print_non_blank_lines (gx_device_printer * pdev, struct ptr_arrays * data_ptrs, struct misc_struct * misc_vars, struct error_val_field * error_values, FILE * prn_stream, int out_count) { void do_ucr (P8(int bytecount, byte * inbyte, byte * kvalues, byte * cvalues, byte * mvalues, byte * yvalues, int * kcorrect, int ggg)); int do_gcr (P7(int bytecount, byte * inbyte, byte * kvalues, byte * cvalues, byte * mvalues, byte * yvalues, int * kcorrect)); void do_floyd_steinberg (P7(int scan, int cscan, int plane_size, int plane_size_c, struct ptr_arrays * data_ptrs, gx_device_printer * pdev, struct error_val_field * error_values)); void FSDlinebw (P7(int scan, int plane_size, struct error_val_field * error_values, byte * kP, int n, int * ep, byte * dp)); int test_scan (P4(int size, byte * current, byte * last, byte * control)); void save_color_data(P3(int size, byte * current, byte * saved)); void rescale_byte_wise (P4(int bytecount, byte * inbytea, byte * inbyteb, byte * outbyte)); int i; byte *kP = data_ptrs->plane_data[misc_vars->scan + 2][3]; byte *dp = data_ptrs->data[misc_vars->scan + 2]; int *ep = data_ptrs->errors[misc_vars->scan]; /* we need cmyk color separation befor all the rest, since black may be contained in the color fields. This needs to be done on all pixel-rows, since even unused color-bytes might generate black */ misc_vars->is_color_data = do_gcr (misc_vars->databuff_size, data_ptrs->data[misc_vars->scan], &gammat.k[0], &gammat.c[0], &gammat.m[0], &gammat.y[0], &gammat.correct[0]); /* dithering the black-plane */ FSDlinebw(misc_vars->scan, misc_vars->plane_size, error_values, kP, 4, ep, dp); /* Compress the black output data*/ out_count = gdev_pcl_mode9compress(misc_vars->plane_size, data_ptrs->plane_data[misc_vars->scan][3], data_ptrs->plane_data[1-misc_vars->scan][3], data_ptrs->out_data); /* and output the black data */ if (out_count) { fprintf(prn_stream, "%dv", out_count); fwrite(data_ptrs->out_data, sizeof(byte), out_count, prn_stream); } else { fputc('v', prn_stream) ; } /* since color resolution is only half of the b/w-resolution, we only output every second row */ if (misc_vars->is_two_pass > 1) { rescale_byte_wise (misc_vars->databuff_size, data_ptrs->data[misc_vars->scan], data_ptrs->data[1 - misc_vars->scan], data_ptrs->data_c[misc_vars->cscan]); /* dither the color planes */ do_floyd_steinberg(misc_vars->scan, misc_vars->cscan, misc_vars->plane_size, misc_vars->plane_size_c, data_ptrs, pdev, error_values); /* Transfer raster graphics in the order C, M, Y, that is planes 2,1,0 */ for (i = misc_vars->num_comps - 2; i >= 0; i--) { /* output the lower color planes */ out_count = gdev_pcl_mode9compress((int) (misc_vars->plane_size_c/2), data_ptrs->plane_data_c[misc_vars->cscan][i], data_ptrs->plane_data_c[1-misc_vars->cscan][i], data_ptrs->out_data); if (out_count) { if (cdj850->retstatus > 0) { fprintf(prn_stream, "%d%c", out_count, "vvvv"[i]); } else { fprintf(prn_stream, "%d%c", out_count, "wvvv"[i]); } fwrite(data_ptrs->out_data, sizeof(byte), out_count, prn_stream); } else { if (cdj850->retstatus > 0) { fprintf(prn_stream, "%c","vvvv"[i]); } else { fprintf(prn_stream, "%c","wvvv"[i]); } } /* output the upper color planes */ if (cdj850->retstatus > 0) { out_count = gdev_pcl_mode9compress((int) (misc_vars->plane_size_c/2), data_ptrs->plane_data_c[misc_vars->cscan][i+4], data_ptrs->plane_data_c[1 - misc_vars->cscan][i+4], data_ptrs->out_data); if (out_count) { fprintf(prn_stream, "%d%c", out_count, "wvvv"[i]); fwrite(data_ptrs->out_data, sizeof(byte), out_count, prn_stream); } else { fprintf(prn_stream, "%c","wvvv"[i]); } } /* end retstatus >0 && is color */ } /* End For i = num_comps */ misc_vars->is_two_pass = 0; misc_vars->cscan = 1 - misc_vars->cscan; } /* End of is_two_pass */ misc_vars->is_two_pass = misc_vars->is_two_pass + 1; misc_vars->scan = 1 - misc_vars->scan; /* toggle scan direction */ return; } void save_color_data(int size, byte * current, byte * saved) { int i; for (i=0;ierrors[0]; epc = data_ptrs->errors_c[0]; if (misc_vars->bits_per_pixel > 4) { /* Randomly seed initial error buffer */ /* Otherwise, the first dithered rows would look rather uniform */ for (i = 0; i < misc_vars->databuff_size; i++) { /* 600dpi planes */ *ep = RANDOM; ep++; } /* Now for the 2 * 300dpi color planes */ for (i = 0; i < misc_vars->databuff_size_c; i++) { *epc = RANDOM; epc++; } } return; } /* moved that code into his own subroutine, otherwise things get somewhat clumsy */ void do_floyd_steinberg(int scan, int cscan, int plane_size, int plane_size_c, struct ptr_arrays * data_ptrs, gx_device_printer * pdev, struct error_val_field * error_values) { void FSDlinebw(P7(int scan, int plane_size, struct error_val_field * error_values, byte * kP, int n, int * ep, byte * dp)); void FSDlinec2(P9(int scan, int plane_size, struct error_val_field * error_values, byte * cPa, byte * mPa, byte * yPa, int n, byte * dp, int * ep)); void FSDlinec3(P12(int scan, int plane_size, struct error_val_field * error_values, byte * cPa, byte * mPa, byte * yPa, byte * cPb, byte * mPb, byte * yPb, int n, byte * dp, int * ep)); void FSDlinec4(P12(int scan, int plane_size, struct error_val_field * error_values, byte * cPa, byte * mPa, byte * yPa, byte * cPb, byte * mPb, byte * yPb, int n, byte * dp, int * ep)); /* the color pointers */ byte *cPa, *mPa, *yPa, *cPb, *mPb, *yPb; byte *dpc; int *epc; /* the b/w pointers */ byte *kP, *dp; int *ep; /* the color pointers, lower byte */ cPa = data_ptrs->plane_data_c[cscan+2][2]; mPa = data_ptrs->plane_data_c[cscan+2][1]; yPa = data_ptrs->plane_data_c[cscan+2][0]; /* upper byte */ cPb = data_ptrs->plane_data_c[cscan+2][6]; mPb = data_ptrs->plane_data_c[cscan+2][5]; yPb = data_ptrs->plane_data_c[cscan+2][4]; /* data and error */ dpc = data_ptrs->data_c[cscan+2]; epc = data_ptrs->errors_c[cscan]; /* the b/w pointers */ kP = data_ptrs->plane_data[scan + 2][3]; dp = data_ptrs->data[scan + 2]; ep = data_ptrs->errors[scan]; if ((cdj850->retstatus > 0) && (cdj850->papertype > 2)) { FSDlinec4(cscan, plane_size_c/2, error_values, cPa, mPa, yPa, cPb, mPb, yPb, 4, dpc, epc); } if ((cdj850->retstatus > 0) && (cdj850->papertype <=2)) { FSDlinec3(cscan, plane_size_c/2, error_values, cPa, mPa, yPa, cPb, mPb, yPb, 4, dpc, epc); } if (cdj850->retstatus == 0) { FSDlinec2(cscan, plane_size_c/2, error_values, cPa, mPa, yPa, 4, dpc, epc); } return ; } /* here we do our own gamma-correction */ void do_gamma(float mastergamma, float gammaval, byte values[256]) { int i; float gamma; if (gammaval > 0.0) { gamma = gammaval; } else { gamma = mastergamma; } for (i=0;i<256;i++){ values[i] = (byte) (255.0 * (1.0 - pow(((double)(255.0-(float)i)/255.0), (double)(1.0/gamma)))); } return; } /* here we calculate a lookup-table which is used to compensate the relativ loss of color due to undercolor-removal */ void do_black_correction(float kvalue, int kcorrect[256]) { int i; for (i=0;i<256;i++){ kcorrect[i] = (int) ( 100.0 * kvalue * ( pow(10.0, pow((i/255.0), 3.0) ) -1.0 ) ); } return; } /* For Better Performance we use a macro here */ #define DOUCR(col1, col2, col3, col4)\ {\ /* determine how far we are from the grey axis. This is */\ /* traditionally done by computing MAX(CMY)-MIN(CMY). */\ /* However, if two colors are very similar, we could */\ /* as either CMYRGB and K. Therefore we calculate the */\ /* the distance col1-col2 and col2-col3, and use the */\ /* smaller one. */\ a = *col1 - *col2;\ b = *col2 - *col3;\ if (a >= b) {\ grey_distance = 1.0 - (b/255.0);\ } else {\ grey_distance = 1.0 - (a/255.0);\ }\ ucr = (byte) (*col3 * grey_distance); \ *col4 = *col4 + ucr; /* add removed black to black */\ /* remove only as much color as black is surviving the */\ /* gamma correction */\ ucr = *(kvalues + ucr);\ *col1 = *col1 - ucr ;\ *col2 = *col2 - ucr ;\ *col3 = *col3 - ucr ;\ } /* For Better Performance we use a macro here */ #define DOGCR(col1, col2, col3, col4)\ {\ ucr = (int) *col3;\ *col1 = *col1 - ucr ;\ *col2 = *col2 - ucr ;\ *col3 = *col3 - ucr ;\ *col4 = *col4 + ucr; /* add removed black to black */\ kadd = ucr + *(kcorrect + ucr);\ uca_fac = 1.0 + (kadd/255.0);\ *col1 = *col1 * uca_fac;\ *col2 = *col2 * uca_fac;\ } int x_mul_div (int a, int b, int c) { int result; result = (int) ((a * b) / c) ; return result; } /* Transform from cmy into hsv */ void cmy2hsv(int *c, int *m, int *y, int *h, int *s, int *v) { int hue; int r, g, b; int r1, g1, b1; int maxValue, minValue, diff; r = 255 - *c; g = 255 - *m; b = 255 - *y; maxValue = max(r, max(g,b)); minValue = min(r,min(g,b)); diff = maxValue - minValue; *v = maxValue; if (maxValue != 0) *s = x_mul_div(diff,255,maxValue); else *s = 0; if (*s == 0) { hue = 0; } else { r1 = x_mul_div(maxValue - r,255,diff); g1 = x_mul_div(maxValue - g,255,diff); b1 = x_mul_div(maxValue - b,255,diff); if (r == maxValue) hue = b1 - g1; else if (g == maxValue) hue = 510 + r1 - b1; else hue = 1020 + g1 - r1; if (hue < 0) hue += 1530; } *h = (hue + 3) / 6; return; } /* Since resolution can be different on different planes, we need to do real color separation, here we try a real grey component replacement */ int do_gcr (int bytecount, byte * inbyte, byte kvalues[256], byte cvalues[256], byte mvalues[256], byte yvalues[256], int kcorrect[256]) { int i, ucr, kadd, is_color = 0; byte *black, *cyan, *magenta, *yellow; float uca_fac; /* Grey component replacement */ for (i=0;i 0) { /* if any color at all */ is_color = 1; if ((*cyan >= *magenta) && (*magenta >= *yellow) && (*yellow > 0)){ /* if any grey component */ DOGCR(cyan,magenta,yellow,black); } else if ((*cyan >= *yellow) && (*yellow >= *magenta) && (*magenta > 0)){ DOGCR(cyan,yellow,magenta,black); } else if ((*yellow >= *magenta) && (*magenta >= *cyan) && (*cyan > 0)){ DOGCR(yellow,magenta,cyan,black); } else if ((*yellow >= *cyan ) && (*cyan >= *magenta) && (*magenta > 0)){ DOGCR(yellow,cyan,magenta,black); } else if ((*magenta >= *yellow ) && (*yellow >= *cyan) && (*cyan > 0)){ DOGCR(magenta,yellow,cyan,black); } else if ((*magenta >= *cyan ) && (*cyan >= *yellow) && (*yellow > 0)){ DOGCR(magenta,cyan,yellow,black); } else { /* do gamma only if no black */ } *cyan = *(cvalues + *cyan); *magenta = *(mvalues + *magenta); *yellow = *(yvalues + *yellow); } /* end of if c+m+y > 0 */ *black = *(kvalues + *black); } /* end of for bytecount */ return is_color; } /* Since resolution can be different on different planes, we need to rescale the data byte by byte*/ void rescale_byte_wise (int bytecount, byte * inbytea, byte * inbyteb, byte * outbyte) { register int i,j; int max = bytecount/2; for (i=0;i>= 1) { /* dp points to the first word of the input data which is in kcmy-format */ /* k points to the beginning of the first outbut byte, which is filled up, bit by bit while looping over bytemask */ /* ep points to the first word of the error-plane which contains the errors kcmy format */ /* err_values->k tempararily holds the error-value */ /* bitmask selects the bit to be set in the outbyte */ /* n gives the offset for the byte selection within words. With simple cmyk-printing, this should be 4 */ /* 0 points to the active color within the input-word, i.e. 0 = black, 1 = cyan, 2 = yellow, 3 = magenta */ FSdither(dp, k, ep, error_values->k, bitmask, -n, 0); dp += n, ep += n; /* increment the input and error pointer one word (=4 byte) further, in order to convert the next word into an bit */ } *kP++ = k; /* fill the output-plane byte with the computet byte and increment the output plane pointer one byte */ } } else { /* going_down */ byte k, bitmask; int oldErr, i; for (i = 0; i < plane_size; i++) { bitmask = 0x01; for (k = 0; bitmask != 0; bitmask <<= 1) { dp -= n, ep -= 4; FSdither(dp, k, ep, error_values->k, bitmask, n, 0); } *--kP = k; } } return; } /* Since bw has already been dithered for the hp850c, we need an adapted dither algorythm */ void FSDlinec2(int scan, int plane_size, struct error_val_field * error_values, byte * cPa, byte * mPa, byte * yPa, int n, byte * dp, int * ep) { if (scan == 0) { /* going_up */ int oldErr, i; byte ca, ya, ma, bitmask; for (i = 0; i < plane_size; i++) { bitmask = 0x80; ca = ya = ma = 0; for (ca =0; bitmask != 0; bitmask >>= 1) { FSdither(dp, ca, ep, error_values->c, bitmask, -n, n - 3); FSdither(dp, ma, ep, error_values->m, bitmask, -n, n - 2); FSdither(dp, ya, ep, error_values->y, bitmask, -n, n - 1); dp += n, ep += n; } *cPa++ = ca; *mPa++ = ma; *yPa++ = ya; } } else { /* going_down */ byte ca, ya, ma, bitmask; int oldErr, i; for (i = 0; i < plane_size; i++) { bitmask = 0x01; ca = ya = ma = 0; for (ca=0; bitmask != 0; bitmask <<= 1) { dp -= n, ep -= 4; FSdither(dp, ya, ep, error_values->y, bitmask, n, n - 1); FSdither(dp, ma, ep, error_values->m, bitmask, n, n - 2); FSdither(dp, ca, ep, error_values->c, bitmask, n, n - 3); } *--yPa = ya; *--mPa = ma; *--cPa = ca; } } return; } /* On ordinary paper, we'll only use 3 intensities with the hp850 */ void FSDlinec3(int scan, int plane_size, struct error_val_field * error_values, byte * cPa, byte * mPa, byte * yPa, byte * cPb, byte * mPb, byte * yPb, int n, byte * dp, int * ep) { if (scan == 0) { /* going_up */ byte ca, ya, ma, cb, yb, mb, bitmask; int oldErr, i; for (i = 0; i < plane_size; i++) { bitmask = 0x80; ca = ya = ma = cb = yb = mb = 0; for (ca =0; bitmask != 0; bitmask >>= 1) { FSdither8503(dp, ca, cb, ep, error_values->c, bitmask, -4, n - 3); FSdither8503(dp, ma, mb, ep, error_values->m, bitmask, -4, n - 2); FSdither8503(dp, ya, yb, ep, error_values->y, bitmask, -4, n - 1); dp += n, ep += 4; } *cPa++ = ca; *mPa++ = ma; *yPa++ = ya; *cPb++ = cb; *mPb++ = mb; *yPb++ = yb; } } else { /* going_down */ byte ca, ya, ma, cb, yb, mb, bitmask; int oldErr, i; for (i = 0; i < plane_size; i++) { bitmask = 0x01; ca = ya = ma = cb = yb = mb = 0; for (ca=0; bitmask != 0; bitmask <<= 1) { dp -= n, ep -= 4; FSdither8503(dp, ya, yb, ep, error_values->y, bitmask, 4, n - 1); FSdither8503(dp, ma, mb, ep, error_values->m, bitmask, 4, n - 2); FSdither8503(dp, ca, cb ,ep, error_values->c, bitmask, 4, n - 3); } *--yPa = ya; *--mPa = ma; *--cPa = ca; *--yPb = yb; *--mPb = mb; *--cPb = cb; } } return; } /* The hp850c knows about 4 intensity levels per color. Once more, we need an adapted dither algorythm */ void FSDlinec4(int scan, int plane_size, struct error_val_field * error_values, byte * cPa, byte * mPa, byte * yPa, byte * cPb, byte * mPb, byte * yPb, int n, byte * dp, int * ep) { if (scan == 0) { /* going_up */ byte ca, ya, ma, cb, yb, mb, bitmask; int oldErr, i; for (i = 0; i < plane_size; i++) { bitmask = 0x80; ca = ya = ma = cb = yb = mb = 0; for (ca =0; bitmask != 0; bitmask >>= 1) { FSdither8504(dp, ca, cb, ep, error_values->c, bitmask, -4, n - 3); FSdither8504(dp, ma, mb, ep, error_values->m, bitmask, -4, n - 2); FSdither8504(dp, ya, yb, ep, error_values->y, bitmask, -4, n - 1); dp += n, ep += 4; } *cPa++ = ca; *mPa++ = ma; *yPa++ = ya; *cPb++ = cb; *mPb++ = mb; *yPb++ = yb; } } else { /* going_down */ byte ca, ya, ma, cb, yb, mb, bitmask; int oldErr, i; for (i = 0; i < plane_size; i++) { bitmask = 0x01; ca = ya = ma = cb = yb = mb = 0; for (ca=0; bitmask != 0; bitmask <<= 1) { dp -= n, ep -= 4; FSdither8504(dp, ya, yb, ep, error_values->y, bitmask, 4, n - 1); FSdither8504(dp, ma, mb, ep, error_values->m, bitmask, 4, n - 2); FSdither8504(dp, ca, cb ,ep, error_values->c, bitmask, 4, n - 3); } *--yPa = ya; *--mPa = ma; *--cPa = ca; *--yPb = yb; *--mPb = mb; *--cPb = cb; } } return; } /* caculate the needed memory */ void calculate_memory_size (gx_device_printer * pdev, struct misc_struct * misc_vars) { misc_vars->line_size = gdev_prn_raster(pdev); misc_vars->line_size_c = misc_vars->line_size/2 ; misc_vars->line_size_words = (misc_vars->line_size + W - 1) / W; misc_vars->paper_size = gdev_pcl_paper_size((gx_device *)pdev); misc_vars->num_comps = pdev->color_info.num_components; misc_vars->bits_per_pixel = pdev->color_info.depth; misc_vars->storage_bpp = misc_vars->num_comps * 8; misc_vars->expanded_bpp = misc_vars->num_comps * 8; misc_vars->errbuff_size = 0; misc_vars->errbuff_size_c = 0; misc_vars->plane_size = calc_buffsize(misc_vars->line_size, misc_vars->storage_bpp); /* plane_size_c is dependedend on the bits used for dithering. Currently 2 bits are sufficient */ misc_vars->plane_size_c = calc_buffsize((misc_vars->line_size_c * 2), misc_vars->storage_bpp); /* 4n extra values for line ends */ /* might be wrong, see gdevcdj.c */ misc_vars->errbuff_size = calc_buffsize((misc_vars->plane_size * misc_vars->expanded_bpp + misc_vars->num_comps * 4) * I, 1); /* 4n extra values for line ends */ misc_vars->errbuff_size_c = calc_buffsize((misc_vars->plane_size_c/2 * misc_vars->expanded_bpp + misc_vars->num_comps * 4) * I, 1); misc_vars->databuff_size = misc_vars->plane_size * misc_vars->storage_bpp; misc_vars->databuff_size_c = misc_vars->plane_size_c/2 * misc_vars->storage_bpp; misc_vars->outbuff_size = misc_vars->plane_size * 4; misc_vars->storage_size_words = (((misc_vars->plane_size) * 2 * misc_vars->num_comps) + misc_vars->databuff_size + misc_vars->errbuff_size + misc_vars->outbuff_size + ((misc_vars->plane_size_c) * 2 * misc_vars->num_comps) + misc_vars->databuff_size_c + misc_vars->errbuff_size_c + (4*misc_vars->plane_size_c)) / W; return; } /* Initialise the needed pointers */ void init_data_structure(gx_device_printer * pdev, struct ptr_arrays * data_ptrs, struct misc_struct * misc_vars) { int i; byte * p = (byte *) data_ptrs->storage; misc_vars->compression = 9; misc_vars->scan = 0; misc_vars->cscan = 0; misc_vars->is_two_pass = 1; /* the b/w pointer */ data_ptrs->data[0] = data_ptrs->data[1] = data_ptrs->data[2] = p; data_ptrs->data[3] = p + misc_vars->databuff_size; /* Note: The output data will overwrite part of the input-data */ if (misc_vars->bits_per_pixel > 1) { p += misc_vars->databuff_size; } if (misc_vars->bits_per_pixel > 4) { data_ptrs->errors[0] = (int *)p + misc_vars->num_comps * 2; data_ptrs->errors[1] = data_ptrs->errors[0] + misc_vars->databuff_size; p += misc_vars->errbuff_size; } for (i = 0; i num_comps; i++) { data_ptrs->plane_data[0][i] = data_ptrs->plane_data[2][i] = p; p += misc_vars->plane_size; } for (i = 0; i < misc_vars->num_comps; i++) { data_ptrs->plane_data[1][i] = p; data_ptrs->plane_data[3][i] = p + misc_vars->plane_size; p += misc_vars->plane_size; } data_ptrs->out_data = p; p += misc_vars->outbuff_size; /* --------------------------------------------------------- now for the color pointers --------------------------------------------------------- */ data_ptrs->data_c[0] = data_ptrs->data_c[1] = data_ptrs->data_c[2] = p; data_ptrs->data_c[3] = p + misc_vars->databuff_size_c; /* Note: The output data will overwrite part of the input-data */ if (misc_vars->bits_per_pixel > 1) { p += misc_vars->databuff_size_c; } if (misc_vars->bits_per_pixel > 4) { data_ptrs->errors_c[0] = (int *)p + misc_vars->num_comps * 2; data_ptrs->errors_c[1] = data_ptrs->errors_c[0] + misc_vars->databuff_size_c; p += misc_vars->errbuff_size_c; } /* pointer for the lower bits of the output data */ for (i = 0; i < misc_vars->num_comps; i++) { data_ptrs->plane_data_c[0][i] = data_ptrs->plane_data_c[2][i] = p; p += misc_vars->plane_size_c/2; } for (i = 0; i < misc_vars->num_comps; i++) { data_ptrs->plane_data_c[1][i] = p; data_ptrs->plane_data_c[3][i] = p + misc_vars->plane_size_c/2; p += misc_vars->plane_size_c/2; } /* pointer for the upper bits of the output data */ for (i = 0; i < misc_vars->num_comps; i++) { data_ptrs->plane_data_c[0][i+4] = data_ptrs->plane_data_c[2][i+4] = p; p += misc_vars->plane_size_c/2; } for (i = 0; i < misc_vars->num_comps; i++) { data_ptrs->plane_data_c[1][i+4] = p; data_ptrs->plane_data_c[3][i+4] = p + misc_vars->plane_size_c/2; p += misc_vars->plane_size_c/2; } for (i = 0; i < misc_vars->num_comps; i++) { data_ptrs->test_data[i] = p; p += misc_vars->plane_size_c/2; } /* Clear temp storage */ memset(data_ptrs->storage, 0, misc_vars->storage_size_words * W); return; } /* end init_data_structure */ /* Configure the printer and start Raster mode */ void start_raster_mode (gx_device_printer * pdev, int compression, int paper_size, FILE * prn_stream) { int laenge = 26 ; /* Be sure that cRET is turned off when printing in draft-mode */ if (cdj850->quality < 0) cdj850->retstatus = 0; if ((cdj850->retstatus > 0) && (cdj850->papertype > 2)) { hp850_cmyk_init.a14 = 0x04; /* Intensity levels cyan */ hp850_cmyk_init.a20 = 0x04; /* Intensity levels magenta */ hp850_cmyk_init.a26 = 0x04; /* Intensity levels yellow */ } if ((cdj850->retstatus > 0) && (cdj850->papertype <= 2)) { hp850_cmyk_init.a14 = 0x03; /* Intensity levels cyan */ hp850_cmyk_init.a20 = 0x03; /* Intensity levels magenta */ hp850_cmyk_init.a26 = 0x03; /* Intensity levels yellow */ } fputs("\033*rbC", prn_stream); /* End raster graphics */ fputs("\033E", prn_stream); /* Reset */ /* Page size, orientation, top margin & perforation skip */ fprintf(prn_stream, "\033&l%daolE", paper_size); /* Print Quality, -1 = draft, 0 = normal, 1 = presentation */ fprintf(prn_stream, "\033*o%dM", cdj850->quality); /* Media Type,0 = plain paper, 1 = bond paper, 2 = special paper, 3 = glossy film, 4 = transparency film */ fprintf(prn_stream, "\033&l%dM", cdj850->papertype); /* Move to top left of printed area */ fprintf(prn_stream, "\033*p%dY", (int)(600 * DOFFSET)); /* This will start and configure the raster-mode */ fprintf(prn_stream, "\033*g%dW",laenge); /* The new configure raster data comand */ fwrite(&hp850_cmyk_init,sizeof(byte),laenge,prn_stream); /* Transmit config data */ /* From now on, all escape commands start with \033*b, so we * combine them (if the printer supports this). */ fputs("\033*b", prn_stream); /* Set compression if the mode has been defined. */ if (compression) fprintf(prn_stream, "%dm", compression); return; } /* end configure raster-mode */ /* * Mode 9 2D compression for the HP DeskJets . This mode can give * very good compression ratios, especially if there are areas of flat * colour (or blank areas), and so is 'highly recommended' for colour * printing in particular because of the very large amounts of data which * can be generated */ private int gdev_pcl_mode9compress(int bytecount, const byte * current, const byte * previous, byte * compressed) { register const byte *cur = current; register const byte *prev = previous; register byte *out = compressed; const byte *end = current + bytecount; while (cur < end) { /* Detect a run of unchanged bytes. */ const byte *run = cur; register const byte *diff; int offset; while (cur < end && *cur == *prev) { cur++, prev++; } if (cur == end) break; /* rest of row is unchanged */ /* Detect a run of changed bytes. */ /* We know that *cur != *prev. */ diff = cur; do { prev++; cur++; } while (cur < end && *cur != *prev); /* Now [run..diff) are unchanged, and */ /* [diff..cur) are changed. */ offset = diff - run; { const byte *stop_test = cur - 4; int dissimilar, similar; while (diff < cur) { const byte *compr = diff; const byte *next; /* end of run */ byte value = 0; while (diff <= stop_test && ((value = *diff) != diff[1] || value != diff[2] || value != diff[3])) diff++; /* Find out how long the run is */ if (diff > stop_test) /* no run */ next = diff = cur; else { next = diff + 4; while (next < cur && *next == value) next++; } #define MAXOFFSETU 15 #define MAXCOUNTU 7 /* output 'dissimilar' bytes, uncompressed */ if ((dissimilar = diff - compr)) { int temp, i; if ((temp = --dissimilar) > MAXCOUNTU) temp = MAXCOUNTU; if (offset < MAXOFFSETU) *out++ = (offset << 3) | (byte) temp; else { *out++ = (MAXOFFSETU << 3) | (byte) temp; offset -= MAXOFFSETU; while (offset >= 255) { *out++ = 255; offset -= 255; } *out++ = offset; } if (temp == MAXCOUNTU) { temp = dissimilar - MAXCOUNTU; while (temp >= 255) { *out++ = 255; temp -= 255; } *out++ = (byte) temp; } for (i = 0; i <= dissimilar; i++) *out++ = *compr++; offset = 0; } /* end uncompressed */ #define MAXOFFSETC 3 #define MAXCOUNTC 31 /* output 'similar' bytes, run-length encoded */ if ((similar = next - diff)) { int temp; if ((temp = (similar -= 2)) > MAXCOUNTC) temp = MAXCOUNTC; if (offset < MAXOFFSETC) *out++ = 0x80 | (offset << 5) | (byte) temp; else { *out++ = 0x80 | (MAXOFFSETC << 5) | (byte) temp; offset -= MAXOFFSETC; while (offset >= 255) { *out++ = 255; offset -= 255; } *out++ = offset; } if (temp == MAXCOUNTC) { temp = similar - MAXCOUNTC; while (temp >= 255) { *out++ = 255; temp -= 255; } *out++ = (byte) temp; } *out++ = value; offset = 0; } /* end compressed */ diff = next; } } } return out - compressed; } private int near cdj_put_param_int(gs_param_list *plist, gs_param_name pname, int *pvalue, int minval, int maxval, int ecode) { int code, value; switch ( code = param_read_int(plist, pname, &value) ) { default: return code; case 1: return ecode; case 0: if ( value < minval || value > maxval ) param_signal_error(plist, pname, gs_error_rangecheck); *pvalue = value; return (ecode < 0 ? ecode : 1); } } private int near cdj_put_param_float(gs_param_list *plist, gs_param_name pname, float *pvalue, float minval, float maxval, int ecode) { int code; float value; switch ( code = param_read_float(plist, pname, &value) ) { default: return code; case 1: return ecode; case 0: if ( value < minval || value > maxval ) param_signal_error(plist, pname, gs_error_rangecheck); *pvalue = value; return (ecode < 0 ? ecode : 1); } } private int cdj_set_bpp(gx_device *pdev, int bpp, int ccomps) { gx_device_color_info *ci = &pdev->color_info; if (ccomps && bpp == 0) { if (cprn_device->cmyk) { switch (ccomps) { default: return gs_error_rangecheck; /*NOTREACHED*/ break; case 1: bpp = 1; break; case 3: bpp = 24; break; case 4: switch (ci->depth) { case 8: case 16: case 24: case 32: break; default: bpp = cprn_device->default_depth; break; } break; } } } if (bpp == 0) { bpp = ci->depth; /* Use the current setting. */ } if (cprn_device->cmyk < 0) { /* Reset procedures because we may have been in another mode. */ dev_proc(pdev, map_cmyk_color) = gdev_cmyk_map_cmyk_color; dev_proc(pdev, map_rgb_color) = NULL; dev_proc(pdev, map_color_rgb) = gdev_cmyk_map_color_rgb; if (pdev->is_open) gs_closedevice(pdev); } /* Check for valid bpp values */ switch ( bpp ) { case 16: case 32: if (cprn_device->cmyk && ccomps && ccomps != 4) goto bppe; break; case 24: if (!cprn_device->cmyk || ccomps == 0 || ccomps == 4) { break; } else if (ccomps == 1) { goto bppe; } else { /* 3 components 24 bpp printing for CMYK device. */ cprn_device->cmyk = -1; } break; case 8: if (cprn_device->cmyk) { if (ccomps) { if (ccomps == 3) { cprn_device->cmyk = -1; bpp = 3; } else if (ccomps != 1 && ccomps != 4) { goto bppe; } } if (ccomps != 1) break; } else { break; } case 1: if (ccomps != 1) goto bppe; if (cprn_device->cmyk && bpp != pdev->color_info.depth) { dev_proc(pdev, map_cmyk_color) = NULL; dev_proc(pdev, map_rgb_color) = gdev_cmyk_map_rgb_color; if (pdev->is_open) { gs_closedevice(pdev); } } break; case 3: if (!cprn_device->cmyk) { break; } default: bppe: return gs_error_rangecheck; } if (cprn_device->cmyk == -1) { dev_proc(pdev, map_cmyk_color) = NULL; dev_proc(pdev, map_rgb_color) = gdev_pcl_map_rgb_color; dev_proc(pdev, map_color_rgb) = gdev_pcl_map_color_rgb; if (pdev->is_open) { gs_closedevice(pdev); } } switch (ccomps) { case 0: break; case 1: if (bpp != 1 && bpp != 8) goto cce; break; case 4: if (cprn_device->cmyk) { if (bpp >= 8) break; } case 3: if (bpp == 1 || bpp == 3 || bpp == 8 || bpp == 16 || bpp == 24 || bpp == 32) { break; } cce: default: return gs_error_rangecheck; } if (cprn_device->cmyk) { if (cprn_device->cmyk > 0) { ci->num_components = ccomps ? ccomps : (bpp < 8 ? 1 : 4); } else { ci->num_components = ccomps ? ccomps : (bpp < 8 ? 1 : 3); } if (bpp != 1 && ci->num_components == 1) { /* We do dithered grays. */ bpp = bpp < 8 ? 8 : bpp; } ci->max_color = (1 << (bpp >> 2)) - 1; ci->max_gray = (bpp >= 8 ? 255 : 1); if (ci->num_components == 1) { ci->dither_grays = (bpp >= 8 ? 5 : 2); ci->dither_colors = (bpp >= 8 ? 5 : bpp > 1 ? 2 : 0); } else { ci->dither_grays = (bpp > 8 ? 5 : 2); ci->dither_colors = (bpp > 8 ? 5 : bpp > 1 ? 2 : 0); } } else { ci->num_components = (bpp == 1 || bpp == 8 ? 1 : 3); ci->max_color = (bpp >= 8 ? 255 : bpp > 1 ? 1 : 0); ci->max_gray = (bpp >= 8 ? 255 : 1); ci->dither_grays = (bpp >= 8 ? 5 : 2); ci->dither_colors = (bpp >= 8 ? 5 : bpp > 1 ? 2 : 0); } ci->depth = ((bpp > 1) && (bpp < 8) ? 8 : bpp); return 0; } /* * Map a CMYK color to a color index. We just use depth / 4 bits per color * to produce the color index. * * Important note: CMYK values are stored in the order K, C, M, Y because of * the way the HP drivers work. * */ #define gx_color_value_to_bits(cv, b) \ ((cv) >> (gx_color_value_bits - (b))) #define gx_bits_to_color_value(cv, b) \ ((cv) << (gx_color_value_bits - (b))) #define gx_cmyk_value_bits(c, m, y, k, b) \ ((gx_color_value_to_bits((k), (b)) << (3 * (b))) | \ (gx_color_value_to_bits((c), (b)) << (2 * (b))) | \ (gx_color_value_to_bits((m), (b)) << (b)) | \ (gx_color_value_to_bits((y), (b)))) #define gx_value_cmyk_bits(v, c, m, y, k, b) \ (k) = gx_bits_to_color_value(((v) >> (3 * (b))) & ((1 << (b)) - 1), (b)), \ (c) = gx_bits_to_color_value(((v) >> (2 * (b))) & ((1 << (b)) - 1), (b)), \ (m) = gx_bits_to_color_value(((v) >> (b)) & ((1 << (b)) - 1), (b)), \ (y) = gx_bits_to_color_value((v) & ((1 << (b)) - 1), (b)) private gx_color_index gdev_cmyk_map_cmyk_color(gx_device* pdev, gx_color_value cyan, gx_color_value magenta, gx_color_value yellow, gx_color_value black) { gx_color_index color; switch (pdev->color_info.depth) { case 1: color = (cyan | magenta | yellow | black) > gx_max_color_value / 2 ? (gx_color_index) 1 : (gx_color_index) 0; break; default: { int nbits = pdev->color_info.depth; if (cyan == magenta && magenta == yellow) { /* Convert CMYK to gray -- Red Book 6.2.2 */ float bpart = ((float) cyan) * (lum_red_weight / 100.) + ((float) magenta) * (lum_green_weight / 100.) + ((float) yellow) * (lum_blue_weight / 100.) + (float) black; cyan = magenta = yellow = (gx_color_index) 0; black = (gx_color_index) (bpart > gx_max_color_value ? gx_max_color_value : bpart); } color = gx_cmyk_value_bits(cyan, magenta, yellow, black, nbits >> 2); } } return color; } /* Mapping of RGB colors to gray values. */ private gx_color_index gdev_cmyk_map_rgb_color(gx_device *pdev, gx_color_value r, gx_color_value g, gx_color_value b) { if (gx_color_value_to_byte(r & g & b) == 0xff) { return (gx_color_index) 0; /* White */ } else { gx_color_value c = gx_max_color_value - r; gx_color_value m = gx_max_color_value - g; gx_color_value y = gx_max_color_value - b; switch (pdev->color_info.depth) { case 1: return (c | m | y) > gx_max_color_value / 2 ? (gx_color_index) 1 : (gx_color_index) 0; /*NOTREACHED*/ break; case 8: return ((ulong) c * lum_red_weight * 10 + (ulong) m * lum_green_weight * 10 + (ulong) y * lum_blue_weight * 10) >> (gx_color_value_bits + 2); /*NOTREACHED*/ break; } } return (gx_color_index) 0; /* This should never happen. */ } /* Mapping of CMYK colors. */ private int gdev_cmyk_map_color_rgb(gx_device *pdev, gx_color_index color, gx_color_value prgb[3]) { switch (pdev->color_info.depth) { case 1: prgb[0] = prgb[1] = prgb[2] = gx_max_color_value * (1 - color); break; case 8: if (pdev->color_info.num_components == 1) { gx_color_value value = (gx_color_value) color ^ 0xff; prgb[0] = prgb[1] = prgb[2] = (value << 8) + value; break; } default: { unsigned long bcyan, bmagenta, byellow, black; int nbits = pdev->color_info.depth; gx_value_cmyk_bits(color, bcyan, bmagenta, byellow, black, nbits >> 2); #ifdef USE_ADOBE_CMYK_RGB /* R = 1.0 - min(1.0, C + K), etc. */ bcyan += black, bmagenta += black, byellow += black; prgb[0] = (bcyan > gx_max_color_value ? (gx_color_value) 0 : gx_max_color_value - bcyan); prgb[1] = (bmagenta > gx_max_color_value ? (gx_color_value) 0 : gx_max_color_value - bmagenta); prgb[2] = (byellow > gx_max_color_value ? (gx_color_value) 0 : gx_max_color_value - byellow); #else /* R = (1.0 - C) * (1.0 - K), etc. */ prgb[0] = (gx_color_value) ((ulong)(gx_max_color_value - bcyan) * (gx_max_color_value - black) / gx_max_color_value); prgb[1] = (gx_color_value) ((ulong)(gx_max_color_value - bmagenta) * (gx_max_color_value - black) / gx_max_color_value); prgb[2] = (gx_color_value) ((ulong)(gx_max_color_value - byellow) * (gx_max_color_value - black) / gx_max_color_value); #endif } } return 0; } private gx_color_index gdev_pcl_map_rgb_color(gx_device *pdev, gx_color_value r, gx_color_value g, gx_color_value b) { if (gx_color_value_to_byte(r & g & b) == 0xff) return (gx_color_index)0; /* white */ else { gx_color_value c = gx_max_color_value - r; gx_color_value m = gx_max_color_value - g; gx_color_value y = gx_max_color_value - b; switch (pdev->color_info.depth) { case 1: return ((c | m | y) > gx_max_color_value / 2 ? (gx_color_index)1 : (gx_color_index)0); case 8: if (pdev->color_info.num_components >= 3) #define gx_color_value_to_1bit(cv) ((cv) >> (gx_color_value_bits - 1)) return (gx_color_value_to_1bit(c) + (gx_color_value_to_1bit(m) << 1) + (gx_color_value_to_1bit(y) << 2)); else #define red_weight 306 #define green_weight 601 #define blue_weight 117 return ((((ulong)c * red_weight + (ulong)m * green_weight + (ulong)y * blue_weight) >> (gx_color_value_bits + 2))); case 16: #define gx_color_value_to_5bits(cv) ((cv) >> (gx_color_value_bits - 5)) #define gx_color_value_to_6bits(cv) ((cv) >> (gx_color_value_bits - 6)) return (gx_color_value_to_5bits(y) + (gx_color_value_to_6bits(m) << 5) + (gx_color_value_to_5bits(c) << 11)); case 24: return (gx_color_value_to_byte(y) + (gx_color_value_to_byte(m) << 8) + ((ulong)gx_color_value_to_byte(c) << 16)); case 32: { return ((c == m && c == y) ? ((ulong)gx_color_value_to_byte(c) << 24) : (gx_color_value_to_byte(y) + (gx_color_value_to_byte(m) << 8) + ((ulong)gx_color_value_to_byte(c) << 16))); } } } return (gx_color_index)0; /* This never happens */ } /* Map a color index to a r-g-b color. */ private int gdev_pcl_map_color_rgb(gx_device *pdev, gx_color_index color, gx_color_value prgb[3]) { /* For the moment, we simply ignore any black correction */ switch (pdev->color_info.depth) { case 1: prgb[0] = prgb[1] = prgb[2] = -((gx_color_value)color ^ 1); break; case 8: if (pdev->color_info.num_components >= 3) { gx_color_value c = (gx_color_value)color ^ 7; prgb[0] = -(c & 1); prgb[1] = -((c >> 1) & 1); prgb[2] = -(c >> 2); } else { gx_color_value value = (gx_color_value)color ^ 0xff; prgb[0] = prgb[1] = prgb[2] = (value << 8) + value; } break; case 16: { gx_color_value c = (gx_color_value)color ^ 0xffff; ushort value = c >> 11; prgb[0] = ((value << 11) + (value << 6) + (value << 1) + (value >> 4)) >> (16 - gx_color_value_bits); value = (c >> 6) & 0x3f; prgb[1] = ((value << 10) + (value << 4) + (value >> 2)) >> (16 - gx_color_value_bits); value = c & 0x1f; prgb[2] = ((value << 11) + (value << 6) + (value << 1) + (value >> 4)) >> (16 - gx_color_value_bits); } break; case 24: { gx_color_value c = (gx_color_value)color ^ 0xffffff; prgb[0] = gx_color_value_from_byte(c >> 16); prgb[1] = gx_color_value_from_byte((c >> 8) & 0xff); prgb[2] = gx_color_value_from_byte(c & 0xff); } break; case 32: #define gx_maxcol gx_color_value_from_byte(gx_color_value_to_byte(gx_max_color_value)) { gx_color_value w = gx_maxcol - gx_color_value_from_byte(color >> 24); prgb[0] = w - gx_color_value_from_byte((color >> 16) & 0xff); prgb[1] = w - gx_color_value_from_byte((color >> 8) & 0xff); prgb[2] = w - gx_color_value_from_byte(color & 0xff); } break; } return 0; } /* new_bpp == save_bpp or new_bpp == 0 means don't change bpp. ccomps == 0 means don't change number of color comps. If new_bpp != 0, it must be the value of the BitsPerPixel element of the plist; real_bpp may differ from new_bpp. */ private int cdj_put_param_bpp(gx_device *pdev, gs_param_list *plist, int new_bpp, int real_bpp, int ccomps) { if (new_bpp == 0 && ccomps == 0) return gdev_prn_put_params(pdev, plist); else { gx_device_color_info save_info; int save_bpp; int code; save_info = pdev->color_info; save_bpp = save_info.depth; #define save_ccomps save_info.num_components if ( save_bpp == 8 && save_ccomps == 3 && !cprn_device->cmyk) save_bpp = 3; code = cdj_set_bpp(pdev, real_bpp, ccomps); if ( code < 0 ) { param_signal_error(plist, "BitsPerPixel", code); param_signal_error(plist, "ProcessColorModel", code); return code; } pdev->color_info.depth = new_bpp; /* cdj_set_bpp maps 3/6 to 8 */ code = gdev_prn_put_params(pdev, plist); if ( code < 0 ) { cdj_set_bpp(pdev, save_bpp, save_ccomps); return code; } cdj_set_bpp(pdev, real_bpp, ccomps); /* reset depth if needed */ if ((cdj850->color_info.depth != save_bpp || (ccomps != 0 && ccomps != save_ccomps)) && pdev->is_open ) return gs_closedevice(pdev); return 0; #undef save_ccomps } }