/* Copyright (C) 1991, 1992, 1993 Aladdin Enterprises. All rights reserved. This file is part of Ghostscript. Ghostscript is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to anyone for the consequences of using it or for whether it serves any particular purpose or works at all, unless he says so in writing. Refer to the Ghostscript General Public License for full details. Everyone is granted permission to copy, modify and redistribute Ghostscript, but only under the conditions described in the Ghostscript General Public License. A copy of this license is supposed to have been given to you along with Ghostscript so you can know your rights and responsibilities. It should be in a file named COPYING. Among other things, the copyright notice and this notice must be preserved on all copies. */ /* gdevmjc.c */ /* Many parts of this file are copied from gdevcdj.c and gdevescp.c */ /* EPSON MJ-700V2C colour printer drivers for Ghostscript */ /* These drivers may also work with EPSON Stylus color printer, though the author hasn't tried. */ /* Any comments, suggestions, and bug reports are welcomed. The e-mail address of the author Kubo, Hiroshi is h-kubo@kuee.kyoto-u.ac.jp or JBD02172@niftyserve.or.jp */ #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 "mjmtx2.c" #include "mjbksep.c" #include "mjhtocmy.c" #include "mjvtbl.c" #include "mjgrnsp.c" #include "mjgrnsp2.c" #include "mjespdtc.c" #include "mjespdtm.c" #include "mjespdty.c" #include "mjbarrie.c" /*** *** Note: Original driver gdevcdj.c for HP color printer was written *** by a user, George Cameron. *** *** An idea of Kuniyoshi Yoshio to borrow the codes of gdevcdj.c *** for another color printer BJC-600J inspired the author. *** *** Basic control sequences and compression algorithm for ESC/P *** V2 printer are taken from gdevescp.c, written by Richard Brown. *** *** The author Kubo, Hiroshi gathered necessary codes for EPSON *** MJ-700V2C and Sylus color printer in gdevmjc.c. ***/ /* * available drivers * * 1. mjc180 MJ-700V2C 180dpi mode * 2. mjc360 MJ-700V2C 360dpi mode * 3. mjc720 MJ-700V2C 720dpi mode * 4. mj500c MJ-500C 360dpi mode */ /* ** Options ** * name type description Density int Controls densty of dots. 1024 is normal setting for 360dpi. Cyan int Controls depth of Cyan. 1024 is normal setting. Magenta int Controls depth of Magenta. 1024 is normal setting. Yellow int Controls depth of Yellow. 1024 is normal setting. Black int Controls depth of Black. 1024 is normal setting. Direction int Specifys whether to print in one way or in both way. 1 for one way, 2 for both way. MicroWeave int 0 resets the micro weave mode. 1 sets the micro weave mode. DotSize int Controls the size of the dots. 0 means normal, 1 means small. ColorComponent int The number of the color components on the printer. 4 for MJ-700V2C, MJ-900C, MJ-800C and so on. 3 for MJ500C and 1 for black/white printing. The default value is 4. ** Examples ** % gs -sDEVICE=mjc360 -sOutputFile=tiger.mj tiger.ps % gs -sDEVICE=mjc360 -dDensity=1152 -dCyan=1000 -dMagenta=896 -dYellow=1024 \ -dBlack=512 -dColorComponent=4 -Direction=1 -sOutputFile=tiger.mj tiger.ps * */ #define MJ700V2C_PRINT_LIMIT 0.34 /* taken from gdevescp.c */ /* Margins are left, bottom, right, top. */ /* left bottom right top */ #define MJ700V2C_MARGINS_A2 0.118, 0.52, 0.118, 0.33465 #define MJ700V2C_MARGINS_A3_NOBI 0.118, 0.52, 0.118, 0.33465 #define MJ700V2C_MARGINS_A3 0.118, 0.52, 0.118, 0.33465 #define MJ700V2C_MARGINS_A4 0.118, 0.52, 0.118, 0.33465 #define MJ700V2C_MARGINS_B4 0.118, 0.52, 0.118, 0.33465 #define MJ700V2C_MARGINS_B5 0.118, 0.52, 0.118, 0.33465 #define MJ700V2C_MARGINS_LETTER 0.118, 0.52, 0.118, 0.33465 /* Default page size is US-Letter or A4 (other sizes from command line) */ #ifdef A2 # define WIDTH_10THS 170 /* 420mm */ # define HEIGHT_10THS 220 /* 594mm */ #elif defined A3_NOBI # define WIDTH_10THS 130 /* 329mm */ # define HEIGHT_10THS 190 /* 483mm */ #elif defined A3 # define WIDTH_10THS 110 /* 297mm */ # define HEIGHT_10THS 170 /* 420mm */ #elif defined A4 # define WIDTH_10THS 83 /* 210mm */ # define HEIGHT_10THS 117 /* 297mm */ #elif defined B4 # define WIDTH_10THS 101 /* 257mm */ # define HEIGHT_10THS 144 /* 364mm */ #elif defined B5 # define WIDTH_10THS 72 /* 182mm */ # define HEIGHT_10THS 101 /* 257mm */ #else # define WIDTH_10THS 85 /* LETTER */ # define HEIGHT_10THS 110 #endif /* Undefined macros expected to be defined in gdevpcl.h */ #define PAPER_SIZE_A3_NOBI 28 #ifndef PAPER_SIZE_A2 #define PAPER_SIZE_A2 29 #endif #define PAPER_SIZE_B4 30 #define PAPER_SIZE_B5 31 /* Define bits-per-pixel for generic drivers - default is 24-bit mode */ #ifndef BITSPERPIXEL #define BITSPERPIXEL 32 #endif #define W sizeof(word) #define I sizeof(int) /* Printer types */ #define MJC180 1 #define MJC360 2 #define MJC720 3 #define MJ500C 4 /* No. of ink jets (used to minimise head movements) */ #define HEAD_ROWS_MONO 50 #define HEAD_ROWS_COLOUR 16 /* only for mj700v2c */ #define MJ_HEAD_ROWS_MONO 64 #define MJ_HEAD_ROWS_COLOUR 16 /* Colour mapping procedures */ private dev_proc_map_rgb_color (gdev_mjc_map_rgb_color); private dev_proc_map_color_rgb (gdev_mjc_map_color_rgb); /* Print-page, properties and miscellaneous procedures */ private dev_proc_open_device(mjc180_open); private dev_proc_open_device(mjc360_open); private dev_proc_open_device(mjc720_open); private dev_proc_open_device(mj500c_open); private dev_proc_print_page(mjc180_print_page); private dev_proc_print_page(mjc360_print_page); private dev_proc_print_page(mjc720_print_page); private dev_proc_print_page(mj500c_print_page); private dev_proc_get_params(mj_get_params); private dev_proc_put_params(mj_put_params); private void expand_line(P4(word*, int, int, int)); private int mj_put_param_int(P6(gs_param_list *, gs_param_name, int *, int, int, int)); private void mj_set_bpp(P2(gx_device *, int)); private uint gdev_prn_rasterwidth(P2(const gx_device_printer *, int )); private gx_color_index mjc_correct_color(P2(gx_device_printer *, gx_color_index)); /* The device descriptors */ struct gx_device_mj_s { gx_device_common; gx_prn_device_common; int density; /* (color depth) * density/1024 = otuput */ int cyan; /* weght for cyan */ int magenta; /* weght for magenta */ int yellow; /* weght for yellow */ int black; /* weght for black */ int dither; /* 0 : off 1: on */ int colorcomp; /* 1: grayscale 3: CMY 4: CMYK */ int direction; /* direction of the head. 1: one way 2: both way */ int microweave; /* Micro weave switch. 0: off 1: on */ int dotsize; /* dot size switch. 0: normal 1: small */ }; typedef struct gx_device_mj_s gx_device_mj; #define mj ((gx_device_mj *) pdev) #define prn_hp_colour_device(procs, dev_name, x_dpi, y_dpi, bpp, print_page)\ prn_device_body(gx_device_mj, procs, dev_name,\ WIDTH_10THS, HEIGHT_10THS, x_dpi, y_dpi, 0, 0, 0, 0, 0,\ bpp, 0, 0, 0, 0, print_page) #define mj_device(procs, dev_name, x_dpi, y_dpi, bpp, print_page, dns, r, g, b, k, dthr, colcom, drct, mcrwv, dtsz)\ { prn_hp_colour_device(procs, dev_name, x_dpi, y_dpi, bpp, print_page),\ dns, r, g, b, k, dthr, colcom, drct, mcrwv, dtsz \ } #define mj_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,\ gdev_mjc_map_rgb_color,\ gdev_mjc_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\ } private int mjc_open(P1(gx_device *)); private int mj_colour_open(P1(gx_device *)); private gx_device_procs mj_procs = mj_colour_procs(mjc_open, mj_get_params, mj_put_params); gx_device_mj far_data gs_mjc180_device = mj_device(mj_procs, "mjc180", 180, 180, BITSPERPIXEL, mjc180_print_page, 4096, 1024, 1024, 1024, 1024, 1, 4, 2, 0, 0); gx_device_mj far_data gs_mjc360_device = mj_device(mj_procs, "mjc360", 360, 360, BITSPERPIXEL, mjc360_print_page, 2048, 1024, 1024, 1024, 1024, 1, 4, 2, 1, 0); gx_device_mj far_data gs_mjc720_device = mj_device(mj_procs, "mjc720", 720, 720, BITSPERPIXEL, mjc720_print_page, 1024, 1024, 1024, 1024, 1024, 1, 4, 2, 1, 1); gx_device_mj far_data gs_mj500c_device = mj_device(mj_procs, "mj500c", 360, 360, BITSPERPIXEL, mj500c_print_page, 3072, 1024, 1024, 1024, 1024, 1, 3, 2, 1, 0); /* Open the printer and set up the margins. */ private int mjc_open(gx_device *pdev) { return mj_colour_open(pdev); } /* Get the paper size code, based on width and height. */ private int gdev_mjc_paper_size(gx_device *dev) { return (dev->height / dev->y_pixels_per_inch >= 22.2 ? PAPER_SIZE_A2 : dev->height / dev->y_pixels_per_inch >= 18.0 ? PAPER_SIZE_A3_NOBI : dev->height / dev->y_pixels_per_inch >= 16.0 ? PAPER_SIZE_A3 : dev->height / dev->y_pixels_per_inch >= 13.6 ? PAPER_SIZE_B4 : dev->height / dev->y_pixels_per_inch >= 11.8 ? PAPER_SIZE_LEGAL : dev->height / dev->y_pixels_per_inch >= 11.1 ? PAPER_SIZE_A4 : dev->height / dev->y_pixels_per_inch >= 10.4 ? PAPER_SIZE_LETTER : dev->height / dev->y_pixels_per_inch >= 9.6 ? PAPER_SIZE_B5 : PAPER_SIZE_LETTER); } private int mj_colour_open(gx_device *pdev) { /* Change the margins if necessary. */ static const float mj_a2[4] = { MJ700V2C_MARGINS_A2 }; static const float mj_a3_nobi[4] = { MJ700V2C_MARGINS_A3_NOBI }; static const float mj_a3[4] = { MJ700V2C_MARGINS_A3 }; static const float mj_a4[4] = { MJ700V2C_MARGINS_A4 }; static const float mj_b4[4] = { MJ700V2C_MARGINS_B4 }; static const float mj_b5[4] = { MJ700V2C_MARGINS_B5 }; static const float mj_letter[4] = { MJ700V2C_MARGINS_LETTER }; const float *m; int psize; int paper_size; /* Set up colour params if put_props has not already done so */ if (pdev->color_info.num_components == 0) mj_set_bpp(pdev, pdev->color_info.depth); paper_size = gdev_mjc_paper_size(pdev); if (paper_size == PAPER_SIZE_A2 ) { m = mj_a2; } else if (paper_size == PAPER_SIZE_A3_NOBI ) { m = mj_a3_nobi; } else if (paper_size == PAPER_SIZE_A3 ) { m = mj_a3; } else if (paper_size == PAPER_SIZE_A4 ) { m = mj_a4; } else if (paper_size == PAPER_SIZE_B4 ) { m = mj_b4; } else if (paper_size == PAPER_SIZE_B5 ) { m = mj_b5; } else { m = mj_letter; } gx_device_set_margins(pdev, m, true); switch (mj->colorcomp) { case 1: pdev->color_info.num_components = 1; /* monochrome */ if (mj->dither) { pdev->color_info.depth = 8; /* grayscale */ } else { pdev->color_info.depth = 1; /* black and white */ } break; case 3: case 4: pdev->color_info.num_components = 3; /* inverse of CMY */ break; } return gdev_prn_open(pdev); } /* Get properties. In addition to the standard and printer * properties, we supply shingling and depletion parameters, * and control over the bits-per-pixel used in output rendering */ /* Added properties for DeskJet 5xxC */ private int mj_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, "Density", &mj->density)) < 0 || (code = param_write_int(plist, "Cyan", &mj->cyan)) < 0 || (code = param_write_int(plist, "Magenta", &mj->magenta)) < 0 || (code = param_write_int(plist, "Yellow", &mj->yellow)) < 0 || (code = param_write_int(plist, "Black", &mj->black)) < 0 || (code = param_write_int(plist, "Dither", &mj->dither)) < 0 || (code = param_write_int(plist, "ColorComponent", &mj->colorcomp)) < 0 || (code = param_write_int(plist, "Direction", &mj->direction)) < 0 || (code = param_write_int(plist, "MicroWeave", &mj->microweave)) < 0 || (code = param_write_int(plist, "DotSize", &mj->dotsize)) < 0 ) return code; return code; } /* Put properties. */ private int mj_put_params(gx_device *pdev, gs_param_list *plist) { int old_bpp = mj->color_info.depth; int bpp = 0; int code = 0; int density = mj->density; int cyan = mj->cyan; int magenta = mj->magenta; int yellow = mj->yellow; int black = mj->black; int dither = mj->dither; int colorcomp = mj->colorcomp; int direction = mj->direction; int microweave = mj->microweave; int dotsize = mj->dotsize; code = mj_put_param_int(plist, "Density", &density, 0, INT_MAX, code); code = mj_put_param_int(plist, "Cyan", &cyan, 0, INT_MAX, code); code = mj_put_param_int(plist, "Magenta", &magenta, 0, INT_MAX, code); code = mj_put_param_int(plist, "Yellow", &yellow, 0, INT_MAX, code); code = mj_put_param_int(plist, "Black", &black, 0, INT_MAX, code); code = mj_put_param_int(plist, "Dither", &dither, 0, 1, code); code = mj_put_param_int(plist, "ColorComponent", &colorcomp, 1, 4, code); code = mj_put_param_int(plist, "Direction", &direction, 1, 2, code); code = mj_put_param_int(plist, "MicroWeave", µweave, 0, 1, code); code = mj_put_param_int(plist, "DotSize", &dotsize, 0, 1, code); code = mj_put_param_int(plist, "BitsPerPixel", &bpp, 1, 32, code); if ( code < 0 ) return code; mj->density = density; mj->cyan = cyan; mj->magenta = magenta; mj->yellow = yellow; mj->black = black; mj->dither = dither; mj->colorcomp = colorcomp; mj->direction = direction; mj->microweave = microweave; mj->dotsize = dotsize; if ( bpp != 0 ) { mj_set_bpp(pdev, bpp); gdev_prn_put_params(pdev, plist); if ( bpp != old_bpp && pdev->is_open ) return gs_closedevice(pdev); return 0; } else return gdev_prn_put_params(pdev, plist); } /* ------ Internal routines ------ */ private int mj_colour_print_page(P3(gx_device_printer *, FILE *, int)); private int mjc180_print_page(gx_device_printer * pdev, FILE * prn_stream) { return mj_colour_print_page(pdev, prn_stream, MJC180); } private int mjc360_print_page(gx_device_printer * pdev, FILE * prn_stream) { return mj_colour_print_page(pdev, prn_stream, MJC360); } private int mjc720_print_page(gx_device_printer * pdev, FILE * prn_stream) { return mj_colour_print_page(pdev, prn_stream, MJC720); } private int mj500c_print_page(gx_device_printer * pdev, FILE * prn_stream) { return mj_colour_print_page(pdev, prn_stream, MJ500C); } /* 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 SHIFT (I * I) #define MINVALUE 0 #define MAXVALUE ((256 << SHIFT) - 1) #define THRESHOLD (128 << SHIFT) #define FSditherI(inP, out, errP, Err, Bit, Offset)\ oldErr = Err;\ Err = (*errP + ((Err * 7) >> 4) + (*inP++ << SHIFT));\ if (Err > MAXVALUE) Err = MAXVALUE;\ else if (Err < MINVALUE) Err = MINVALUE;\ if (Err > THRESHOLD) {\ out |= Bit;\ Err -= MAXVALUE;\ }\ errP[Offset] += ((Err * 3) >> 4);\ *errP++ = ((Err * 5 + oldErr) >> 4); #define FSditherD(inP, out, errP, Err, Bit, Offset)\ oldErr = Err;\ Err = (*--errP + ((Err * 7) >> 4) + (*--inP << SHIFT));\ if (Err > MAXVALUE) Err = MAXVALUE;\ else if (Err < MINVALUE) Err = MINVALUE;\ if (Err > THRESHOLD) {\ out |= Bit;\ Err -= MAXVALUE;\ }\ errP[Offset] += ((Err * 3) >> 4);\ *errP = ((Err * 5 + oldErr) >> 4); #define MATRIX_I(inP, out, Bit, Offset)\ if ((*inP++ << 6) > Offset) {\ out |= Bit;\ } #define MATRIX_D(inP, out, Bit, Offset)\ if ((*--inP << 6) > Offset) {\ out |= Bit;\ } /* Here we rely on compiler optimisation to remove lines of the form * (if (1 >= 4) {...}, ie. the constant boolean expressions */ #define FSDline(scan, i, j, plane_size, cErr, mErr, yErr, kErr, cP, mP, yP, kP, n)\ {\ unsigned short *mat = matrix2 + (lnum & 127)*128;\ int x;\ if (scan == 0) { /* going_up */\ x = 0;\ for (i = 0; i < plane_size; i++) {\ byte c, y, m, k, bitmask;\ int oldErr;\ int val;\ bitmask = 0x80;\ for (c = m = y = k = j = 0; j < 8; j++) {\ val = *(mat + (x++ & 127));\ if (n >= 4)\ {\ MATRIX_I(dp, k, bitmask, val);\ }\ if (n >= 3)\ { MATRIX_I(dp, c, bitmask, val);\ MATRIX_I(dp, m, bitmask, val);\ }\ MATRIX_I(dp, y, bitmask, val);\ bitmask >>= 1;\ }\ if (n >= 4)\ *kP++ = k;\ if (n >= 3)\ { *cP++ = c;\ *mP++ = m;\ }\ *yP++ = y;\ }\ } else { /* going_down */\ x = plane_size*8;\ for (i = 0; i < plane_size; i++) {\ byte c, y, m, k, bitmask;\ int oldErr;\ int val;\ bitmask = 0x01;\ for (c = m = y = k = j = 0; j < 8; j++) {\ val = *(mat + (--x & 127));\ MATRIX_D(dp, y, bitmask, val);\ if (n >= 3)\ { MATRIX_D(dp, m, bitmask, val);\ MATRIX_D(dp, c, bitmask, val);\ }\ if (n >= 4)\ { MATRIX_D(dp, k, bitmask, val);\ }\ bitmask <<= 1;\ }\ *--yP = y;\ if (n >= 3)\ { *--mP = m;\ *--cP = c;\ }\ if (n >= 4)\ *--kP = k;\ }\ }\ } /* END MACROS FOR DITHERING */ /* Some convenient shorthand .. */ #define x_dpi (pdev->x_pixels_per_inch) #define y_dpi (pdev->y_pixels_per_inch) #define CONFIG_16BIT "\033*v6W\000\003\000\005\006\005" #define CONFIG_24BIT "\033*v6W\000\003\000\010\010\010" /* 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) /* * Miscellaneous functions for Canon BJC-600J printers in raster command mode. */ #define fputshort(n, f) fputc((n)%256,f);fputc((n)/256,f) #define row_bytes (img_rows / 8) #define row_words (row_bytes / sizeof(word)) #define min_rows (32) /* for optimization of text image printing */ private int mj_raster_cmd(int c_id, int in_size, byte* in, byte* buf2, gx_device_printer* pdev, FILE* prn_stream) { int band_size = 1; /* 1, 8, or 24 */ byte *out = buf2; int width = in_size; int count; byte* in_end = in + in_size; static char colour_number[] = "\004\001\002\000"; /* color ID for MJ700V2C */ byte *inp = in; byte *outp = out; register byte *p, *q; /* specifying a colour */ fputs("\033r",prn_stream); /* secape sequence to specify a color */ fputc(colour_number[c_id], prn_stream); /* end of specifying a colour */ /* Following codes for compression are borrowed from gdevescp.c */ for( p = inp, q = inp + 1 ; q < in_end ; ) { if( *p != *q ) { p += 2; q += 2; } else { /* ** Check behind us, just in case: */ if( p > inp && *p == *(p-1) ) p--; /* ** walk forward, looking for matches: */ for( q++ ; *q == *p && q < in_end ; q++ ) { if( (q-p) >= 128 ) { if( p > inp ) { count = p - inp; while( count > 128 ) { *outp++ = '\177'; memcpy(outp, inp, 128); /* data */ inp += 128; outp += 128; count -= 128; } *outp++ = (char) (count - 1); /* count */ memcpy(outp, inp, count); /* data */ outp += count; } *outp++ = '\201'; /* Repeat 128 times */ *outp++ = *p; p += 128; inp = p; } } if( (q - p) > 2 ) { /* output this sequence */ if( p > inp ) { count = p - inp; while( count > 128 ) { *outp++ = '\177'; memcpy(outp, inp, 128); /* data */ inp += 128; outp += 128; count -= 128; } *outp++ = (char) (count - 1); /* byte count */ memcpy(outp, inp, count); /* data */ outp += count; } count = q - p; *outp++ = (char) (256 - count + 1); *outp++ = *p; p += count; inp = p; } else /* add to non-repeating data list */ p = q; if( q < in_end ) q++; } } /* ** copy remaining part of line: */ if( inp < in_end ) { count = in_end - inp; /* ** If we've had a long run of varying data followed by a ** sequence of repeated data and then hit the end of line, ** it's possible to get data counts > 128. */ while( count > 128 ) { *outp++ = '\177'; memcpy(outp, inp, 128); /* data */ inp += 128; outp += 128; count -= 128; } *outp++ = (char) (count - 1); /* byte count */ memcpy(outp, inp, count); /* data */ outp += count; } /* ** Output data: */ fwrite("\033.\001", 1, 3, prn_stream); if(pdev->y_pixels_per_inch == 720) fputc('\005', prn_stream); else if(pdev->y_pixels_per_inch == 180) fputc('\024', prn_stream); else /* pdev->y_pixels_per_inch == 360 */ fputc('\012', prn_stream); if(pdev->x_pixels_per_inch == 720) fputc('\005', prn_stream); else if(pdev->x_pixels_per_inch == 180) fputc('\024', prn_stream); else /* pdev->x_pixels_per_inch == 360 */ fputc('\012', prn_stream); fputc(band_size, prn_stream); fputc((width << 3) & 0xff, prn_stream); fputc( width >> 5, prn_stream); fwrite(out, 1, (outp - out), prn_stream); fputc('\r', prn_stream); return 0; } private int mj_v_skip(int n, gx_device_printer *pdev, FILE *stream) { /* This is a kind of magic number. */ static const int max_y_step = (256 * 15 + 255); int l = n - max_y_step; for (; l > 0; l -= max_y_step) { /* move 256 * 15 + 255 dots at once*/ fwrite("\033(v\2\0\xff\x0f", sizeof(byte), 7, stream); } l += max_y_step; /* move to the end. */ { int n2 = l / 256; int n1 = l - n2 * 256; fwrite("\033(v\2\0", sizeof(byte) ,5 ,stream); fputc(n1, stream); fputc(n2, stream); fputc('\r', stream); } return 0; } /* NOZ */ /* private void bld_barrier( short **bar , int x ) */ private void bld_barrier( short **bar , int x ) { int i , j; short t; short *p; short *b; short *dat = barrier_dat + 1; p = *bar++ + x + 1; for ( i = 0 ; i < 11 ; i++ ) { t = *dat++; if (*p < t ) *p = t; p++; } for ( j = 0 ; j < 11 ; j++ ) { p = *bar++ + x; b = p; t = *dat++; if (*p < t ) *p = t; p++; for ( i = 0 ; i < 11 ; i++ ) { t = *dat++; if (*p < t ) *p = t; p++; if (*(--b) < t ) *b = t; } } } private void DifSubK( int d0 , short *a4 , short *a5 ) { /* +---+---+---+ | | X |1/2| +---+---+---+ |1/4|1/8|1/8| +---+---+---+ */ *a4++ = 0; d0 >>= 1; *a4 += d0; d0 >>= 1; *(a5-1) += d0; d0 >>= 1; *a5++ += d0; *a5 += d0; } /* a4.w , a5.w , */ private byte Xtal( byte bitmask , short d0 , int x , short **bar , short *b1 , short *b2 ) { short *a2; if (d0 != 0) d0 += *b1; a2 = *bar + x; /*fprintf(stderr , "[%02X]",*a2);*/ if (*a2 < d0) { d0 -= 16400; if (-4096 >= d0) { DifSubK( d0 , b1 , b2 ); bld_barrier( bar , x ); } else { DifSubK( d0 , b1 , b2 ); } return( bitmask ); } else { if (d0 > 56) d0 -= 56; DifSubK( d0 , b1 , b2 ); return( 0 ); } } private void xtal_plane( byte *dp , short *buf[] , byte *oP , short **bar , int plane_size , int xtalbuff_size ) { int i; int j; int x = 0; byte bitmask; byte out; short *p; short *b1 , *b2; b1 = buf[0]; b2 = buf[1]; /* for ( i = 0 ; i < 100 ; i++ ) { fprintf(stderr , "[%04X]",bar[0][i]); } fprintf(stderr , "\n"); */ for ( i = 0 ; i < plane_size ; i++ ) { bitmask = 0x80; out = 0; for ( j = 0 ; j < 8 ; j++ ) { out |= Xtal( bitmask , (short)(*dp) << 6 , x++ , bar , b1++ , b2++ ); dp += 4; bitmask >>= 1; } *oP++ = out; } /*fprintf(stderr , "\n");*/ p = buf[0]; /* fprintf(stderr , "\n"); */ buf[0] = buf[1]; buf[1] = p; p = bar[0]; for ( i = 0 ; i < plane_size*8 ; i++ ) *p++ = 0; /* memset( p, 0, (xtalbuff_size-16) * W);*/ p = bar[0]; for ( i = 0 ; i <= 14 ; i++ ) bar[i] = bar[i+1]; bar[15] = p; } /* Send the page to the printer. Compress each scan line. */ private int mj_colour_print_page(gx_device_printer * pdev, FILE * prn_stream, int ptype) { uint raster_width = gdev_prn_rasterwidth(pdev, 1); /* int line_size = gdev_prn_rasterwidth(pdev, 0); */ int line_size = gdev_prn_raster(pdev); int line_size_words = (line_size + W - 1) / W; int paper_size = gdev_mjc_paper_size((gx_device *)pdev); int num_comps = pdev->color_info.num_components; int bits_per_pixel = pdev->color_info.depth; int storage_bpp = bits_per_pixel; int expanded_bpp = bits_per_pixel; int plane_size, databuff_size; int combined_escapes = 1; int errbuff_size = 0; int outbuff_size = 0; int compression = 0; int scan = 0; int *errors[2]; char *cid_string; byte *data[4], *plane_data[4][4], *out_data; byte *out_row, *out_row_alt; word *storage; uint storage_size_words; uint mj_tmp_buf_size; byte* mj_tmp_buf; int xtalbuff_size; short *xtalbuff; short *Cbar[16]; short *Mbar[16]; short *Ybar[16]; short *Kbar[16]; short *Cbuf[2]; short *Mbuf[2]; short *Ybuf[2]; short *Kbuf[2]; /* Tricks and cheats ... */ switch (ptype) { case MJC180: case MJC360: case MJC720: case MJ500C: if (num_comps == 3) num_comps = 4; /* print CMYK */ break; } if (storage_bpp == 8 && num_comps >= 3) bits_per_pixel = expanded_bpp = 3; /* Only 3 bits of each byte used */ plane_size = calc_buffsize(line_size, storage_bpp); if (bits_per_pixel == 1) { /* Data printed direct from i/p */ databuff_size = 0; /* so no data buffer required, */ outbuff_size = plane_size * 4; /* but need separate output buffers */ } if (bits_per_pixel > 4) { /* Error buffer for FS dithering */ expanded_bpp = storage_bpp = /* 8, 24 or 32 bits */ num_comps * 8; errbuff_size = /* 4n extra values for line ends */ calc_buffsize((plane_size * expanded_bpp + num_comps * 4) * I, 1); } databuff_size = plane_size * storage_bpp; storage_size_words = ((plane_size + plane_size) * num_comps + databuff_size + errbuff_size + outbuff_size) / W; /* NOZ */ xtalbuff_size = plane_size*8 + 64; xtalbuff = (short *) gs_malloc( xtalbuff_size*(16*4+2*4) , W, "mj_colour_print_barrier"); memset(xtalbuff, 0, xtalbuff_size*(16*4+2*4) * W); { int i; short *p = xtalbuff + 16; for ( i = 0 ; i < 16 ; i++ ) { Cbar[i] = p; p += xtalbuff_size; } for ( i = 0 ; i < 16 ; i++ ) { Mbar[i] = p; p += xtalbuff_size; } for ( i = 0 ; i < 16 ; i++ ) { Ybar[i] = p; p += xtalbuff_size; } for ( i = 0 ; i < 16 ; i++ ) { Kbar[i] = p; p += xtalbuff_size; } Cbuf[0] = p; p += xtalbuff_size; Cbuf[1] = p; p += xtalbuff_size; Mbuf[0] = p; p += xtalbuff_size; Mbuf[1] = p; p += xtalbuff_size; Ybuf[0] = p; p += xtalbuff_size; Ybuf[1] = p; p += xtalbuff_size; Kbuf[0] = p; p += xtalbuff_size; Kbuf[1] = p; p += xtalbuff_size; } storage = (word *) gs_malloc(storage_size_words, W, "mj_colour_print_page"); /* prepare a temporary buffer for mj_raster_cmd */ mj_tmp_buf_size = plane_size; mj_tmp_buf = (byte *) gs_malloc(mj_tmp_buf_size, W ,"mj_raster_buffer"); #if 0 fprintf(stderr, "storage_size_words :%d\n", storage_size_words); fprintf(stderr, "mj_tmp_buf_size :%d\n", mj_tmp_buf_size); #endif /* * 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: * * errors: 2 (scan direction only) * data: 4 (scan direction and alternating buffers) * plane_data: 4 (scan direction and alternating buffers) */ if (storage == NULL || mj_tmp_buf == NULL) /* can't allocate working area */ return_error(gs_error_VMerror); else { int i, j; byte *p = out_data = out_row = (byte *)storage; data[0] = data[1] = data[2] = p; data[3] = p + databuff_size; out_row_alt = out_row + plane_size * 2; if (bits_per_pixel > 1) { p += databuff_size; } if (bits_per_pixel > 4) { errors[0] = (int *)p + num_comps * 2; errors[1] = errors[0] + databuff_size; p += errbuff_size; } for (i = 0; i < num_comps; i++) { plane_data[0][i] = plane_data[2][i] = p; p += plane_size; } for (i = 0; i < num_comps; i++) { plane_data[1][i] = p; plane_data[3][i] = p + plane_size; p += plane_size; } if (bits_per_pixel == 1) { out_data = out_row = p; /* size is outbuff_size * 4 */ out_row_alt = out_row + plane_size * 2; data[1] += databuff_size; /* coincides with plane_data pointers */ data[3] += databuff_size; } } /* Clear temp storage */ memset(storage, 0, storage_size_words * W); /* Initialize printer. */ { /** Reset printer, enter graphics mode: */ fwrite("\033@\033(G\001\000\001", sizeof(byte), 8, prn_stream); /** Micro-weave-Mode */ if ( mj->microweave ) { fwrite("\033(i\001\000\001", sizeof(byte), 6, prn_stream); } /** Dot-Size define */ if (mj->dotsize) { fwrite("\033(e\002\000\000\001", sizeof(byte), 7, prn_stream); } switch (mj->direction) { /* set the direction of the head */ case 1: fwrite("\033U\1", 1, 3, prn_stream); break; case 2: fwrite("\033U\0", 1, 3, prn_stream); break; } #if 0 #ifdef A4 /* ** After reset, the Stylus is set up for US letter paper. ** We need to set the page size appropriately for A4 paper. ** For some bizarre reason the ESC/P2 language wants the bottom ** margin measured from the *top* of the page: */ fwrite("\033(U\001\0\n\033(C\002\0t\020\033(c\004\0\0\0t\020", 1, 22, prn_stream); #endif #endif /* ** Set the line spacing to match the band height: */ if( pdev->y_pixels_per_inch >= 720 ) { fwrite("\033(U\001\0\005\033+\001", sizeof(byte), 9, prn_stream); } else if( pdev->y_pixels_per_inch >= 360 ) fwrite("\033(U\001\0\012\033+\001", sizeof(byte), 9, prn_stream); else /* 180 dpi */ fwrite("\033(U\001\0\024\033+\002", sizeof(byte), 9, prn_stream); /* set the length of the page */ fwrite("\033(C\2\0", sizeof(byte), 5, prn_stream); fputc(((pdev->height) % 256), prn_stream); fputc(((pdev->height) / 256), prn_stream); } #define MOFFSET (pdev->t_margin - MJ700V2C_PRINT_LIMIT) /* Print position */ switch (ptype) { case MJC180: case MJC360: case MJC720: case MJ500C: /* Currently, I don't know what to do. */ { int MJ_MARGIN_MM = 55; uint top_skip = ( MJ_MARGIN_MM * pdev->y_pixels_per_inch ) / 254; top_skip = (top_skip ^ (-1)) & 65536; fwrite("\033(V\2\0\0\0",sizeof(byte), 7, prn_stream); fwrite("\033(v\2\0\0\xff",sizeof(byte), 7, prn_stream); } break; } /* Send each scan line in turn */ { long int lend = pdev->height - (dev_t_margin_points(pdev) + dev_b_margin_points(pdev)); int cErr, mErr, yErr, kErr; int this_pass, i; long int lnum; int num_blank_lines = 0; int start_rows = (num_comps == 1) ? HEAD_ROWS_MONO - 1 : HEAD_ROWS_COLOUR - 1; word rmask = ~(word) 0 << ((-pdev->width * storage_bpp) & (W * 8 - 1)); cErr = mErr = yErr = kErr = 0; if (bits_per_pixel > 4) { /* Randomly seed initial error buffer */ int *ep = errors[0]; for (i = 0; i < databuff_size; i++) { *ep++ = (rand() % (MAXVALUE / 2)) - MAXVALUE / 4; } } this_pass = start_rows; lnum = 0; /* for Debug */ for (; lnum < lend; lnum++) { word *data_words = (word *)data[scan]; register word *end_data = data_words + line_size_words; gx_color_index *p_data; gdev_prn_copy_scan_lines(pdev, lnum, data[scan], 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 (end_data == data_words) { /* Blank line */ num_blank_lines++; continue; /* skip to for (lnum) loop */ } /* Skip blank lines if any */ if (num_blank_lines > 0 ) { mj_v_skip(num_blank_lines, pdev, prn_stream); memset(plane_data[1 - scan][0], 0, plane_size * num_comps); num_blank_lines = 0; this_pass = start_rows; } /* Correct color depth. */ if (mj->density != 1024 || mj->yellow != 1024 || mj->cyan != 1024 || mj->magenta != 1024 || mj->black != 1024 ) { for (p_data = (gx_color_index*) data_words; p_data < end_data; p_data++) { *p_data = mjc_correct_color(pdev, *p_data); } } { /* Printing non-blank lines */ register byte *kP = plane_data[scan + 2][3]; register byte *cP = plane_data[scan + 2][2]; register byte *mP = plane_data[scan + 2][1]; register byte *yP = plane_data[scan + 2][0]; register byte *dp = data[scan + 2]; register int *ep = errors[scan]; int zero_row_count; int i, j; byte *odp; if (this_pass) this_pass--; else this_pass = start_rows; if (expanded_bpp > bits_per_pixel) /* Expand line if required */ expand_line(data_words, line_size, bits_per_pixel, expanded_bpp); /* In colour modes, we have some bit-shuffling to do before * we can print the data; in FS mode we also have the * dithering to take care of. */ switch (expanded_bpp) { /* Can be 1, 3, 8, 24 or 32 */ case 3: /* Transpose the data to get pixel planes. */ for (i = 0, odp = plane_data[scan][0]; i < databuff_size; i += 8, odp++) { /* The following is for 16-bit * machines */ #define spread3(c)\ { 0, c, c*0x100, c*0x101, c*0x10000L, c*0x10001L, c*0x10100L, c*0x10101L } static word spr40[8] = spread3(0x40); static word spr08[8] = spread3(8); static word spr02[8] = spread3(2); register byte *dp = data[scan] + i; register word pword = (spr40[dp[0]] << 1) + (spr40[dp[1]]) + (spr40[dp[2]] >> 1) + (spr08[dp[3]] << 1) + (spr08[dp[4]]) + (spr08[dp[5]] >> 1) + (spr02[dp[6]]) + (spr02[dp[7]] >> 1); odp[0] = (byte) (pword >> 16); odp[plane_size] = (byte) (pword >> 8); odp[plane_size * 2] = (byte) (pword); } break; case 8: FSDline(scan, i, j, plane_size, cErr, mErr, yErr, kErr, cP, mP, yP, kP, 1); break; case 24: FSDline(scan, i, j, plane_size, cErr, mErr, yErr, kErr, cP, mP, yP, kP, 3); break; case 32: if (scan == 1) { dp -= plane_size*8*4; cP -= plane_size; mP -= plane_size; yP -= plane_size; kP -= plane_size; } /* { byte *p = dp; int i; for ( i = 0 ; i < plane_size ; i++ ) { fprintf ( stderr , "[%02X%02X%02X%02X]" , p[0] , p[1] , p[2] , p[3] ); p += 4; } fprintf( stderr , "\n"); } */ /* FSDline(scan, i, j, plane_size, cErr, mErr, yErr, kErr, cP, mP, yP, kP, 4); */ /* NOZ */ xtal_plane( dp++ , Kbuf , kP , Kbar , plane_size , xtalbuff_size ); xtal_plane( dp++ , Cbuf , cP , Cbar , plane_size , xtalbuff_size ); xtal_plane( dp++ , Mbuf , mP , Mbar , plane_size , xtalbuff_size ); xtal_plane( dp++ , Ybuf , yP , Ybar , plane_size , xtalbuff_size ); break; } /* switch(expanded_bpp) */ /* Make sure all black is in the k plane */ if (num_comps == 4 ) { if (mj->colorcomp > 3 ) { register word *kp = (word *)plane_data[scan][3]; register word *cp = (word *)plane_data[scan][2]; register word *mp = (word *)plane_data[scan][1]; register word *yp = (word *)plane_data[scan][0]; if (bits_per_pixel > 4) { /* This has been done as 4 planes */ #if 0 for (i = 0; i < plane_size / W; i++) { word bits = ~*kp++; *cp++ &= bits; *mp++ &= bits; *yp++ &= bits; } #endif } else { /* This has really been done as 3 planes */ for (i = 0; i < plane_size / W; i++) { word bits = *cp & *mp & *yp; *kp++ = bits; bits = ~bits; *cp++ &= bits; *mp++ &= bits; *yp++ &= bits; } } } else if (mj->colorcomp == 3 ) { register word *kp = (word *)plane_data[scan][3]; register word *cp = (word *)plane_data[scan][2]; register word *mp = (word *)plane_data[scan][1]; register word *yp = (word *)plane_data[scan][0]; if (bits_per_pixel > 4) { /* This has been done as 4 planes */ for (i = 0; i < plane_size / W; i++) { word bits = *kp++; /* kp will not be used when printing */ *cp++ |= bits; *mp++ |= bits; *yp++ |= bits; } } else { /* This has really been done as 3 planes */ } } } /* Transfer raster graphics * in the order (K), C, M, Y. */ switch (mj->colorcomp) { case 1: zero_row_count = 0; out_data = (byte*) plane_data[scan][0]; /* 3 for balck */ mj_raster_cmd(3, plane_size, out_data, mj_tmp_buf, pdev, prn_stream); break; case 3: for (zero_row_count = 0, i = 3 - 1; i >= 0; i--) { out_data = (byte*) plane_data[scan][i]; mj_raster_cmd(i, plane_size, out_data, mj_tmp_buf, pdev, prn_stream); } break; default: for (zero_row_count = 0, i = num_comps - 1; i >= 0; i--) { int output_plane = 1; out_data = (byte*) plane_data[scan][i]; mj_raster_cmd(i, plane_size, out_data, mj_tmp_buf, pdev, prn_stream); } break; } /* Transfer Raster Graphics ... */ { if ( pdev->y_pixels_per_inch > 360 ) { fwrite("\033(v\2\0\1\0",sizeof(byte),7, prn_stream); } else { fputc('\n', prn_stream); } } scan = 1 - scan; /* toggle scan direction */ } /* Printing non-blank lines */ } /* for lnum ... */ } /* send each scan line in turn */ /* end raster graphics & reset printer */ /* eject page */ { fputs("\f\033@", prn_stream); fflush(prn_stream); } /* free temporary storage */ gs_free((char *) storage, storage_size_words, W, "mj_colour_print_page"); gs_free((char *) mj_tmp_buf, mj_tmp_buf_size, W, "mj_raster_buffer"); gs_free((char *) xtalbuff , xtalbuff_size*(16*4+2*4) , W, "mj_colour_print_barrier"); return 0; } void mj_color_correct(gx_color_value *Rptr ,gx_color_value *Gptr , gx_color_value *Bptr ) /* R,G,B : 0`255 */ { short R,G,B; /* R,G,B : 0`255 */ short C,M,Y; /* C,M,Y : 0`1023 */ short H,D,Wa; /* ese-HSV */ long S; /* HSV */ R = *Rptr; G = *Gptr; B = *Bptr; if (R==G) { if (G==B) { /* R=G=B */ C=M=Y=1023-v_tbl[R]; *Rptr = C; *Gptr = M; *Bptr = Y; return; } else if (G>B) { /* R=G>B */ D = G-B; Wa = R; H = 256; } else { /* B>R=G */ D = G-B; Wa = R; H = 1024; } } if (R>G) { if (G>=B) { /* R>G>B */ Wa=R; D=R-B; H=(G-B)*256/D; } else if (R>B) { /* R>B>G */ Wa=R; D=R-G; H=1536-(B-G)*256/D; } else { /* B>R>G */ Wa=B; D=B-G; H=1024+(R-G)*256/D; } } else { if (R>B) { /* G>R>B */ Wa=G; D=G-B; H=512-(R-B)*256/D; } else if (G>B) { /* G>B>R */ Wa=G; D=G-R; H=512+(B-R)*256/D; } else { /* B>G>R */ Wa=B; D=B-R; H=1024-(G-R)*256/D; } } if(Wa!=0){ if(Wa==D){ Wa=v_tbl[Wa]; D=Wa/4; } else { S=((long)D<<16)/Wa; Wa=v_tbl[Wa]; D= ( ((long)S*Wa)>>18 ); } } Wa=1023-Wa; C=(HtoCMY[H*3 ])*D/256+Wa; M=(HtoCMY[H*3+1])*D/256+Wa; Y=(HtoCMY[H*3+2])*D/256+Wa; if (C<0) C=0; if (M<0) M=0; if (Y<0) Y=0; if(H>256 && H<1024){ /* green correct */ short work; work=(((long)grnsep[M]*(long)grnsep2[H-256])>>16); C+=work; Y+=work+work; M-=work+work; if(C>1023) C=1023; if(Y>1023) Y=1023; } *Rptr = C; *Gptr = M; *Bptr = Y; } /* * Map a r-g-b color to a color index. * We complement the colours, since we're using cmy anyway, and * because the buffering routines expect white to be zero. * Includes colour balancing, following HP recommendations, to try * and correct the greenish cast resulting from an equal mix of the * c, m, y, inks by reducing the cyan component to give a truer black. */ private gx_color_index gdev_mjc_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 ((((word)c * red_weight + (word)m * green_weight + (word)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) + ((word)gx_color_value_to_byte(c) << 16)); case 32: { gx_color_value k; c = gx_color_value_to_byte(r); m = gx_color_value_to_byte(g); y = gx_color_value_to_byte(b); mj_color_correct( &c , &m , &y ); c = esp_dat_c[c]; m = esp_dat_m[m]; y = esp_dat_y[y]; k = c <= m ? (c <= y ? c : y) : (m <= y ? m : y); k = black_sep[ k >> 4 ] >> 6; c >>= 6; m >>= 6; y >>= 6; return ( (y - k) + ((m - k) << 8) + ((word)(c - k) << 16) + ((word)(k) << 24) ); } } } return (gx_color_index)0; /* This never happens */ } /* Map a color index to a r-g-b color. */ private int gdev_mjc_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; } /* * Convert and expand scanlines: * * (a) 16 -> 24 bit (1-stage) * (b) 16 -> 32 bit (2-stage) * or (c) 24 -> 32 bit (1-stage) */ private void expand_line(word *line, int linesize, int bpp, int ebpp) { int endline = linesize; byte *start = (byte *)line; register byte *in, *out; if (bpp == 16) /* 16 to 24 (cmy) if required */ { register byte b0, b1; endline = ((endline + 1) / 2); in = start + endline * 2; out = start + (endline *= 3); while (in > start) { b0 = *--in; b1 = *--in; *--out = (b0 << 3) + ((b0 >> 2) & 0x7); *--out = (b1 << 5) + ((b0 >> 3) & 0x1c) + ((b1 >> 1) & 0x3); *--out = (b1 & 0xf8) + (b1 >> 5); } } if (ebpp == 32) /* 24 (cmy) to 32 (cmyk) if required */ { register byte c, m, y, k; endline = ((endline + 2) / 3); in = start + endline * 3; out = start + endline * 4; while (in > start) { y = *--in; m = *--in; c = *--in; k = c < m ? (c < y ? c : y) : (m < y ? m : y); *--out = y - k; *--out = m - k; *--out = c - k; *--out = k; } } } private int mj_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 void mj_set_bpp(gx_device *pdev, int bits_per_pixel) { gx_device_color_info *ci = &pdev->color_info; /* Only valid bits-per-pixel are 1, 3, 8, 16, 24, 32 */ int bpp = bits_per_pixel < 3 ? 1 : bits_per_pixel < 8 ? 3 : (bits_per_pixel >> 3) << 3; ci->num_components = ((bpp == 1) || (bpp == 8) ? 1 : 3); ci->depth = ((bpp > 1) && (bpp < 8) ? 8 : bpp); ci->max_gray = (bpp >= 8 ? 255 : 1); ci->max_color = (bpp >= 8 ? 255 : bpp > 1 ? 1 : 0); ci->dither_grays = (bpp >= 8 ? 5 : 2); ci->dither_colors = (bpp >= 8 ? 5 : bpp > 1 ? 2 : 0); } /* This returns either the number of pixels in a scan line, or the number * of bytes required to store the line, both clipped to the page margins */ private uint gdev_prn_rasterwidth(const gx_device_printer *pdev, int pixelcount) { word raster_width = pdev->width - (pdev->HWMargins[0] + pdev->HWMargins[2]); return (pixelcount ? (uint)raster_width : (uint)((raster_width * pdev->color_info.depth + 7) >> 3)); } private gx_color_index mjc_correct_color(gx_device_printer *pdev, gx_color_index ci) { gx_color_index c, m, y, k, co; const uint cmask = 0xff; uint dn = mj->density; uint mjy = mj->yellow; uint mjc = mj->cyan; uint mjm = mj->magenta; uint mjb = mj->black; switch (pdev->color_info.depth) { case 24: y = ((ci & cmask) * (mjy * dn)) >> 20; y = (y < cmask) ? y : cmask; m = (((ci >> 8) & cmask) * (mjm * dn)) >> 20; m = (m < cmask) ? m : cmask; c = (((ci >> 16) & cmask) * (mjc * dn)) >> 20; c = (c < cmask) ? c : cmask; return ( y + (m << 8) + (c << 16)); break; case 32: y = ((ci & cmask) * mjy * dn) >> 20; y = (y < cmask) ? y : cmask; m = (((ci >> 8) & cmask) * mjm * dn) >> 20; m = (m < cmask) ? m : cmask; c = (((ci >> 16) & cmask) * mjc * dn) >> 20; c = (c < cmask) ? c : cmask; k = (((ci >> 24) & cmask) * mjb * dn) >> 20; k = (k < cmask) ? k : cmask; co = (y + (m << 8) + (c << 16) + (k << 24)); /* fprintf(stderr,"%d,%d:%d,%d,%d,%d\n", ci,co, y, m, c, k); */ return co; /* return (gx_color_value_to_byte(y) + (gx_color_value_to_byte(m) << 8) + ((word)gx_color_value_to_byte(c) << 16) + ((word)gx_color_value_to_byte(k) << 24)); */ break; } return ci; }