/* Copyright (C) 1995, 1996 artofcode LLC. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA, 02111-1307. */ /*$Id: gdevstc.c,v 1.2.6.1.2.1 2003/01/17 00:49:01 giles Exp $*/ /* Epson Stylus-Color Printer-Driver */ /*** *** This file was "copied" from gdevcdj.c (ghostscript-3.12), which was *** contributed by: *** George Cameron - g.cameron@biomed.abdn.ac.ukis *** Koert Zeilstra - koert@zen.cais.com *** Eckhard Rueggeberg - eckhard@ts.go.dlr.de *** *** Some of the ESC/P2-code was drawn from gdevescp.c, contributed by *** Richard Brown - rab@eos.ncsu.edu *** *** The POSIX-Interrupt-Code is from (Compile-Time-Option -DSTC_SIGNAL) *** Frederic Loyer - loyer@ensta.fr *** *** And several improvements are based on discussions with *** Brian Converse - BCONVERSE@ids.net *** Bill Davidson - bdavidson@ra.isisnet.com *** Gero Guenther - gero@cs.tu-berlin.de *** Jason Patterson - jason@reflections.com.au *** ? Rueschstroer - rue@ibe.med.uni-muenchen.de *** Steven Singer - S.Singer@ph.surrey.ac.uk *** *** And the remaining little rest, mainly the bugs, were written by me: *** Gunther Hess - gunther@elmos.de *** *** P.S.: there is some documentation, see devices.doc *** *** Revision-History: *** 16-DEC-1994 1.1 - initial Version (GS-Dithering & Plain-Write) ... *** 30-JAN-1995 1.11 - FS-Improvements, u/sWeave, 1/4/24-Bits *** 5-MAR-1995 1.12 - L. Peter Deutsch - updated put_params routine (first distributed version with gs3.33) *** 26-APR-1995 1.13 - merged Peters fixes with algorithmic changes: Changed 24Bit-Mode, added 32Bit-Mode (moves colors) [Arrgh: much better than 1.12, but patch was lost] *** 5-JUN-1995 1.14 - Added Color-Correction & Transfer-Curves (Several Beta-Testers, but not distributed) ... *** 24-JUL-1995 1.16 - Made dithering-Algorithms external-functions. (Mailed for Beta-Distribution) *** 10-AUG-1995 1.17 - Several Bug-Fixes and some new features: CMYK10-Coding added Readonly Parameters added "Algorithms", "BitsPerComponent", "Version" Parameters Flag0-4, Model, OutputCode (mailed for distribution) *** 14-SEP-1995 1.18 Fixes Bugs with Borland C (gs3.47) *** 23-SEP-1995 1.19 - reorganized printcode + bug-fixing *** 24-SEP-1995 1.20 - Little Cleanup for the release *** 25-SEP-1995 1.21 - Readonly-Parameters added to put_params. *** 31-Dec-1995 1.22 - Sanitary Engineering on the code *** 16-Jan-1996 1.23 - Added String escp_Release *** 8-May-1996 1.90 - Reintroduced Deltarow & Fixed MEMORY-BUG! ***/ #include "gdevstc.h" #ifdef STC_SIGNAL # include #endif /* STC_SIGNAL */ /*** *** Mode-Table - the various algorithms *** (The intention is, that this source can live alone) ***/ private stc_proc_dither(stc_gscmyk); /* resides in this file */ private stc_proc_dither(stc_hscmyk); /* resides in this file */ #include /* for rand, used in stc_hscmyk */ private const stc_dither_t stc_dither[] = { {"gscmyk", stc_gscmyk, DeviceCMYK|STC_BYTE|STC_DIRECT,0,{0.0,1.0}}, {"hscmyk", stc_hscmyk, DeviceCMYK|STC_LONG|STC_CMYK10|STC_DIRECT|1*STC_SCAN,1+2*4, {0.0, 1023.0}}, STC_MODI { NULL , NULL , 0, 0,{0.0,0.0}} }; /*** *** forward-declarations of routines ***/ /* Primary Device functions * (I've the idea to rename the driver to stc) */ private dev_proc_print_page(stc_print_page); private dev_proc_open_device(stc_open); private dev_proc_close_device(stc_close); private dev_proc_get_params(stc_get_params); private dev_proc_put_params(stc_put_params); /* * Color-Mapping-functions. */ /* routines for monochrome monochrome modi */ private dev_proc_map_rgb_color(stc_map_gray_color); private dev_proc_map_color_rgb(stc_map_color_gray); /* routines for RGB-Modi */ private dev_proc_map_rgb_color(stc_map_rgb_color); private dev_proc_map_color_rgb(stc_map_color_rgb); /* routines for general CMYK-Modi */ private dev_proc_map_cmyk_color(stc_map_cmyk_color); private dev_proc_map_color_rgb(stc_map_color_cmyk); /* routines for 10Bit/Component CMYK */ private dev_proc_map_cmyk_color(stc_map_cmyk10_color); private dev_proc_map_color_rgb(stc_map_color_cmyk10); /*** *** Table of Device-Procedures ***/ private gx_device_procs stcolor_procs = { stc_open, gx_default_get_initial_matrix, gx_default_sync_output, gdev_prn_output_page, stc_close, NULL, stc_map_color_cmyk, NULL, /* fill_rectangle */ NULL, /* tile_rectangle */ NULL, /* copy_mono */ NULL, /* copy_color */ NULL, /* draw_line */ gx_default_get_bits, stc_get_params, stc_put_params, stc_map_cmyk_color }; /*** *** A local dummy-array for extvals ***/ private float defext[] = { 0.0, 1.0 }; /*** *** Main device-control structure ***/ stcolor_device far_data gs_stcolor_device = { prn_device_body(stcolor_device, stcolor_procs, "stcolor", DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, X_DPI, Y_DPI, STC_L_MARGIN,STC_B_MARGIN,STC_R_MARGIN,STC_T_MARGIN, 4, 4, 1, 1, 2, 2, /* default: cmyk-direct */ stc_print_page), {STCNWEAVE, /* stcflags: noWeave/bidirectional */ 1, /* stcbits: matches the default */ stc_dither, /* stcdither: first algorithm */ NULL, /* stcam: NULL -> not used */ { NULL, NULL, NULL, NULL}, /* extcode: none defined yet */ { 0, 0, 0, 0}, /* sizcode: 0, since no extcode yet */ { NULL, NULL, NULL, NULL}, /* stccode: computed by put_params */ {defext,defext,defext,defext},/* extvals: default */ { 2, 2, 2, 2}, /* sizvals: default countof(defext) */ { NULL, NULL, NULL, NULL}, /* stcvals: computed by put_params */ { 0, 0, 0}, /* white-run */ { 0, 0, 0}, /* white-end */ {NULL,0,false}, /* algorithm-table */ {NULL,0,false}, /* initialization-String (BOP) */ {NULL,0,false}, /* release-String (EOP) */ 0,0,0,0, /* New escp-stuff */ 1} /* itemsize used by algorithm */ }; /*** *** Test for white scan-lines ***/ private bool stc_iswhite(P3(stcolor_device *, int, byte *)); /*** *** Functions used for conversion inside the print-loop ***/ #define stc_proc_iconvert(Name) \ byte * Name(P4(stcolor_device *sd,byte *ext_data,int prt_pixels,byte *alg_line)) private stc_proc_iconvert(stc_any_depth); /* general input-conversion */ private stc_proc_iconvert(stc_rgb24_long); /* 24Bit RGB -> long's */ private stc_proc_iconvert(stc_cmyk32_long); /* 32Bit CMYK -> long's */ private stc_proc_iconvert(stc_any_direct); /* use ext_data as input */ private stc_proc_iconvert(stc_cmyk10_byte); /* CMYK10->vals-> any type */ private stc_proc_iconvert(stc_cmyk10_long); /* CMYK10->vals-> any type */ private stc_proc_iconvert(stc_cmyk10_float); /* CMYK10->vals-> any type */ private stc_proc_iconvert(stc_cmyk10_dbyte); /* CMYK10 direct bytes */ private stc_proc_iconvert(stc_cmyk10_dlong); /* CMYK10 direct longs */ /*** *** Print-functions ***/ private void stc_print_weave(P2(stcolor_device *sd,FILE *prn_stream)); private void stc_print_bands(P2(stcolor_device *sd,FILE *prn_stream)); private void stc_print_delta(P2(stcolor_device *sd,FILE *prn_stream)); private int stc_print_setup(P1(stcolor_device *sd)); /*** *** compute the ESC/P2 specific values ***/ private int stc_print_setup(stcolor_device *sd) { /* * Compute the resolution-parameters */ sd->stc.escp_u = 3600.0 / sd->y_pixels_per_inch; /* y-units */ sd->stc.escp_h = 3600.0 / sd->x_pixels_per_inch; /* x-units */ sd->stc.escp_v = sd->stc.flags & (STCUWEAVE | STCNWEAVE) ? sd->stc.escp_u : 40; /* * Initialize color */ sd->stc.escp_c = 0; /* preselect-black */ /* * Band-Width */ if((sd->stc.flags & STCBAND) == 0) { if(sd->stc.escp_v != sd->stc.escp_u) sd->stc.escp_m = 15; else if(STCSTCII == (sd->stc.flags & STCMODEL)) sd->stc.escp_m = 1; else if( sd->stc.flags & STCUWEAVE) sd->stc.escp_m = 1; else if((sd->stc.escp_v == sd->stc.escp_u) && (sd->stc.escp_u == 5)) sd->stc.escp_m = 1; else sd->stc.escp_m = 1; } /* * Page-Dimensions */ if((sd->stc.flags & STCWIDTH ) == 0) sd->stc.escp_width = sd->width - (dev_l_margin(sd)+dev_r_margin(sd))*sd->x_pixels_per_inch; if((sd->stc.flags & STCHEIGHT) == 0) sd->stc.escp_height = sd->height; if((sd->stc.flags & STCTOP) == 0) sd->stc.escp_top = dev_t_margin(sd)*sd->y_pixels_per_inch; if((sd->stc.flags & STCBOTTOM) == 0) sd->stc.escp_bottom = sd->height - dev_b_margin(sd)*sd->y_pixels_per_inch; if((sd->stc.flags & STCINIT) == 0) { /* No Initialization-String defined */ int need = 8 /* Reset, Graphics-Mode 1 */ + 6 /* MicroWeave */ + 6 /* Select Units */ + 7 /* Set Page-Length */ + 9 /* Set Margins */ + 3; /* Select Unidirectionality */ byte *bp = (byte *) (sd->stc.escp_init.data); if(need != sd->stc.escp_init.size) { /* Reallocate */ if(NULL != (bp = gs_malloc(need,1,"stcolor/init"))) { /* Replace */ if(0 != sd->stc.escp_init.size) gs_free((byte *)sd->stc.escp_init.data,sd->stc.escp_init.size,1, "stcolor/init"); sd->stc.escp_init.data = bp; sd->stc.escp_init.size = need; sd->stc.escp_init.persistent = false; } else { /* Replace */ return_error(gs_error_VMerror); } } if(need != 39) return_error(gs_error_unregistered); memcpy(bp, /* 1 1 11 1 11 1 1 1 2 22 2 2 22 2 22 3 3 3333 3 33*/ /* 0 1 2 34 5 6 7 8 90 1 23 4 56 7 8 9 0 12 3 4 56 7 89 0 1 2345 6 78*/ "\033@\033(G\001\0\1\033(i\1\0w\033(U\001\000u\033(C\2\000hh\033(c\4\000ttbb\033U", need); if((sd->stc.flags & STCUWEAVE) != 0) bp[13] = '\1'; else bp[13] = '\0'; bp[19] = sd->stc.escp_u; bp[25] = sd->stc.escp_height & 0xff; bp[26] = (sd->stc.escp_height>>8) & 0xff; bp[32] = sd->stc.escp_top & 0xff; bp[33] = (sd->stc.escp_top>>8) & 0xff; bp[34] = sd->stc.escp_bottom & 0xff; bp[35] = (sd->stc.escp_bottom>>8) & 0xff; if(sd->stc.flags & STCUNIDIR) bp[38] = 1; else bp[38] = 0; } /* No Initialization-String defined */ if((sd->stc.flags & STCRELEASE) == 0) { /* No Release-String defined */ int need = 3; /* ESC @ \f */ byte *bp = (byte *) (sd->stc.escp_release.data); if(need != sd->stc.escp_release.size) { /* Reallocate */ if(NULL != (bp = gs_malloc(need,1,"stcolor/release"))) { /* Replace */ if(0 != sd->stc.escp_release.size) gs_free((byte *)sd->stc.escp_release.data,sd->stc.escp_release.size,1, "stcolor/release"); sd->stc.escp_release.data = bp; sd->stc.escp_release.size = need; sd->stc.escp_release.persistent = false; } else { /* Replace */ return_error(gs_error_VMerror); } } if(need != 3) return_error(gs_error_unregistered); memcpy(bp,"\033@\f",need); } /* No Release-String defined */ return 0; } /*** *** stc_print_page: here we go to do the nasty work ***/ private int stc_print_page(gx_device_printer * pdev, FILE * prn_stream) { stcolor_device *sd = (stcolor_device *) pdev; long flags = sd == NULL ? 0 : sd->stc.flags; int npass; /* # of print-passes (softweave) */ int ext_size; /* size of a ghostscript-scanline */ byte *ext_line; /* dyn: for this scanline */ int alg_size; /* size of a scanline for the dithering-algorithm */ byte *alg_line; /* dyn: 1 scanline for the dithering-algorithm */ int buf_size; /* size of the private-buffer for dither-function */ byte *buf; /* dyn: the private buffer */ int prt_pixels; /* Number of pixels printed */ byte *col_line; /* A Line with a byte per pixel */ #define OK4GO ((flags & STCOK4GO) != 0) #define SORRY ( flags &= ~STCOK4GO) if(0 > (npass = stc_print_setup(sd))) return_error(npass); npass = sd->stc.escp_v / sd->stc.escp_u; /*** *** Allocate dynamic memory ***/ ext_size = gdev_prn_raster(sd); ext_line = gs_malloc(ext_size,1,"stc_print_page/ext_line"); if(ext_line == NULL) SORRY; prt_pixels = sd->stc.escp_width; sd->stc.prt_size = (prt_pixels+7)/8; prt_pixels = sd->stc.prt_size * 8; sd->stc.prt_scans = sd->height - (dev_t_margin(sd)+dev_b_margin(sd))*sd->y_pixels_per_inch; col_line = gs_malloc(prt_pixels,1,"stc_print_page/col_line"); if(col_line == NULL) SORRY; alg_size = prt_pixels; alg_size *= sd->color_info.num_components; if((sd->stc.dither->flags & STC_DIRECT) || ((sd->stc.bits == 8) && (sd->stc.alg_item == 1))) { alg_line = NULL; } else { alg_line = gs_malloc(alg_size,sd->stc.alg_item,"stc_print_page/alg_line"); if(alg_line == NULL) SORRY; } buf_size = sd->stc.dither->bufadd + alg_size*(sd->stc.dither->flags/STC_SCAN); if(buf_size > 0) { buf = gs_malloc(buf_size,sd->stc.alg_item,"stc_print_page/buf"); if(buf == NULL) SORRY; } else { buf = NULL; } /* * compute the number of printer-buffers */ for(sd->stc.prt_buf = 16; sd->stc.prt_buf < (sd->stc.escp_m * npass); sd->stc.prt_buf <<= 1); if(sd->color_info.num_components > 1) sd->stc.prt_buf *= 4; sd->stc.prt_width = gs_malloc(sd->stc.prt_buf,sizeof(int), "stc_print_page/prt_width"); if(sd->stc.prt_width == NULL) SORRY; sd->stc.prt_data = gs_malloc(sd->stc.prt_buf,sizeof(byte *), "stc_print_page/prt_data"); if(sd->stc.prt_data == NULL) { SORRY; } else { int i; for(i = 0; i < sd->stc.prt_buf; ++i) { sd->stc.prt_data[i] = gs_malloc(sd->stc.prt_size,1, "stc_print_page/prt"); if(sd->stc.prt_data[i] == NULL) SORRY; } } sd->stc.seed_size = (sd->stc.prt_size + 2*sizeof(int) - 1)/sizeof(int); { int i; for(i = 0; i < sd->color_info.num_components; ++i) { if((flags & STCCOMP) == STCDELTA) { sd->stc.seed_row[i] = gs_malloc(sd->stc.seed_size,sizeof(int), "stc_print_page/seed_row"); if(sd->stc.seed_row[i] == NULL) SORRY; else memset(sd->stc.seed_row[i],0,sd->stc.seed_size*sizeof(int)); } else { sd->stc.seed_row[i] = NULL; } } while(i < countof(sd->stc.seed_row)) sd->stc.seed_row[i++] = NULL; } switch(flags & STCCOMP) { case STCPLAIN: sd->stc.escp_size = 64 + sd->stc.prt_size; break; case STCDELTA: sd->stc.escp_size = 64 + 2 * sd->stc.prt_size; break; default: sd->stc.escp_size = 64 + sd->stc.prt_size + (sd->stc.prt_size + 127)/128; break; } sd->stc.escp_data = gs_malloc(sd->stc.escp_size,1, "stc_print_page/escp_data"); if(sd->stc.escp_data == NULL) SORRY; /* * If we're still ok, we can print something */ if(OK4GO) { int ncolor; int buf_i; stc_proc_iconvert((*iconvert)) = stc_any_depth; /* * initialize col_line */ if(sd->color_info.num_components == 3) { memset(col_line,RED|GREEN|BLUE,prt_pixels); } else { memset(col_line,0, prt_pixels); } /* * select proper conversion for input to algorithm */ if( (sd->stc.dither->flags & STC_DIRECT ) || ((sd->stc.bits == 8) && (sd->stc.alg_item == 1))) iconvert = stc_any_direct; else if((sd->color_info.num_components == 3) && (sd->color_info.depth == 24) && (sizeof(long) == sd->stc.alg_item)) iconvert = stc_rgb24_long; else if(sd->stc.flags & STCCMYK10) { if( ((sd->stc.dither->flags & STC_TYPE) == STC_BYTE) && ( sd->stc.dither->minmax[0] == 0.0 )) iconvert = stc_cmyk10_dbyte; else if ((sd->stc.dither->flags & STC_TYPE) == STC_BYTE) iconvert = stc_cmyk10_byte; else if(((sd->stc.dither->flags & STC_TYPE) == STC_LONG) && ( sd->stc.dither->minmax[0] == 0.0 ) && ( sd->stc.dither->minmax[1] <= 1023.0 )) iconvert = stc_cmyk10_dlong; else if( (sd->stc.dither->flags & STC_TYPE) == STC_LONG) iconvert = stc_cmyk10_long; else iconvert = stc_cmyk10_float; } else if((sd->color_info.num_components == 4) && (sd->color_info.depth == 32) && (sizeof(long) == sd->stc.alg_item)) iconvert = stc_cmyk32_long; /* * initialize the algorithm */ if((*sd->stc.dither->fun)(sd,-prt_pixels,alg_line,buf,col_line) < 0) SORRY; /* * Main-Print-Loop */ if(OK4GO) { #ifdef STC_SIGNAL sigset_t stc_int_mask, stc_int_save, stc_int_pending; sigemptyset(&stc_int_mask); sigaddset(&stc_int_mask,SIGINT); sigprocmask(SIG_BLOCK,&stc_int_mask, &stc_int_save); #endif /* STC_SIGNAL */ if(sd->color_info.num_components > 1) ncolor = 4; else ncolor = 1; /* * Decide, wether we Adjust Linefeeds or not. (I hate it here) */ if((0 == ((sd->stc.escp_m*sd->stc.escp_u) % 10)) && (256 > ((sd->stc.escp_m*sd->stc.escp_u) / 10))) sd->stc.escp_lf = sd->stc.escp_m; else sd->stc.escp_lf = 0; /* * prepare run-values, then loop over scans */ sd->stc.stc_y = 0; /* current printer y-Position */ sd->stc.buf_y = 0; /* Top-Position within the buffer */ sd->stc.prt_y = 0; /* physical position of the printer */ buf_i = 0; /* next free line in buffer */ sd->stc.flags &= ~STCPRINT; /* no data yet */ while(sd->stc.stc_y < sd->stc.prt_scans) { /* Until all scans are processed */ int need; need = sd->stc.stc_y + npass * sd->stc.escp_m; if(sd->stc.buf_y < need) { /* Nr. 5 (give me input) */ /* read as much as the buffer can hold */ if(ncolor == 1) need = sd->stc.stc_y + sd->stc.prt_buf; else need = sd->stc.stc_y + (sd->stc.prt_buf>>2); for(;sd->stc.buf_y < need; buf_i = (sd->stc.prt_buf-1) & (buf_i+ncolor), ++sd->stc.buf_y) { int color; byte *ext_data; byte *alg_data; /* initialize output data 1st -> may take shortcut */ for(color = 0; color < ncolor; ++color) { memset(sd->stc.prt_data[buf_i+color],0,sd->stc.prt_size); sd->stc.prt_width[buf_i+color] = 0; } /* "read data", immediately continue if all is white */ if(sd->stc.buf_y < sd->stc.prt_scans) { /* Test for White */ gdev_prn_get_bits(pdev,sd->stc.buf_y,ext_line,&ext_data); color = stc_iswhite(sd,prt_pixels,ext_data) ? ext_size : 0; } else { color = ext_size; } /* Test for White */ if(color >= ext_size) { /* bypass processing */ if(sd->stc.dither->flags & STC_WHITE) (*sd->stc.dither->fun)(sd,prt_pixels,NULL,buf,col_line); continue; } /* bypass processing */ /* convert data for the various cases */ alg_data = (*iconvert)(sd,ext_data,prt_pixels,alg_line); /* * invoke the dithering-algorithm */ (*sd->stc.dither->fun)(sd,prt_pixels,alg_data,buf,col_line); /* * convert col_line to printer-format (separate colors) */ switch(sd->color_info.num_components) { case 1: /* Black & White: just merge into 8 Bytes */ { byte *bytein,*byteout; int width; bytein = col_line; byteout = sd->stc.prt_data[buf_i]; for(width = 1; width <= sd->stc.prt_size; ++width) { byte tmp = 0; byte i; for(i = 128; i; i >>= 1) if(*bytein++) tmp |= i; if(tmp != 0) sd->stc.prt_width[buf_i] = width; *byteout++ = tmp; } } break; case 3: /* convert rgb into cmyk */ { byte *bytein; int width; bytein = col_line; for(width = 0; width < sd->stc.prt_size; ++width) { byte i,tmp,cmyk[4]; memset(cmyk,0,4); for(i = 128; i; i >>= 1) { static const byte rgb2cmyk[] = { BLACK, /* 0->Black */ CYAN | MAGENTA, /* 1->BLUE */ CYAN | YELLOW, /* 2->GREEN */ CYAN, /* 3->CYAN */ MAGENTA | YELLOW, /* 4->RED */ MAGENTA, /* 5->MAGENTA */ YELLOW, /* 6->YELLOW */ 0}; /* 7->WHITE */ tmp = rgb2cmyk[(*bytein++) & 7]; if(tmp & BLACK) cmyk[3] |= i; if(tmp & YELLOW) cmyk[2] |= i; if(tmp & MAGENTA) cmyk[1] |= i; if(tmp & CYAN) cmyk[0] |= i; } for(i = 0; i < 4; ++i) { if(cmyk[i] != 0) sd->stc.prt_width[buf_i+i] = width+1; sd->stc.prt_data[buf_i+i][width] = cmyk[i]; } } } break; case 4: /* split cmyk */ { byte *bytein; int width; bytein = col_line; for(width = 0; width < sd->stc.prt_size; ++width) { byte i,tmp,cmyk[4]; memset(cmyk,0,4); for(i = 128; i; i >>= 1) { tmp = (*bytein++) & 15; if(tmp & BLACK) cmyk[3] |= i; if(tmp & YELLOW) cmyk[2] |= i; if(tmp & MAGENTA) cmyk[1] |= i; if(tmp & CYAN) cmyk[0] |= i; } for(i = 0; i < 4; ++i) { if(cmyk[i] != 0) sd->stc.prt_width[buf_i+i] = width+1; sd->stc.prt_data[buf_i+i][width] = cmyk[i]; } } } break; default: break; } } } /* Nr. 5 (give me input) */ /* * Nr. 5 has got enough input, now we should print it */ if((flags & STCCOMP) == STCDELTA) stc_print_delta(sd,prn_stream); else if(npass > 1) stc_print_weave(sd,prn_stream); else stc_print_bands(sd,prn_stream); #ifdef STC_SIGNAL sigpending(&stc_int_pending); if(sigismember(&stc_int_pending,SIGINT)) { fputs("\033@[Aborted]\f", prn_stream); fflush(prn_stream); sigprocmask(SIG_SETMASK,&stc_int_save,NULL); break; } #endif /* STC_SIGNAL */ } /* Until all scans are processed */ if(sd->stc.flags & STCPRINT) { if((flags & STCCOMP) == STCDELTA) fputc(0xe3,prn_stream); fwrite(sd->stc.escp_release.data,1,sd->stc.escp_release.size,prn_stream); fflush(prn_stream); } #ifdef STC_SIGNAL sigprocmask(SIG_SETMASK,&stc_int_save,NULL); #endif /* STC_DIGNAL */ } } /*** *** Release the dynamic memory ***/ if(ext_line != NULL) gs_free(ext_line,ext_size,1,"stc_print_page/ext_line"); if(col_line != NULL) gs_free(col_line,prt_pixels,1,"stc_print_page/col_line"); if(alg_line != NULL) gs_free(alg_line,alg_size,sd->stc.alg_item, "stc_print_page/alg_line"); if(buf != NULL) gs_free(buf,buf_size,sd->stc.alg_item,"stc_print_page/buf"); if(sd->stc.prt_width != NULL) gs_free(sd->stc.prt_width,sd->stc.prt_buf,sizeof(int), "stc_print_page/prt_width"); if(sd->stc.prt_data != NULL) { int i; for(i = 0; i < sd->stc.prt_buf; ++i) { if(sd->stc.prt_data[i] != NULL) gs_free(sd->stc.prt_data[i],sd->stc.prt_size,1, "stc_print_page/prt"); } gs_free(sd->stc.prt_data,sd->stc.prt_buf,sizeof(byte *), "stc_print_page/prt_data"); } { int i; for(i = 0; i < sd->color_info.num_components; ++i) { if(sd->stc.seed_row[i] != NULL) gs_free(sd->stc.seed_row[i],sd->stc.seed_size,sizeof(int), "stc_print_page/seed_row"); } } if(sd->stc.escp_data != NULL) gs_free(sd->stc.escp_data,sd->stc.escp_size,1, "stc_print_page/escp_data"); return OK4GO ? 0 : gs_error_undefined; } /* * white-check */ private bool stc_iswhite(stcolor_device *sd, int prt_pixels,byte *ext_data) { long b2do = (prt_pixels*sd->color_info.depth+7)>>3; int bcmp = 4 * countof(sd->stc.white_run); byte *wht = (byte *) sd->stc.white_run; while(b2do >= bcmp) { if(memcmp(ext_data,wht,bcmp)) break; ext_data += bcmp; b2do -= bcmp; } if((b2do > 0) && (b2do < bcmp)) b2do = memcmp(ext_data,sd->stc.white_end,b2do); return b2do ? false : true; } /*** *** A bunch of routines that convert gslines into algorithms format. ***/ private byte * stc_any_depth(stcolor_device *sd,byte *ext_data,int prt_pixels,byte *alg_line) { /* general conversion */ int p,c, niext, nbits; gx_color_index ciext,ci,cimsk,cvmsk; byte *ap = alg_line; nbits = sd->stc.bits; cvmsk = ((gx_color_index) 1<color_info.depth == (sd->color_info.num_components<<3)) nbits = 8; cimsk = cvmsk; for(c = 1; c < sd->color_info.num_components; ++c) cimsk = (cimsk<color_info.depth-niext; c >= 8; c -= 8) ci = (ci<<8) | *ext_data++; if(c > 0) { /* partial byte required */ niext = 8 - c; ciext = *ext_data++; ci = (ci<>niext); ciext &= (1L<>niext; } else { /* entire ciext used */ niext = 0; ciext = 0; } /* ciext-adjust */ ci &= cimsk; # define stc_storeapc(T) \ ((T *)ap)[c] = ((T *)(sd->stc.vals[c]))[ci & cvmsk]; for(c = sd->color_info.num_components; c--;) { /* comp */ STC_TYPESWITCH(sd->stc.dither,stc_storeapc) ci >>= nbits; } /* comp */ # undef stc_storeapc ap += sd->color_info.num_components * sd->stc.alg_item; } /* over pixels */ return alg_line; } /* general conversion */ /* * rgb-data with depth=24, can use a faster algorithm */ private byte * stc_rgb24_long(stcolor_device *sd,byte *ext_data,int prt_pixels,byte *alg_line) { /* convert 3 bytes into appropriate long-Values */ register int p; register long *out = (long *) alg_line; register long *rvals = (long *) (sd->stc.vals[0]); register long *gvals = (long *) (sd->stc.vals[1]); register long *bvals = (long *) (sd->stc.vals[2]); for(p = prt_pixels; p; --p) { *out++ = rvals[*ext_data++]; *out++ = gvals[*ext_data++]; *out++ = bvals[*ext_data++]; } return alg_line; } /* convert 3 bytes into appropriate long-Values */ /* * cmyk-data with depth=32, can use a faster algorithm */ private byte * stc_cmyk32_long(stcolor_device *sd,byte *ext_data,int prt_pixels,byte *alg_line) { /* convert 4 bytes into appropriate long-Values */ register int p; register long *out = (long *) alg_line; register long *cvals = (long *) (sd->stc.vals[0]); register long *mvals = (long *) (sd->stc.vals[1]); register long *yvals = (long *) (sd->stc.vals[2]); register long *kvals = (long *) (sd->stc.vals[3]); for(p = prt_pixels; p; --p) { *out++ = cvals[*ext_data++]; *out++ = mvals[*ext_data++]; *out++ = yvals[*ext_data++]; *out++ = kvals[*ext_data++]; } return alg_line; } /* convert 4 bytes into appropriate long-Values */ /* * handle indirect encoded cmyk-data */ #define STC_CMYK10_ANY(T)\ \ register int p = prt_pixels; \ register stc_pixel ci,k,n,mode; \ register stc_pixel *in = (stc_pixel *) ext_data; \ register T *out = (T *) alg_line; \ register T *cv = (T *) sd->stc.vals[0]; \ register T *mv = (T *) sd->stc.vals[1]; \ register T *yv = (T *) sd->stc.vals[2]; \ register T *kv = (T *) sd->stc.vals[3]; \ \ while(p--) { \ ci = *in++; \ mode = ci & 3; \ k = (ci>>2) & 0x3ff; \ if(mode == 3) { \ *out++ = cv[0]; \ *out++ = mv[0]; \ *out++ = yv[0]; \ *out++ = kv[k]; \ } else { \ out[3] = kv[k]; \ n = (ci>>12) & 0x3ff; \ if(mode == 2) { out[2] = yv[k]; } \ else { out[2] = yv[n]; n = (ci>>22) & 0x3ff; } \ if(mode == 1) { out[1] = mv[k]; } \ else { out[1] = mv[n]; n = (ci>>22) & 0x3ff; } \ if(mode == 0) out[0] = cv[k]; \ else out[0] = cv[n]; \ out += 4; \ } \ } \ \ return alg_line; private byte * stc_cmyk10_byte(stcolor_device *sd, byte *ext_data,int prt_pixels,byte *alg_line) { STC_CMYK10_ANY(byte) } private byte * stc_cmyk10_long(stcolor_device *sd, byte *ext_data,int prt_pixels,byte *alg_line) { STC_CMYK10_ANY(long) } private byte * stc_cmyk10_float(stcolor_device *sd, byte *ext_data,int prt_pixels,byte *alg_line) { STC_CMYK10_ANY(float) } #undef STC_CMYK10_ANY #define STC_CMYK10_DANY(T)\ \ register int p = prt_pixels; \ register stc_pixel ci,k,n,mode; \ register stc_pixel *in = (stc_pixel *) ext_data; \ register T *out = (T *) alg_line; \ \ while(p--) { \ ci = *in++; \ mode = ci & 3; \ k = (ci>>2) & 0x3ff; \ if(mode == 3) { \ *out++ = 0; \ *out++ = 0; \ *out++ = 0; \ *out++ = k; \ } else { \ out[3] = k; \ n = (ci>>12) & 0x3ff; \ if(mode == 2) { out[2] = k; } \ else { out[2] = n; n = (ci>>22) & 0x3ff; } \ if(mode == 1) { out[1] = k; } \ else { out[1] = n; n = (ci>>22) & 0x3ff; } \ if(mode == 0) out[0] = k; \ else out[0] = n; \ out += 4; \ } \ } \ \ return alg_line; private byte * stc_cmyk10_dbyte(stcolor_device *sd, byte *ext_data,int prt_pixels,byte *alg_line) { STC_CMYK10_DANY(byte) } private byte * stc_cmyk10_dlong(stcolor_device *sd, byte *ext_data,int prt_pixels,byte *alg_line) { STC_CMYK10_DANY(long) } #undef STC_CMYK10_DANY /* * if the algorithm uses bytes & bytes are in ext_data, use them */ /*ARGSUSED*/ private byte * stc_any_direct(stcolor_device *sd,byte *ext_data,int prt_pixels,byte *alg_line) { /* return ext_data */ return ext_data; } /* return ext_data */ /* ----------------------------------------------------------------------- */ /* stc_rle: epson ESC/P2 RLE-Encoding */ private int stc_rle(byte *out,const byte *in,int width) { int used = 0; int crun,cdata; byte run; if(in != NULL) { /* Data present */ crun = 1; while(width > 0) { /* something to compress */ run = in[0]; while((width > crun) && (run == in[crun])) if(++crun == 129) break; if((crun > 2) || (crun == width)) { /* use this run */ *out++ = (257 - crun) & 0xff; *out++ = run; used += 2; width -= crun; in += crun; crun = 1; } else { /* ignore this run */ for(cdata = crun; (width > cdata) && (crun < 4);) { if(run == in[cdata]) crun += 1; else run = in[cdata], crun = 1; if(++cdata == 128) break; } if(crun < 3) crun = 0; /* ignore trailing run */ else cdata -= crun; *out++ = cdata-1; used++; memcpy(out,in,cdata); used += cdata; out += cdata; width -= cdata; in += cdata; } /* use/ignore run */ } /* something to compress */ } else { /* Empty scans to fill bands */ while(width > 0) { crun = width > 129 ? 129 : width; width -= crun; *out++ = (257 - crun) & 0xff; *out++ = 0; used += 2; } } /* Data present or empty */ return used; } /* * Horizontal & vertical positioning, color-selection, "ESC ." */ private int stc_print_escpcmd(stcolor_device *sd, FILE *prn_stream, int escp_used, int color,int m,int wbytes) { int dy = sd->stc.stc_y - sd->stc.prt_y; /* number of units to skip */ int nlf; /* ESC-R color codes, used only here */ static const byte stc_colors[] = { 0x02, 0x01, 0x04, 0x00 }; /* CMYK */ /* * initialize the printer, if necessary */ if(0 == (sd->stc.flags & STCPRINT)) { fwrite(sd->stc.escp_init.data,1,sd->stc.escp_init.size,prn_stream); if(0 < sd->stc.escp_lf) { /* Adjust Linefeed */ fputc('\033', prn_stream); fputc('+', prn_stream); fputc(((sd->stc.escp_m*sd->stc.escp_u) / 10),prn_stream); } /* Adjust Linefeed */ sd->stc.flags |= STCPRINT; } sd->stc.escp_data[escp_used++] = '\r'; /* leftmost position */ if(dy) { /* position the printer */ if(( sd->stc.escp_lf > 0) && /* Linefeed allowed */ ((dy % sd->stc.escp_lf) == 0)) /* and possible */ nlf = dy / sd->stc.escp_lf; else nlf = 7; if(nlf > 6) { sd->stc.escp_data[escp_used++] = '\033'; sd->stc.escp_data[escp_used++] = '('; sd->stc.escp_data[escp_used++] = 'V'; sd->stc.escp_data[escp_used++] = '\002'; sd->stc.escp_data[escp_used++] = '\000'; sd->stc.escp_data[escp_used++] = sd->stc.stc_y & 0xff; sd->stc.escp_data[escp_used++] = (sd->stc.stc_y >> 8) & 0xff; } else { while(nlf--) sd->stc.escp_data[escp_used++] = '\n'; } sd->stc.prt_y = sd->stc.stc_y; } /* position the printer */ if((sd->color_info.num_components > 1) && (sd->stc.escp_c != stc_colors[color])) { /* select color */ sd->stc.escp_data[escp_used++] = '\033'; sd->stc.escp_data[escp_used++] = 'r'; sd->stc.escp_c = stc_colors[color]; sd->stc.escp_data[escp_used++] = sd->stc.escp_c; } /* select color */ /* * Build the command used */ sd->stc.escp_data[escp_used++] = '\033'; sd->stc.escp_data[escp_used++] = '.'; sd->stc.escp_data[escp_used++] = (sd->stc.flags & STCCOMP) == STCPLAIN ? 0 : 1; sd->stc.escp_data[escp_used++] = sd->stc.escp_v; sd->stc.escp_data[escp_used++] = sd->stc.escp_h; sd->stc.escp_data[escp_used++] = m; sd->stc.escp_data[escp_used++] = (wbytes<<3) & 0xff; /* width in Pixels */ sd->stc.escp_data[escp_used++] = (wbytes>>5) & 0xff; return escp_used; } /* * compute width of a group of scanlines */ private int stc_bandwidth(stcolor_device *sd,int color,int m,int npass) { int ncolor = sd->color_info.num_components == 1 ? 1 : 4; int buf_a = (sd->stc.prt_buf-1) & (sd->stc.stc_y * ncolor + color); int w = 0; while(m-- > 0) { /* check width */ if(sd->stc.prt_width[buf_a] > w) w = sd->stc.prt_width[buf_a]; buf_a = (sd->stc.prt_buf-1) & (buf_a + ncolor * npass); } /* check width */ return w; } /* * Multi-Pass Printing-Routine */ private void stc_print_weave(stcolor_device *sd, FILE *prn_stream) { int escp_used,nprint,nspace,color,buf_a,iprint,w; int npass = sd->stc.escp_v / sd->stc.escp_u; int ncolor = sd->color_info.num_components == 1 ? 1 : 4; while(sd->stc.stc_y < sd->stc.prt_scans) { /* * compute spacing & used heads (seems to work with odd escp_m) */ if(sd->stc.stc_y >= sd->stc.escp_m) { /* in normal mode */ nprint = sd->stc.escp_m; nspace = sd->stc.escp_m; } else if((sd->stc.stc_y) < npass) { /* initialisation */ nprint = sd->stc.escp_m - sd->stc.stc_y * ((sd->stc.escp_m+1)/npass); nspace = 1; } else { /* switch to normal */ nprint = sd->stc.escp_m - sd->stc.stc_y * ((sd->stc.escp_m+1)/npass); nspace = sd->stc.escp_m - sd->stc.stc_y; } iprint = sd->stc.stc_y + npass * nprint; if(sd->stc.buf_y < iprint) break; escp_used = 0; for(color = 0; color < ncolor; ++color) { /* print the colors */ if(0 == (w = stc_bandwidth(sd,color,nprint,npass))) continue; escp_used = stc_print_escpcmd(sd,prn_stream, escp_used,color,sd->stc.escp_m,w); buf_a = (sd->stc.prt_buf-1) & (sd->stc.stc_y * ncolor + color); for(iprint = 0; iprint < nprint; ++iprint) { /* send data */ if((sd->stc.flags & STCCOMP) == STCPLAIN) { memcpy(sd->stc.escp_data+escp_used,sd->stc.prt_data[buf_a],w); escp_used += w; } else { escp_used += stc_rle(sd->stc.escp_data+escp_used, sd->stc.prt_data[buf_a],w); } fwrite(sd->stc.escp_data,1,escp_used,prn_stream); escp_used = 0; buf_a = (sd->stc.prt_buf-1) & (buf_a + ncolor * npass); } /* send data */ while(iprint++ < sd->stc.escp_m) { /* add empty rows */ if((sd->stc.flags & STCCOMP) == STCPLAIN) { memset(sd->stc.escp_data+escp_used,0,w); escp_used += w; } else { escp_used += stc_rle(sd->stc.escp_data+escp_used,NULL,w); } fwrite(sd->stc.escp_data,1,escp_used,prn_stream); escp_used = 0; } /* add empty rows */ } /* print the colors */ sd->stc.stc_y += nspace; } } /* * Single-Pass printing-Routine */ private void stc_print_bands(stcolor_device *sd, FILE *prn_stream) { int escp_used,color,buf_a,iprint,w,m; int ncolor = sd->color_info.num_components == 1 ? 1 : 4; while(sd->stc.stc_y < sd->stc.prt_scans) { /* * find the begin of the band */ for(w = 0; sd->stc.stc_y < sd->stc.buf_y; ++sd->stc.stc_y) { buf_a = (sd->stc.prt_buf-1) & (sd->stc.stc_y * ncolor); for(color = 0; color < ncolor; ++color) if(sd->stc.prt_width[buf_a+color] > w) w = sd->stc.prt_width[buf_a+color]; if(w != 0) break; } if(w == 0) break; /* * adjust the band-height */ w = sd->stc.prt_scans - sd->stc.stc_y; if((w < sd->stc.escp_m) && (sd->stc.escp_v != 40)) { if(w < 8) m = 1; else if(w < 24) m = 8; else m = 24; } else { m = sd->stc.escp_m; } if(sd->stc.buf_y < (sd->stc.stc_y+m)) break; escp_used = 0; for(color = 0; color < ncolor; ++color) { /* print the colors */ if(0 == (w = stc_bandwidth(sd,color,m,1))) continue; /* shortcut */ escp_used = stc_print_escpcmd(sd,prn_stream,escp_used,color,m,w); buf_a = (sd->stc.prt_buf-1) & (sd->stc.stc_y * ncolor + color); for(iprint = 0; iprint < m; ++iprint) { /* send data */ if((sd->stc.flags & STCCOMP) == STCPLAIN) { memcpy(sd->stc.escp_data+escp_used,sd->stc.prt_data[buf_a],w); escp_used += w; } else { escp_used += stc_rle(sd->stc.escp_data+escp_used, sd->stc.prt_data[buf_a],w); } fwrite(sd->stc.escp_data,1,escp_used,prn_stream); escp_used = 0; buf_a = (sd->stc.prt_buf-1) & (buf_a + ncolor); } /* send data */ } /* print the colors */ sd->stc.stc_y += m; } } /* ----------------------------------------------------------------------- */ private int stc_deltarow(byte *out,const byte *in,int width,byte *seed) { int istop,nmove,ndata,i,j; int *wseed = (int *) seed; int used = 0; seed += sizeof(int); if((in != NULL) && (width > 0)) { /* Data present */ istop = width < wseed[0] ? wseed[0] : width; i = 0; while(i < istop) { for(j = i; j < istop; ++j) if(in[j] != seed[j]) break; nmove = j - i; if(nmove > 0) { /* issue a move */ i = j; if(i == istop) break; if( nmove < 8) { out[used++] = 0x40 | nmove; } else if(nmove < 128) { out[used++] = 0x51; out[used++] = nmove; } else { out[used++] = 0x52; out[used++] = 0xff & nmove; out[used++] = 0xff & (nmove>>8); } } /* issue a move */ /* * find the end of this run */ nmove = 0; for(j = i+1; (j < istop) && ((nmove < 4)); ++j) { if(in[j] == seed[j]) nmove += 1; else nmove = 0; } ndata = j-i-nmove; nmove = stc_rle(out+used+3,in+i,ndata); if(nmove < 16) { out[used++] = 0x20 | nmove; for(j = 0; j < nmove; ++j) out[used+j] = out[used+j+2]; } else if(nmove < 256) { out[used++] = 0x31; out[used++] = nmove; for(j = 0; j < nmove; ++j) out[used+j] = out[used+j+1]; } else { out[used++] = 0x32; out[used++] = 0xff & nmove; out[used++] = 0xff & (nmove>>8); } used += nmove; i += ndata; } memcpy(seed,in,istop); wseed[0] = width; } else if(wseed[0] > 0) { /* blank line, but seed has data */ out[used++] = 0xe1; /* clear row */ memset(seed,0,wseed[0]); wseed[0] = 0; } return used; } /* * Slightly different single-pass printing */ private void stc_print_delta(stcolor_device *sd, FILE *prn_stream) { int color,buf_a,w; int escp_used = 0; int ncolor = sd->color_info.num_components == 1 ? 1 : 4; while(sd->stc.stc_y < sd->stc.prt_scans) { /* * find the begin of the band */ for(w = 0; sd->stc.stc_y < sd->stc.buf_y; ++sd->stc.stc_y) { buf_a = (sd->stc.prt_buf-1) & (sd->stc.stc_y * ncolor); for(color = 0; color < ncolor; ++color) if(sd->stc.prt_width[buf_a+color] > w) w = sd->stc.prt_width[buf_a+color]; if(w != 0) break; } if(sd->stc.buf_y == sd->stc.stc_y) break; escp_used = 0; /* * Send Initialization & ESC . 3 once */ if(0 == (sd->stc.flags & STCPRINT)) { sd->stc.flags |= STCPRINT; fwrite(sd->stc.escp_init.data,1,sd->stc.escp_init.size,prn_stream); sd->stc.escp_data[escp_used++] = '\033'; sd->stc.escp_data[escp_used++] = '.'; sd->stc.escp_data[escp_used++] = 3; sd->stc.escp_data[escp_used++] = sd->stc.escp_v; sd->stc.escp_data[escp_used++] = sd->stc.escp_h; sd->stc.escp_data[escp_used++] = sd->stc.escp_m; sd->stc.escp_data[escp_used++] = 0; sd->stc.escp_data[escp_used++] = 0; sd->stc.escp_data[escp_used++] = 0xe4; /* MOVXBYTE */ } if(sd->stc.stc_y != sd->stc.prt_y) { /* really position the printer */ w = sd->stc.stc_y - sd->stc.prt_y; if( w < 16) { sd->stc.escp_data[escp_used++] = 0x60 | w; } else if(w < 256) { sd->stc.escp_data[escp_used++] = 0x71; sd->stc.escp_data[escp_used++] = w; } else { sd->stc.escp_data[escp_used++] = 0x72; sd->stc.escp_data[escp_used++] = 0xff & w; sd->stc.escp_data[escp_used++] = 0xff & (w>>8); } sd->stc.prt_y = sd->stc.stc_y; } /* really position the printer */ for(color = 0; color < ncolor; ++color) { /* print the colors */ /* Color-Selection */ if(color == (ncolor-1)) { sd->stc.escp_data[escp_used++] = 0x80; /* Black */ } else { switch(color) { case 1: sd->stc.escp_data[escp_used++] = 0x81; break; /* M */ case 2: sd->stc.escp_data[escp_used++] = 0x84; break; /* Y */ default: sd->stc.escp_data[escp_used++] = 0x82; break; /* C */ } } /* Data-Transfer */ buf_a = (sd->stc.prt_buf-1) & (sd->stc.stc_y * ncolor + color); w = stc_deltarow(sd->stc.escp_data+escp_used, sd->stc.prt_data[buf_a],sd->stc.prt_width[buf_a], sd->stc.seed_row[color]); if(w == 0) escp_used -= 1; else escp_used += w; if(escp_used > 0) fwrite(sd->stc.escp_data,1,escp_used,prn_stream); escp_used = 0; } /* print the colors */ sd->stc.stc_y += 1; } } /* ----------------------------------------------------------------------- */ /*** *** Free-Data: release the specific-Arrays ***/ private void stc_freedata(stc_t *stc) { int i,j; for(i = 0; i < 4; ++i) { if(stc->code[i] != NULL) { for(j = 0; j < i; ++j) if(stc->code[i] == stc->code[j]) break; if(i == j) gs_free(stc->code[i],1<bits,sizeof(gx_color_value), "stcolor/code"); } if(stc->vals[i] != NULL) { for(j = 0; j < i; ++j) if(stc->vals[i] == stc->vals[j]) break; if(i == j) gs_free(stc->vals[i],1<bits,sd->stc.alg_item, "stcolor/transfer"); } } for(i = 0; i < 4; ++i) { stc->code[i] = NULL; stc->vals[i] = NULL; } } /*** *** open the device and initialize margins & arrays ***/ private int stc_open(gx_device *pdev) /* setup margins & arrays */ { stcolor_device *sd = (stcolor_device *) pdev; int i,j,code; gx_color_index white; byte *bpw,*bpm; code = 0; /* * Establish Algorithm-Table, if not present */ if(sd->stc.algorithms.size == 0) { gs_param_string *dp; for(i = 0; stc_dither[i].name != NULL; ++i); /* count 'em */ sd->stc.algorithms.size = i; dp = gs_malloc(i,sizeof(gs_param_string), "stcolor/algorithms"); if(dp == NULL) { code = gs_error_VMerror; sd->stc.algorithms.size = 0; } else { sd->stc.algorithms.data = dp; sd->stc.algorithms.persistent = true; for(i = 0; stc_dither[i].name != NULL; ++i) { param_string_from_string(dp[i],stc_dither[i].name); } } } # define stc_sizeofitem(T) sd->stc.alg_item = sizeof(T) STC_TYPESWITCH(sd->stc.dither,stc_sizeofitem) stc_print_setup(sd); /* * Establish internal Value & Code-Arrays */ for(i = 0; i < sd->color_info.num_components; ++i) { /* comp */ if((sd->stc.sizc[i] > 1) && (sd->stc.extc[i] != NULL)) { /* code req. */ for(j = 0; j < i; ++j) if(sd->stc.extc[i] == sd->stc.extc[j]) break; if(i == j) { /* new one */ sd->stc.code[i] = gs_malloc(1<stc.bits,sizeof(gx_color_value), "stcolor/code"); if(sd->stc.code[i] == NULL) { /* error */ code = gs_error_VMerror; } else { /* success */ /* * Try making things easier: * normalize values to 0.0/1.0-Range * X-Axis: Color-Values (implied) * Y-Values: Indices (given) */ unsigned long ly,iy; double ystep,xstep,fx,fy; /* normalize */ fx = 1e18; fy = -1e18; for(ly = 0; ly < sd->stc.sizc[i]; ++ly) { if(sd->stc.extc[i][ly] < fx) fx = sd->stc.extc[i][ly]; if(sd->stc.extc[i][ly] > fy) fy = sd->stc.extc[i][ly]; } if((fx != 0.0) || (fy != 1.0)) { fy = 1.0 / (fy - fx); for(ly = 0; ly < sd->stc.sizc[i]; ++ly) sd->stc.extc[i][ly] = fy * (sd->stc.extc[i][ly]-fx); } /* interpolate */ ystep = 1.0 / (double)((1<stc.bits)-1); xstep = 1.0 / (double)( sd->stc.sizc[i] -1); iy = 0; for(ly = 0; ly < (1<stc.bits); ++ly) { fy = ystep * ly; while(((iy+1) < sd->stc.sizc[i]) && ( fy > sd->stc.extc[i][iy+1])) ++iy; fx = iy + (fy - sd->stc.extc[i][iy]) / (sd->stc.extc[i][iy+1] - sd->stc.extc[i][iy]); fx *= xstep * gx_max_color_value; fx = fx < 0.0 ? 0.0 : (fx > gx_max_color_value ? gx_max_color_value : fx); sd->stc.code[i][ly] = fx; if((fx-sd->stc.code[i][ly]) >= 0.5) sd->stc.code[i][ly] += 1; } } /* error || success */ } else { /* shared one */ sd->stc.code[i] = sd->stc.code[j]; } /* new || shared one */ } /* code req. */ if((sd->stc.sizv[i] > 1) && (sd->stc.extv[i] != NULL)) { /* vals req. */ for(j = 0; j < i; ++j) if((sd->stc.extc[i] == sd->stc.extc[j]) && (sd->stc.extv[i] == sd->stc.extv[j])) break; if(i == j) { /* new one */ sd->stc.vals[i] = gs_malloc(1<stc.bits,sd->stc.alg_item,"stcolor/transfer"); if(sd->stc.vals[i] == NULL) { code = gs_error_VMerror; } else { /* success */ if(sd->stc.code[i] == NULL) { /* linear */ byte *Out = sd->stc.vals[i]; int Nout = 1<stc.bits; double Omin = sd->stc.dither->minmax[0]; double Omax = sd->stc.dither->minmax[1]; float *In = sd->stc.extv[i]; int Nin = sd->stc.sizv[i]; unsigned long I,io; double Istep,Ostep,Y; byte Ovb; long Ovl; Istep = 1.0 / (double) ((Nin)-1); Ostep = 1.0 / (double) ((Nout)-1); for(io = 0; io < (Nout); ++io) { I = (long)(io * ((Nin)-1))/((Nout)-1); if((I+1) < (Nin)) Y = In[I] + (In[I+1]-In[I]) * ((double) io * Ostep - (double)I * Istep) / (double) Istep; else Y = In[I] + (In[I]-In[I-1]) * ((double) io * Ostep - (double)I * Istep) / (double) Istep; Y = Omin + (Omax-Omin) * Y; Y = Y < Omin ? Omin : (Y > Omax ? Omax : Y); switch(sd->stc.dither->flags & STC_TYPE) { case STC_BYTE: Ovb = Y; if(((Y-Ovb) >= 0.5) && ((Ovb+1) <= Omax)) Ovb += 1; Out[io] = Ovb; break; case STC_LONG: Ovl = Y; if(((Y-Ovl) >= 0.5) && ((Ovl+1) <= Omax)) Ovl += 1; if(((Ovl-Y) >= 0.5) && ((Ovl-1) >= Omax)) Ovl -= 1; ((long *)Out)[io] = Ovl; break; default: ((float *)Out)[io] = Y; break; } } } else { /* encoded */ unsigned long j,o; double xstep,x,y; xstep = 1.0 / (double) (sd->stc.sizv[i]-1); /* * The following differs in so far from the previous, that the desired * X-Values are stored in another array. */ for(o = 0; o < (1<stc.bits); ++o) { /* code-loop */ x = sd->stc.code[i][o]; x /= gx_max_color_value; j = x / xstep; if((j+1) < sd->stc.sizv[i]) { y = sd->stc.extv[i][j]; y += (sd->stc.extv[i][j+1]-y)*(x-(double)j*xstep)/xstep; } else { y = sd->stc.extv[i][j]; y += (y-sd->stc.extv[i][j-1])*(x-(double)j*xstep)/xstep; } y = sd->stc.dither->minmax[0] +(sd->stc.dither->minmax[1]-sd->stc.dither->minmax[0])*y; # define stc_adjvals(T) \ ((T *)(sd->stc.vals[i]))[o] = y; \ \ if(((y-((T *)(sd->stc.vals[i]))[o]) >= 0.5) && \ ((1+((T *)(sd->stc.vals[i]))[o]) <= sd->stc.dither->minmax[1]))\ ((T *)(sd->stc.vals[i]))[o] += 1; \ \ if(((((T *)(sd->stc.vals[i]))[o]-y) >= 0.5) && \ ((((T *)(sd->stc.vals[i]))[o]-1) >= sd->stc.dither->minmax[0]))\ ((T *)(sd->stc.vals[i]))[o] -= 1; STC_TYPESWITCH(sd->stc.dither,stc_adjvals) # undef stc_adjvals } /* code-loop */ } /* lineaer / encoded */ } /* error || success */ } else { /* shared one */ sd->stc.vals[i] = sd->stc.vals[j]; } /* new || shared one */ } /* vals req. */ } /* comp */ if(code == 0) { sd->stc.flags |= STCOK4GO; /* * Arrgh: open-procedure seems to be the right-place, but it is * necessary to establish the defaults for omitted procedures too. */ switch(sd->color_info.num_components) { /* Establish color-procs */ case 1: set_dev_proc(sd,map_rgb_color, stc_map_gray_color); set_dev_proc(sd,map_cmyk_color,gx_default_map_cmyk_color); set_dev_proc(sd,map_color_rgb, stc_map_color_gray); white = stc_map_gray_color((gx_device *) sd, gx_max_color_value,gx_max_color_value,gx_max_color_value); break; case 3: set_dev_proc(sd,map_rgb_color, stc_map_rgb_color); set_dev_proc(sd,map_cmyk_color,gx_default_map_cmyk_color); set_dev_proc(sd,map_color_rgb, stc_map_color_rgb); white = stc_map_rgb_color((gx_device *) sd, gx_max_color_value,gx_max_color_value,gx_max_color_value); break; default: set_dev_proc(sd,map_rgb_color, gx_default_map_rgb_color); if(sd->stc.flags & STCCMYK10) { set_dev_proc(sd,map_cmyk_color,stc_map_cmyk10_color); set_dev_proc(sd,map_color_rgb, stc_map_color_cmyk10); white = stc_map_cmyk10_color((gx_device *) sd,0,0,0,0); } else { set_dev_proc(sd,map_cmyk_color,stc_map_cmyk_color); set_dev_proc(sd,map_color_rgb, stc_map_color_cmyk); white = stc_map_cmyk_color((gx_device *) sd,0,0,0,0); } break; /* Establish color-procs */ } /* * create at least a Byte */ if(sd->color_info.depth < 2) white |= (white<<1); if(sd->color_info.depth < 4) white |= (white<<2); if(sd->color_info.depth < 8) white |= (white<<4); /* * copy the Bytes */ bpw = (byte *) sd->stc.white_run; if(sd->color_info.depth < 16) { for(i = 0; i < sizeof(sd->stc.white_run); i += 1) { bpw[i] = 0xff & white; } } else if(sd->color_info.depth < 24) { for(i = 0; i < sizeof(sd->stc.white_run); i += 2) { bpw[i] = 0xff & (white>>8); bpw[i+1] = 0xff & white; } } else if(sd->color_info.depth < 32) { for(i = 0; i < sizeof(sd->stc.white_run); i += 3) { bpw[i] = 0xff & (white>>16); bpw[i+1] = 0xff & (white>> 8); bpw[i+2] = 0xff & white; } } else { for(i = 0; i < sizeof(sd->stc.white_run); i += 4) { bpw[i] = 0xff & (white>>24); bpw[i+1] = 0xff & (white>>16); bpw[i+2] = 0xff & (white>> 8); bpw[i+3] = 0xff & white; } } /* * compute the trailer */ j = sd->width - (dev_l_margin(sd)+dev_r_margin(sd))*sd->x_pixels_per_inch; j = j * sd->color_info.depth; /* the Bit-count */ j = j % (32*countof(sd->stc.white_run)); /* remaining Bits */ bpm = (byte *) sd->stc.white_end; for(i = 0; i < (4*countof(sd->stc.white_end)); ++i) { if( j <= 0) { bpm[i] = 0; } else if(j >= 8) { bpm[i] = 0xff; j -= 8; } else { bpm[i] = 0xff ^ ((1<<(8-j))-1); j = 0; } bpm[i] &= bpw[i]; } /* * Call super-class open */ return gdev_prn_open(pdev); } else { stc_freedata(&sd->stc); return_error(code); } } /*** *** stc_close: release the internal data ***/ private int stc_close(gx_device *pdev) { stc_freedata(&((stcolor_device *) pdev)->stc); ((stcolor_device *) pdev)->stc.flags &= ~STCOK4GO; return gdev_prn_close(pdev); } /*** *** Function for Bit-Truncation, including direct-byte-transfer ***/ private gx_color_value stc_truncate(stcolor_device *sd,int i,gx_color_value v) { if(sd->stc.bits < gx_color_value_bits) { if(sd->stc.code[i] != NULL) { /* * Perform binary search in the code-array */ long s; gx_color_value *p; s = sd->stc.bits > 1 ? 1L<<(sd->stc.bits-2) : 0L; p = sd->stc.code[i]+(1L<<(sd->stc.bits-1)); while(s > 0) { if(v > *p) { p += s; } else if(v < p[-1]) { p -= s; } else { if((v-p[-1]) < (p[0]-v)) p -= 1; break; } s >>= 1; } if((v-p[-1]) < (p[0]-v)) p -= 1; v = p - sd->stc.code[i]; } else { v >>= gx_color_value_bits-sd->stc.bits; } /* V = (((1L<stc.bits)-1)*V+(gx_max_color_value>>1))\ /gx_max_color_value; \ */ } return v; } private gx_color_value stc_truncate1(stcolor_device *sd,int i,gx_color_value v) { return sd->stc.vals[i][stc_truncate(sd,i,v)]; } /*** *** Expansion of indices for reverse-mapping ***/ private gx_color_value stc_expand(stcolor_device *sd,int i,gx_color_index col) { gx_color_index cv; gx_color_index l = (1<stc.bits)-1; if(sd->stc.code[i] != NULL) { cv = sd->stc.code[i][col & l]; } else if(sd->stc.bits < gx_color_value_bits) { cv = (col & l)<<(gx_color_value_bits-sd->stc.bits); cv += (col & l)/l * ((1<<(gx_color_value_bits-sd->stc.bits))-1); } else if(sd->stc.bits > gx_color_value_bits) { cv = (col & l)>>(sd->stc.bits-gx_color_value_bits); } else { cv = col & l; } return cv; } /*** *** color-mapping of gray-scales ***/ private gx_color_index stc_map_gray_color(gx_device *pdev, gx_color_value r, gx_color_value g, gx_color_value b) { stcolor_device *sd = (stcolor_device *) pdev; gx_color_index rv; if((r == g) && (g == b)) { rv = gx_max_color_value - r; } else if(sd->stc.am != NULL) { float *m,fv; m = sd->stc.am; fv = gx_max_color_value; fv -= *m++ * (float) r; fv -= *m++ * (float) g; fv -= *m * (float) b; if( fv < 0.0) rv = 0; else if((fv+0.5) > gx_max_color_value) rv = gx_max_color_value; else rv = fv+0.5; } else { rv = ((gx_color_index)gx_max_color_value)<<3; rv -= (gx_color_index) 3 * r; rv -= (gx_color_index) 3 * g; rv -= ((gx_color_index)b)<<1; rv = (rv+4)>>3; if(rv > gx_max_color_value) rv = gx_max_color_value; } if(( sd->stc.bits == 8) && ((sd->stc.dither->flags & STC_TYPE) == STC_BYTE)) rv = stc_truncate1(sd,0,(gx_color_value)rv); else rv = stc_truncate(sd,0,(gx_color_value)rv); return rv; } private int stc_map_color_gray(gx_device *pdev, gx_color_index color,gx_color_value prgb[3]) { stcolor_device *sd = (stcolor_device *) pdev; gx_color_index l = ((gx_color_index)1<stc.bits)-1; prgb[0] = gx_max_color_value - stc_expand(sd,0,color & l); prgb[1] = prgb[0]; prgb[2] = prgb[0]; return 0; } /*** *** color-mapping of rgb-values ***/ private gx_color_index stc_map_rgb_color(gx_device *pdev, gx_color_value r, gx_color_value g, gx_color_value b) { stcolor_device *sd = (stcolor_device *) pdev; int shift = sd->color_info.depth == 24 ? 8 : sd->stc.bits; gx_color_index rv = 0; if((sd->stc.am != NULL) && ((r != g) || (g != b))) { float *m,fr,fg,fb,fv; m = sd->stc.am; fr = r; fg = g; fb = b; fv = *m++ * fr; fv += *m++ * fg; fv += *m++ * fb; if( fv < 0.0) r = 0; else if((fv+0.5) > gx_max_color_value) r = gx_max_color_value; else r = fv+0.5; fv = *m++ * fr; fv += *m++ * fg; fv += *m++ * fb; if( fv < 0.0) g = 0; else if((fv+0.5) > gx_max_color_value) g = gx_max_color_value; else g = fv+0.5; fv = *m++ * fr; fv += *m++ * fg; fv += *m++ * fb; if( fv < 0.0) b = 0; else if((fv+0.5) > gx_max_color_value) b = gx_max_color_value; else b = fv+0.5; } if(( sd->stc.bits == 8) && ((sd->stc.dither->flags & STC_TYPE) == STC_BYTE)) { rv = stc_truncate1(sd,0,r); rv = (rv<color_info.depth == 24 ? 8 : sd->stc.bits; gx_color_index l = ((gx_color_index)1<stc.bits)-1; prgb[0] = stc_expand(sd,0,((color>>(shift<<1)) & l)); prgb[1] = stc_expand(sd,1,((color>> shift ) & l)); prgb[2] = stc_expand(sd,2,( color & l)); return 0; } /*** *** color-mapping of cmyk-values ***/ private gx_color_index stc_map_cmyk_color(gx_device *pdev, gx_color_value c, gx_color_value m, gx_color_value y,gx_color_value k) { stcolor_device *sd = (stcolor_device *) pdev; int shift = sd->color_info.depth == 32 ? 8 : sd->stc.bits; gx_color_index rv = 0; if((c == m) && (m == y)) { k = c > k ? c : k; c = m = y = 0; if(( sd->stc.bits == 8) && ((sd->stc.dither->flags & STC_TYPE) == STC_BYTE)) { k = stc_truncate1(sd,3,k); } else { k = stc_truncate(sd,3,k); } } else { if(sd->stc.am != NULL) { float *a,fc,fm,fy,fk,fv; if(k == 0) { /* no separated black yet */ k = c < m ? c : m; k = k < y ? k : y; if(k) { /* no black at all */ c -= k; m -= k; y -= k; } /* no black at all */ } /* no separated black yet */ a = sd->stc.am; fc = c; fm = m; fy = y; fk = k; fv = *a++ * fc; fv += *a++ * fm; fv += *a++ * fy; fv += *a++ * fk; if( fv < 0.0) c = 0; else if((fv+0.5) > gx_max_color_value) c = gx_max_color_value; else c = fv+0.5; fv = *a++ * fc; fv += *a++ * fm; fv += *a++ * fy; fv += *a++ * fk; if( fv < 0.0) m = 0; else if((fv+0.5) > gx_max_color_value) m = gx_max_color_value; else m = fv+0.5; fv = *a++ * fc; fv += *a++ * fm; fv += *a++ * fy; fv += *a++ * fk; if( fv < 0.0) y = 0; else if((fv+0.5) > gx_max_color_value) y = gx_max_color_value; else y = fv+0.5; fv = *a++ * fc; fv += *a++ * fm; fv += *a++ * fy; fv += *a++ * fk; if( fv < 0.0) k = 0; else if((fv+0.5) > gx_max_color_value) k = gx_max_color_value; else k = fv+0.5; } else if(k == 0) { k = c < m ? c : m; k = k < y ? k : y; } if(( sd->stc.bits == 8) && ((sd->stc.dither->flags & STC_TYPE) == STC_BYTE)) { c = stc_truncate1(sd,0,c); m = stc_truncate1(sd,1,m); y = stc_truncate1(sd,2,y); k = stc_truncate1(sd,3,k); } else { c = stc_truncate(sd,0,c); m = stc_truncate(sd,1,m); y = stc_truncate(sd,2,y); k = stc_truncate(sd,3,k); } } rv = c; rv = (rv<color_info.depth == 32 ? 8 : sd->stc.bits; gx_color_index l = ((gx_color_index)1<stc.bits)-1; gx_color_value c,m,y,k; k = stc_expand(sd,3, color & l); color >>= shift; y = stc_expand(sd,2, color & l); color >>= shift; m = stc_expand(sd,1, color & l); color >>= shift; c = stc_expand(sd,0, color & l); if((c == m) && (m == y)) { prgb[0] = gx_max_color_value-k; prgb[1] = prgb[0]; prgb[2] = prgb[0]; } else { prgb[0] = gx_max_color_value-c; prgb[1] = gx_max_color_value-m; prgb[2] = gx_max_color_value-y; } return 0; } /*** *** color-mapping of cmyk10-values ***/ private gx_color_index stc_map_cmyk10_color(gx_device *pdev, gx_color_value c, gx_color_value m, gx_color_value y,gx_color_value k) { stcolor_device *sd = (stcolor_device *) pdev; int mode; gx_color_index rv = 0; if((c == m) && (m == y)) { k = c > k ? c : k; c = m = y = 0; mode = 3; } else { if(sd->stc.am != NULL) { float *a,fc,fm,fy,fk,fv; k = c < m ? c : m; k = k < y ? k : y; if(k) { /* no black at all */ c -= k; m -= k; y -= k; } /* no black at all */ a = sd->stc.am; fc = c; fm = m; fy = y; fk = k; fv = *a++ * fc; fv += *a++ * fm; fv += *a++ * fy; fv += *a++ * fk; if( fv < 0.0) c = 0; else if((fv+0.5) > gx_max_color_value) c = gx_max_color_value; else c = fv+0.5; fv = *a++ * fc; fv += *a++ * fm; fv += *a++ * fy; fv += *a++ * fk; if( fv < 0.0) m = 0; else if((fv+0.5) > gx_max_color_value) m = gx_max_color_value; else m = fv+0.5; fv = *a++ * fc; fv += *a++ * fm; fv += *a++ * fy; fv += *a++ * fk; if( fv < 0.0) y = 0; else if((fv+0.5) > gx_max_color_value) y = gx_max_color_value; else y = fv+0.5; } if(c < m) { if(c < y) { k = c; c = 0; mode = 0; } else { k = y; y = 0; mode = 2; } } else { if(m < y) { k = m; m = 0; mode = 1; } else { k = y; y = 0; mode = 2; } } } /* * truncate only the values that require it */ if(c) c = stc_truncate(sd,0,c); if(m) m = stc_truncate(sd,1,m); if(y) y = stc_truncate(sd,2,y); if(k) k = stc_truncate(sd,3,k); /* * make sure that truncation-white becomes white. */ if((c|m|y) == 0) mode = 3; /* * check wether value-arrays can be bypassed */ if(((sd->stc.dither->flags & STC_TYPE) == STC_BYTE) && ( sd->stc.dither->minmax[0] == 0.0 )) { c = sd->stc.vals[0][c]; m = sd->stc.vals[1][m]; y = sd->stc.vals[2][y]; k = sd->stc.vals[3][k]; } else if(((sd->stc.dither->flags & STC_TYPE) == STC_LONG) && ( sd->stc.dither->minmax[0] == 0.0 ) && ( sd->stc.dither->minmax[1] <= 1023.0 )) { c = ((long *)(sd->stc.vals[0]))[c]; m = ((long *)(sd->stc.vals[1]))[m]; y = ((long *)(sd->stc.vals[2]))[y]; k = ((long *)(sd->stc.vals[3]))[k]; } /* direct */ /* * compute the long-representation of gx_color_index */ switch(mode) { case 0: rv = (((gx_color_index) m)<<22)| (((gx_color_index) y)<<12)| (((gx_color_index) k)<< 2)|mode; break; case 1: rv = (((gx_color_index) c)<<22)| (((gx_color_index) y)<<12)| (((gx_color_index) k)<< 2)|mode; break; case 2: rv = (((gx_color_index) c)<<22)| (((gx_color_index) m)<<12)| (((gx_color_index) k)<< 2)|mode; break; default: rv = (((gx_color_index) k)<< 2)|mode; break; } /* * We may need some swapping */ #if !arch_is_big_endian { union { stc_pixel cv; byte bv[4]; } ui,uo; ui.cv = rv; uo.bv[0] = ui.bv[3]; uo.bv[1] = ui.bv[2]; uo.bv[2] = ui.bv[1]; uo.bv[3] = ui.bv[0]; rv = uo.cv; } #endif return rv; } private int stc_map_color_cmyk10(gx_device *pdev, gx_color_index color, gx_color_value prgb[3]) { stcolor_device *sd = (stcolor_device *) pdev; gx_color_value c,m,y; /* * We may need some swapping */ #if !arch_is_big_endian union { stc_pixel cv; byte bv[4]; } ui,uo; ui.cv = color; uo.bv[0] = ui.bv[3]; uo.bv[1] = ui.bv[2]; uo.bv[2] = ui.bv[1]; uo.bv[3] = ui.bv[0]; color = uo.cv; #endif c = stc_expand(sd,3,(color>>2)&0x3ff); switch(color & 3) { case 0: m = stc_expand(sd,1,(color>>22) & 0x3ff); y = stc_expand(sd,2,(color>>12) & 0x3ff); break; case 1: m = c; c = stc_expand(sd,0,(color>>22) & 0x3ff); y = stc_expand(sd,2,(color>>12) & 0x3ff); break; case 2: y = c; c = stc_expand(sd,0,(color>>22) & 0x3ff); m = stc_expand(sd,1,(color>>12) & 0x3ff); break; default: m = c; y = c; break; } prgb[0] = gx_max_color_value - c; prgb[1] = gx_max_color_value - m; prgb[2] = gx_max_color_value - y; return 0; } /*** *** Macros for parameter-handling ***/ #define set_param_array(A, D, S)\ {A.data = D; A.size = S; A.persistent = false;} #define stc_write_null(N) \ set_param_array(pfa,defext,countof(defext)) \ code = param_write_null(plist,N); \ if (code < 0) return code; #define stc_write_xarray(I,Coding,Transfer) \ if(sd->stc.sizc[I] > 0) { \ set_param_array(pfa, sd->stc.extc[I],sd->stc.sizc[I]) \ code = param_write_float_array(plist,Coding,&pfa); \ } else { \ code = param_write_null(plist,Coding); \ } \ if ( code < 0 ) return code; \ \ if(sd->stc.sizv[I] > 0) \ set_param_array(pfa, sd->stc.extv[I],sd->stc.sizv[I]) \ else \ set_param_array(pfa,defext,countof(defext)) \ code = param_write_float_array(plist,Transfer,&pfa); \ if ( code < 0 ) return code; #define stc_read_null(N) \ code = param_read_null(plist,N); \ if(code == gs_error_typecheck) \ code = param_read_float_array(plist,N,&pfa); \ if(code < 0) param_signal_error(plist,N,code); \ error = error > code ? code : error; #define stc_read_xarray(I,Coding,Transfer) \ code = param_read_float_array(plist,Coding,&pfa); \ if((error == 0) && (code == 0)) { \ if(pfa.size > 1) { \ sd->stc.extc[I] = (float *) pfa.data; \ sd->stc.sizc[I] = pfa.size; \ } else { \ code = gs_error_rangecheck; \ } \ } else if(code < 0) { \ code = param_read_null(plist,Coding); \ if(code == 0) { \ sd->stc.extc[I] = NULL; \ sd->stc.sizc[I] = 0; \ } \ } \ if(code < 0) param_signal_error(plist,Coding,code); \ error = error > code ? code : error; \ code = param_read_float_array(plist,Transfer,&pfa); \ if((error == 0) && (code == 0)) { \ sd->stc.extv[I] = (float *) pfa.data; \ sd->stc.sizv[I] = pfa.size; \ } else if(code < 0) { \ code = param_read_null(plist,Transfer); \ if(code == 0) { \ sd->stc.extv[I] = defext; \ sd->stc.sizv[I] = countof(defext); \ } \ } \ if(code < 0) param_signal_error(plist,Transfer,code); \ error = error > code ? code : error; /*** *** Get parameters == Make them accessable via PostScript ***/ private int stc_get_params(gx_device *pdev, gs_param_list *plist) { int code,nc; gs_param_string ps; gs_param_float_array pfa; bool btmp; stcolor_device *sd = (stcolor_device *) pdev; code = gdev_prn_get_params(pdev, plist); if ( code < 0 ) return code; /* * Export some readonly-Parameters, used by stcinfo.ps */ param_string_from_string(ps,"1.91"); code = param_write_string(plist,"Version",&ps); if ( code < 0 ) return code; code = param_write_int(plist,"BitsPerComponent",&sd->stc.bits); if ( code < 0 ) return code; if(sd->stc.algorithms.size > 0) { code = param_write_string_array(plist,"Algorithms",&sd->stc.algorithms); } else { code = param_write_null(plist,"Algorithms"); } if ( code < 0 ) return code; /* * Export OutputCode */ switch(sd->stc.flags & STCCOMP) { case STCPLAIN: param_string_from_string(ps,"plain"); break; case STCDELTA: param_string_from_string(ps,"deltarow"); break; default: param_string_from_string(ps,"runlength"); break; } code = param_write_string(plist,"OutputCode",&ps); if ( code < 0 ) return code; /* * Export Model */ switch(sd->stc.flags & STCMODEL) { case STCST800: param_string_from_string(ps,"st800"); break; case STCSTCII: param_string_from_string(ps,"stcii"); break; default: param_string_from_string(ps,"stc"); break; } code = param_write_string(plist,"Model",&ps); if ( code < 0 ) return code; /* * Export the booleans */ #define stc_write_flag(Mask,Name) \ btmp = sd->stc.flags & (Mask) ? true : false; \ code = param_write_bool(plist,Name,&btmp); \ if ( code < 0 ) return code; stc_write_flag(STCUNIDIR,"Unidirectional") stc_write_flag(STCUWEAVE,"Microweave") btmp = sd->stc.flags & (STCUNIDIR|STCUWEAVE) ? false : true; code = param_write_bool(plist,"Softweave",&btmp); if ( code < 0 ) return code; stc_write_flag(STCNWEAVE,"noWeave") stc_write_flag(STCDFLAG0, "Flag0") stc_write_flag(STCDFLAG1, "Flag1") stc_write_flag(STCDFLAG2, "Flag2") stc_write_flag(STCDFLAG3, "Flag3") stc_write_flag(STCDFLAG4, "Flag4") #undef stc_write_flag # define stc_write_int(Mask,Name,Val) \ code = param_write_int(plist,Name,&Val); \ if ( code < 0 ) return code stc_write_int(STCBAND, "escp_Band", sd->stc.escp_m); stc_write_int(STCWIDTH, "escp_Width", sd->stc.escp_width); stc_write_int(STCHEIGHT,"escp_Height",sd->stc.escp_height); stc_write_int(STCTOP, "escp_Top", sd->stc.escp_top); stc_write_int(STCBOTTOM,"escp_Bottom",sd->stc.escp_bottom); # undef stc_write_int code = param_write_string(plist,"escp_Init",&sd->stc.escp_init); code = param_write_string(plist,"escp_Release",&sd->stc.escp_release); if(sd->stc.dither != NULL) { param_string_from_string(ps,sd->stc.dither->name); code = param_write_string(plist,"Dithering",&ps); } else { code = param_write_null(plist,"Dithering"); } if ( code < 0 ) return code; nc = sd->color_info.num_components; if(sd->stc.am != NULL) { if( nc == 1) set_param_array(pfa, sd->stc.am, 3) else if(nc == 3) set_param_array(pfa, sd->stc.am, 9) else set_param_array(pfa, sd->stc.am,16) code = param_write_float_array(plist,"ColorAdjustMatrix",&pfa); } else { code = param_write_null(plist,"ColorAdjustMatrix"); } if ( code < 0 ) return code; if(nc == 1) { /* DeviceGray */ stc_write_xarray(0,"Kcoding","Ktransfer"); stc_write_null("Rcoding"); stc_write_null("Rtransfer"); stc_write_null("Gcoding"); stc_write_null("Gtransfer"); stc_write_null("Bcoding"); stc_write_null("Btransfer"); stc_write_null("Ccoding"); stc_write_null("Ctransfer"); stc_write_null("Mcoding"); stc_write_null("Mtransfer"); stc_write_null("Ycoding"); stc_write_null("Ytransfer"); } else if(nc == 3) { /* DeviceRGB */ stc_write_xarray(0,"Rcoding","Rtransfer"); stc_write_xarray(1,"Gcoding","Gtransfer"); stc_write_xarray(2,"Bcoding","Btransfer"); stc_write_null("Ccoding"); stc_write_null("Ctransfer"); stc_write_null("Mcoding"); stc_write_null("Mtransfer"); stc_write_null("Ycoding"); stc_write_null("Ytransfer"); stc_write_null("Kcoding"); stc_write_null("Ktransfer"); } else { /* DeviceCMYK */ stc_write_xarray(0,"Ccoding","Ctransfer"); stc_write_xarray(1,"Mcoding","Mtransfer"); stc_write_xarray(2,"Ycoding","Ytransfer"); stc_write_xarray(3,"Kcoding","Ktransfer"); stc_write_null("Rcoding"); stc_write_null("Rtransfer"); stc_write_null("Gcoding"); stc_write_null("Gtransfer"); stc_write_null("Bcoding"); stc_write_null("Btransfer"); } return code; } /*** *** put parameters == Store them in the device-structure ***/ private int stc_put_params(gx_device *pdev, gs_param_list *plist) { int code,error,i,l; bool b1,b2,b3; float fv,*fp; gs_param_string ps; gs_param_string_array psa; gs_param_float_array pfa; stcolor_device *sd = (stcolor_device *) pdev; gx_device_color_info oldcolor; stc_t oldstc; /* * save old Values */ memcpy(&oldcolor,&sd->color_info,sizeof(oldcolor)); memcpy(&oldstc ,&sd->stc ,sizeof(oldstc )); /* * Arrrgh: * With Version 3.4x and above my simple minded read-only Parameters * do not work any more. So read them here for heavens sake. */ code = param_read_string(plist,"Version",&ps); code = param_read_int(plist,"BitsPerComponent",&i); code = param_read_string_array(plist,"Algorithms",&psa); /* * Fetch Major-Parameters (Model, Dithering, BitsPerPixel/BitsPerComponent) */ error = 0; code = param_read_string(plist,"Model",&ps); if(code == 0) { /* Analyze the Model-String */ /* * Arrgh: I should have known, that internal strings are not zero-terminated. */ for(l = ps.size; (l > 0) && (ps.data[l-1] == 0); --l); # define stc_putcmp(Name) \ ((strlen(Name) != l) || (0 != strncmp(Name, (const char *)ps.data,l))) sd->stc.flags &= ~STCMODEL; if( !stc_putcmp("st800")) sd->stc.flags |= STCST800; else if(!stc_putcmp("stcii")) sd->stc.flags |= STCSTCII; } /* Analyze the Model-String */ if(code < 0) param_signal_error(plist,"Model",code); error = error > code ? code : error; /* If we're running for st800, #components must be 1 */ if(((sd->stc.flags & STCMODEL) == STCST800) && (( sd->color_info.num_components > 1) || ( sd->stc.dither == NULL) || ((sd->stc.dither->flags & 7) > 1))) { sd->color_info.num_components = 1; sd->stc.dither = NULL; } /* Weaving isn't a feature for the st800 */ if((sd->stc.flags & STCMODEL) == STCST800) { sd->stc.flags &= ~STCUWEAVE; sd->stc.flags |= STCNWEAVE; } else if((sd->stc.flags & STCMODEL) == STCSTCII) { /* no SoftWeave */ sd->stc.flags |= STCNWEAVE; } code = param_read_string(plist,"Dithering",&ps); if(code == 0) { /* lookup new value new value */ for(l = ps.size; (l > 0) && (ps.data[l-1] == 0); --l); for(i = 0; stc_dither[i].name != NULL; ++i) if(!stc_putcmp(stc_dither[i].name)) break; } else if(sd->stc.dither != NULL) { /* compute index of given value */ i = sd->stc.dither - stc_dither; } else { /* find matching value */ for(i = 0; stc_dither[i].name != NULL; ++i) if((stc_dither[i].flags & 7) == sd->color_info.num_components) break; } /* we've got an index */ if(stc_dither[i].name != NULL) { /* establish data */ /* * Establish new dithering algorithm & color-model */ sd->stc.dither = stc_dither+i; sd->color_info.num_components = sd->stc.dither->flags & 7; STC_TYPESWITCH(sd->stc.dither,stc_sizeofitem) # undef stc_sizeofitem if(((sd->stc.flags & STCMODEL) == STCST800) && ( sd->color_info.num_components > 1 )) code = gs_error_rangecheck; /* * reset Parameters related to the color-model, if it changed */ if(sd->color_info.num_components != oldcolor.num_components) { for(i = 0; i < sd->color_info.num_components; ++i) { sd->stc.extv[i] = (float *) defext; sd->stc.sizv[i] = countof(defext); sd->stc.extc[i] = NULL; sd->stc.sizc[i] = 0; } sd->stc.am = NULL; } else { /* guarantee, that extvals is present */ for(i = 0; i < sd->color_info.num_components; ++i) { if(sd->stc.sizv[i] < 2) { sd->stc.extv[i] = (float *) defext; sd->stc.sizv[i] = countof(defext); } } } for(i = sd->color_info.num_components; i < 4; ++ i) { /* clear unused */ sd->stc.extv[i] = NULL; sd->stc.sizv[i] = 0; sd->stc.vals[i] = NULL; sd->stc.extc[i] = NULL; sd->stc.sizc[i] = 0; sd->stc.code[i] = NULL; } /* clear unused */ /* * Guess default depth from range of values */ if((sd->stc.dither != oldstc.dither)||(oldstc.vals[0] == NULL)) { if((sd->stc.dither->flags & STC_CMYK10) != 0) { sd->stc.flags |= STCCMYK10; sd->stc.bits = 10; sd->color_info.depth = 32; } else { sd->stc.flags &= ~STCCMYK10; if((sd->stc.dither->flags & STC_FLOAT) != STC_FLOAT) { fv = 2.0; for(i = 1;(i < gx_color_value_bits) && (fv <= (sd->stc.dither->minmax[1]-sd->stc.dither->minmax[0])); ++i) fv *= 2.0; } else { i = 8; /* arbitrary */ } if((i*sd->color_info.num_components) > (sizeof(stc_pixel)*8)) { sd->stc.bits = (sizeof(stc_pixel)*8) / sd->color_info.num_components; sd->color_info.depth = sd->stc.bits * sd->color_info.num_components; } else { sd->stc.bits = i; sd->color_info.depth = sd->stc.bits * sd->color_info.num_components; } } } } else { code = gs_error_rangecheck; } /* verify new value */ if(code < 0) param_signal_error(plist,"Dithering",code); error = error > code ? code : error; /* * now fetch the desired depth, if the algorithm allows it */ /* * Arrrgh: We get code == 0, even if nobody sets BitsPerPixel. * The value is the old one, but this may cause trouble * with CMYK10. */ code = param_read_int(plist, "BitsPerPixel", &i); if((error == 0) && (code == 0) && (((sd->stc.flags & STCCMYK10) == 0) || (i != sd->color_info.depth))) { if((1 > i) || (i > (sizeof(stc_pixel)*8))) code = gs_error_rangecheck; else sd->color_info.depth = i; sd->stc.bits = i / sd->color_info.num_components; if(1 > sd->stc.bits) code = gs_error_rangecheck; if((sd->stc.dither->flags & STC_DIRECT) && (sd->stc.dither->flags & STC_CMYK10)) code = gs_error_rangecheck; else sd->stc.flags &= ~STCCMYK10; } if(code < 0) param_signal_error(plist,"BitsPerPixel",code); error = error > code ? code : error; /* * Fetch OutputCode */ code = param_read_string(plist,"OutputCode",&ps); if(code == 0) { /* Analyze the OutputCode-String */ for(l = ps.size; (l > 0) && (ps.data[l-1] == 0); --l); sd->stc.flags &= ~STCCOMP; if(!stc_putcmp("plain")) sd->stc.flags |= STCPLAIN; else if(!stc_putcmp("deltarow")) sd->stc.flags |= STCDELTA; } /* Analyze the OutputCode-String */ if((sd->stc.flags & STCCOMP) == STCDELTA) { sd->stc.flags |= STCUWEAVE; sd->stc.flags &= ~STCNWEAVE; } if(code < 0) param_signal_error(plist,"OutputCode",code); error = error > code ? code : error; /* * fetch the weave-mode (noWeave wins) */ b1 = sd->stc.flags & STCUWEAVE ? true : false; b2 = sd->stc.flags & STCNWEAVE ? true : false; b3 = sd->stc.flags & (STCUWEAVE|STCNWEAVE) ? false : true; code = param_read_bool(plist,"Microweave",&b1); if(code < 0) { param_signal_error(plist,"Microweave",code); } else if(code == 0) { if(b1) { b2 = false; b3 = false; } } error = error > code ? code : error; code = param_read_bool(plist,"noWeave",&b2); if(code < 0) { param_signal_error(plist,"noWeave",code); } else if (code == 0) { if(b2) { b1 = false; b3 = false; } } error = error > code ? code : error; code = param_read_bool(plist,"Softweave",&b3); if(code < 0) { param_signal_error(plist,"Softweave",code); } else if (code == 0) { if(b3) { b1 = false; b2 = false; } } error = error > code ? code : error; if(b1) sd->stc.flags |= STCUWEAVE; else sd->stc.flags &= ~STCUWEAVE; if(b2) sd->stc.flags |= STCNWEAVE; else sd->stc.flags &= ~STCNWEAVE; /* * Check the simple Flags */ # define stc_read_flag(Mask,Name) \ code = param_read_bool(plist,Name,&b1); \ if(code < 0) { \ param_signal_error(plist,Name,code); \ } else if(code == 0) { \ if(b1 == true) sd->stc.flags |= Mask; \ else sd->stc.flags &= ~(Mask); \ } \ error = error > code ? code : error; stc_read_flag(STCUNIDIR,"Unidirectional") stc_read_flag(STCDFLAG0, "Flag0") stc_read_flag(STCDFLAG1, "Flag1") stc_read_flag(STCDFLAG2, "Flag2") stc_read_flag(STCDFLAG3, "Flag3") stc_read_flag(STCDFLAG4, "Flag4") /* * Now deal with the escp-Stuff */ # define stc_read_int(Mask,Name,Val) \ code = param_read_int(plist,Name,&Val); \ if(code < 0) \ param_signal_error(plist,Name,code); \ else if(code == 0) \ sd->stc.flags |= Mask; \ error = error > code ? code : error stc_read_int(STCBAND, "escp_Band", sd->stc.escp_m); stc_read_int(STCWIDTH, "escp_Width", sd->stc.escp_width); stc_read_int(STCHEIGHT,"escp_Height",sd->stc.escp_height); stc_read_int(STCTOP, "escp_Top", sd->stc.escp_top); stc_read_int(STCBOTTOM,"escp_Bottom",sd->stc.escp_bottom); # undef stc_read_int code = param_read_string(plist,"escp_Init",&sd->stc.escp_init); if(code == 0) sd->stc.flags |= STCINIT; error = error > code ? code : error; code = param_read_string(plist,"escp_Release",&sd->stc.escp_release); if(code == 0) sd->stc.flags |= STCRELEASE; error = error > code ? code : error; /* * ColorAdjustMatrix must match the required size, * setting it explicitly to null, erases old matrix */ code = param_read_float_array(plist,"ColorAdjustMatrix",&pfa); if((error == 0) && (code == 0)) { if(((sd->color_info.num_components == 1) && (pfa.size == 3)) || ((sd->color_info.num_components == 3) && (pfa.size == 9)) || ((sd->color_info.num_components == 4) && (pfa.size == 16))) sd->stc.am = (float *) pfa.data; else code = gs_error_rangecheck; } else if(code < 0) { code = param_read_null(plist,"ColorAdjustMatrix"); if(code == 0) sd->stc.am = NULL; } if(code < 0) param_signal_error(plist,"ColorAdjustMatrix",code); error = error > code ? code : error; /* * Read the external array-Parameters */ if(sd->color_info.num_components == 1) { /* DeviceGray */ stc_read_xarray(0,"Kcoding","Ktransfer"); stc_read_null("Rcoding"); stc_read_null("Rtransfer"); stc_read_null("Gcoding"); stc_read_null("Gtransfer"); stc_read_null("Bcoding"); stc_read_null("Btransfer"); stc_read_null("Ccoding"); stc_read_null("Ctransfer"); stc_read_null("Mcoding"); stc_read_null("Mtransfer"); stc_read_null("Ycoding"); stc_read_null("Ytransfer"); } else if(sd->color_info.num_components == 3) { /* DeviceRGB */ stc_read_xarray(0,"Rcoding","Rtransfer"); stc_read_xarray(1,"Gcoding","Gtransfer"); stc_read_xarray(2,"Bcoding","Btransfer"); stc_read_null("Ccoding"); stc_read_null("Ctransfer"); stc_read_null("Mcoding"); stc_read_null("Mtransfer"); stc_read_null("Ycoding"); stc_read_null("Ytransfer"); stc_read_null("Kcoding"); stc_read_null("Ktransfer"); } else { /* DeviceCMYK */ stc_read_xarray(0,"Ccoding","Ctransfer"); stc_read_xarray(1,"Mcoding","Mtransfer"); stc_read_xarray(2,"Ycoding","Ytransfer"); stc_read_xarray(3,"Kcoding","Ktransfer"); stc_read_null("Rcoding"); stc_read_null("Rtransfer"); stc_read_null("Gcoding"); stc_read_null("Gtransfer"); stc_read_null("Bcoding"); stc_read_null("Btransfer"); } /* * Update remaining color_info values */ if(error == 0) { /* compute #values from the component-bits */ sd->color_info.max_gray = sd->stc.bits < gx_color_value_bits ? (1<stc.bits)-1 : gx_max_color_value; /* An integer-algorithm might reduce the number of values */ if(((sd->stc.dither->flags & STC_TYPE) != STC_FLOAT) && ((sd->stc.dither->minmax[1]-sd->stc.dither->minmax[0]) < sd->color_info.max_gray)) sd->color_info.max_gray = sd->stc.dither->minmax[1]-sd->stc.dither->minmax[0]+0.5; sd->color_info.max_color = sd->color_info.num_components < 3 ? 0 : sd->color_info.max_gray; sd->color_info.dither_grays = sd->color_info.max_gray < gx_max_color_value ? sd->color_info.max_gray+1 : gx_max_color_value; sd->color_info.dither_colors = sd->color_info.num_components < 3 ? 0 : sd->color_info.dither_grays; } /* * Call superclass-Update */ code = gdev_prn_put_params(pdev, plist); error = error > code ? code : error; /* * Arrrgh, writing BitsPerPixel is really *VERY* special: * gdev_prn_put_params verifies, that the external value * is written, if not, it raises a rangecheck-error. * On the other hand ghostscript is quite unhappy with odd * values, so we do the necessary rounding *AFTER* the * "superclass-Update". */ if(sd->color_info.depth == 3) sd->color_info.depth = 4; else if(sd->color_info.depth > 4) sd->color_info.depth = (sd->color_info.depth+7) & ~7; /* * Allocate the storage for the arrays in memory */ if(error == 0) { /* Allocate new external-arrays */ for(i = 0; i < sd->color_info.num_components; ++i){ /* Active components */ int j; if((sd->stc.extv[i] != oldstc.extv[i]) && (sd->stc.extv[i] != defext )) { /* Value-Arrays */ for(j = 0; j < i; ++j) if((sd->stc.sizv[j] == sd->stc.sizv[i]) && (memcmp(sd->stc.extv[j],sd->stc.extv[i], sd->stc.sizv[i]*sizeof(float)) == 0)) break; if(j < i) { sd->stc.extv[i] = sd->stc.extv[j]; } else { fp = gs_malloc(sd->stc.sizv[i],sizeof(float),"stc_put_params"); if(fp != NULL) memcpy(fp,sd->stc.extv[i],sd->stc.sizv[i]*sizeof(float)); else code = gs_error_VMerror; sd->stc.extv[i] = fp; } } /* Value-Arrays */ if((sd->stc.sizc[i] > 1) && (sd->stc.extc[i] != oldstc.extc[i])) { /* Code-Arrays */ for(j = 0; j < i; ++j) if((sd->stc.sizc[j] == sd->stc.sizc[i]) && (memcmp(sd->stc.extc[j],sd->stc.extc[i], sd->stc.sizc[i]*sizeof(float)) == 0)) break; if(j < i) { sd->stc.extc[i] = sd->stc.extc[j]; } else { fp = gs_malloc(sd->stc.sizc[i],sizeof(float),"stc_put_params"); if(fp != NULL) memcpy(fp,sd->stc.extc[i],sd->stc.sizc[i]*sizeof(float)); else code = gs_error_VMerror; sd->stc.extc[i] = fp; } } /* Code-Arrays */ } /* Active components */ if((sd->stc.am != NULL) && (sd->stc.am != oldstc.am)) { if( sd->color_info.num_components == 1) i = 3; else if(sd->color_info.num_components == 3) i = 9; else i = 16; fp = gs_malloc(i,sizeof(float),"stc_put_params"); if(fp != NULL) memcpy(fp,sd->stc.am,i*sizeof(float)); else code = gs_error_VMerror; sd->stc.am = fp; } if(sd->stc.escp_init.data != oldstc.escp_init.data) { byte *ip = NULL; if(sd->stc.escp_init.size > 0) { ip = gs_malloc(sd->stc.escp_init.size,1,"stcolor/init"); if(ip == NULL) { code = gs_error_VMerror; sd->stc.escp_init.size = 0; } else { memcpy(ip,sd->stc.escp_init.data,sd->stc.escp_init.size); } } sd->stc.escp_init.data = ip; sd->stc.escp_init.persistent = false; } if(sd->stc.escp_release.data != oldstc.escp_release.data) { byte *ip = NULL; if(sd->stc.escp_release.size > 0) { ip = gs_malloc(sd->stc.escp_release.size,1,"stcolor/release"); if(ip == NULL) { code = gs_error_VMerror; sd->stc.escp_release.size = 0; } else { memcpy(ip,sd->stc.escp_release.data,sd->stc.escp_release.size); } } sd->stc.escp_release.data = ip; sd->stc.escp_release.persistent = false; } if(code < 0) { /* free newly allocated arrays */ if((sd->stc.am != NULL) && (sd->stc.am != oldstc.am)) { if( sd->color_info.num_components == 1) i = 3; else if(sd->color_info.num_components == 3) i = 9; else i = 16; gs_free(sd->stc.am,i,sizeof(float),"stc_put_params"); } if((sd->stc.escp_init.data != NULL) && (sd->stc.escp_init.data != oldstc.escp_init.data)) gs_free((byte *) sd->stc.escp_init.data,sd->stc.escp_init.size,1, "stcolor/init"); if((sd->stc.escp_release.data != NULL) && (sd->stc.escp_release.data != oldstc.escp_release.data)) gs_free((byte *) sd->stc.escp_release.data,sd->stc.escp_release. size,1,"stcolor/release"); for(i = 0; i < sd->color_info.num_components; ++i) { /* components */ int j; if((sd->stc.extc[i] != NULL) && (sd->stc.extc[i] != defext) && (sd->stc.extc[i] != oldstc.extc[i])) { for(j = 0; j < i; ++j) if(sd->stc.extc[i] == sd->stc.extc[j]) break; if(i == j) gs_free(sd->stc.extc[i],sd->stc.sizc[i],sizeof(float), "stc_put_params"); } if((sd->stc.extv[i] != NULL) && (sd->stc.extv[i] != oldstc.extv[i]) && (sd->stc.extv[i] != defext)) { for(j = 0; j < i; ++j) if(sd->stc.extv[i] == sd->stc.extv[j]) break; if(i == j) gs_free(sd->stc.extv[i],sd->stc.sizv[i],sizeof(float), "stc_put_params"); } } /* components */ } /* free newly allocated arrays */ } /* Allocate new arrays */ error = error > code ? code : error; /* * finally decide upon restore or release of old, unused data */ if(error != 0) { /* Undo changes */ memcpy(&sd->color_info,&oldcolor,sizeof(oldcolor)); memcpy(&sd->stc ,&oldstc ,sizeof(oldstc )); } else { /* undo / release */ if((oldstc.escp_init.data != NULL) && (oldstc.escp_init.data != sd->stc.escp_init.data)) { gs_free((byte *)oldstc.escp_init.data, oldstc.escp_init.size,1,"stcolor/init"); } if((oldstc.escp_release.data != NULL) && (oldstc.escp_release.data != sd->stc.escp_release.data)) { gs_free((byte *)oldstc.escp_release.data, oldstc.escp_release.size,1,"stcolor/release"); } if((oldstc.am != NULL) && (oldstc.am != sd->stc.am)) { if( oldcolor.num_components == 1) i = 3; else if(oldcolor.num_components == 3) i = 9; else i = 16; gs_free(oldstc.am,i,sizeof(float),"stc_put_params"); } for(i = 0; i < 4; ++i) { int j; if((oldstc.extc[i] != NULL) && (oldstc.extc[i] != sd->stc.extc[i]) && (oldstc.dither != NULL) && (oldstc.extc[i] != defext)) { for(j = 0; j < i; ++j) if(oldstc.extc[i] == oldstc.extc[j]) break; if(i == j) gs_free(oldstc.extc[i],oldstc.sizc[i],sizeof(float), "stc_put_params"); } if((oldstc.extv[i] != NULL) && (oldstc.extv[i] != sd->stc.extv[i]) && (oldstc.extv[i] != defext)) { for(j = 0; j < i; ++j) if(oldstc.extv[i] == oldstc.extv[j]) break; if(i == j) gs_free(oldstc.extv[i],oldstc.sizv[i],sizeof(float), "stc_put_params"); } } /* * Close the device if colormodel changed or recomputation * of internal arrays is required */ if(sd->is_open) { /* we might need to close it */ bool doclose = false; if((sd->color_info.num_components != oldcolor.num_components) || (sd->color_info.depth != oldcolor.depth ) || (sd->stc.bits != oldstc.bits ) || (sd->stc.dither != oldstc.dither )) doclose = true; for(i = 0; i < sd->color_info.num_components; ++i) { if(sd->stc.extv[i] != oldstc.extv[i]) doclose = true; if(sd->stc.extc[i] != oldstc.extc[i]) doclose = true; } if(doclose) { stc_freedata(&oldstc); for(i = 0; i < 4; ++i) { sd->stc.vals[i] = NULL; sd->stc.code[i] = NULL; } gs_closedevice(pdev); } } /* we might need to close it */ } return error; } /* * 1Bit CMYK-Algorithm */ private int stc_gscmyk(stcolor_device *sdev,int npixel,byte *in,byte *buf,byte *out) { byte *ip = in; int error = 0; /* ============================================================= */ if(npixel > 0) { /* npixel > 0 -> scanline-processing */ /* ============================================================= */ int p; /* * simply split the two pixels rsiding in a byte */ for(p = npixel; p > 0; --p) { /* loop over pixels */ byte tmp =*ip++; *out++ = (tmp>>4) & 15; if(--p <= 0) break; *out++ = tmp & 15; } /* loop over pixels */ /* ============================================================= */ } else { /* npixel <= 0 -> initialisation */ /* ============================================================= */ /* we didn't check for the white-calls above, so this may cause errors */ if(sdev->stc.dither->flags & STC_WHITE) error = -1; /* if we're not setup for bytes, this is an error too */ if((sdev->stc.dither->flags & STC_TYPE) != STC_BYTE) error = -2; /* This IS a direct-driver, so STC_DIRECT must be set! */ if((sdev->stc.dither->flags & STC_DIRECT) == 0) error = -3; /* and cmyk-mode is the only supported mode */ if(sdev->color_info.num_components != 4) error = -4; /* and we support only 4Bit-Depth here */ if(sdev->color_info.depth != 4) error = -5; /* ============================================================= */ } /* scanline-processing or initialisation */ /* ============================================================= */ return error; } /* * The following is an algorithm under test */ private int stc_hscmyk(stcolor_device *sdev,int npixel,byte *in,byte *buf,byte *out) { /* ============================================================= */ if(npixel < 0) { /* npixel <= 0 -> initialisation */ /* ============================================================= */ int i,i2do; long *lp = (long *) buf; /* CMYK-only algorithm */ if( sdev->color_info.num_components != 4) return -1; /* * check wether stcdither & TYPE are correct */ if(( sdev->stc.dither == NULL) || ((sdev->stc.dither->flags & STC_TYPE) != STC_LONG)) return -2; /* * check wether the buffer-size is sufficiently large */ if(((sdev->stc.dither->flags/STC_SCAN) < 1) || ( sdev->stc.dither->bufadd < (1 + 2*sdev->color_info.num_components))) return -3; /* * must have STC_CMYK10, STC_DIRECT, but not STC_WHITE */ if((sdev->stc.dither->flags & STC_CMYK10) == 0) return -4; if((sdev->stc.dither->flags & STC_DIRECT) == 0) return -5; if((sdev->stc.dither->flags & STC_WHITE ) != 0) return -6; /* * Must have values between 0-1023.0 */ if((sdev->stc.dither->minmax[0] != 0.0) || (sdev->stc.dither->minmax[1] != 1023.0)) return -7; /* * initialize buffer */ i2do = 1 + 8 - 4 * npixel; lp[0] = 0; if(sdev->stc.flags & STCDFLAG0) { for(i = 1; i < i2do; ++i) lp[i] = 0; } else { for(i = 1; i < i2do; ++i) lp[i] = (rand() % 381) - 190; } /* ============================================================= */ } else { /* npixel > 0 && in != NULL -> scanline-processing */ /* ============================================================= */ long errc[4],*errv; int step = buf[0] ? -1 : 1; stc_pixel *ip = (stc_pixel *) in; buf[0] = ~ buf[0]; errv = (long *) buf + 5; if(step < 0) { ip += npixel-1; out += npixel-1; errv += 4*(npixel-1); } errc[0] = 0; errc[1] = 0; errc[2] = 0; errc[3] = 0; while(npixel-- > 0) { register stc_pixel ci,mode; register long k,v,n; register int pixel; /* internal pixel-value */ ci = *ip; ip += step; mode = ci & 3; k = (ci>>2) & 0x3ff; pixel = 0; v = k+errv[3]+((7*errc[3])>>4); if(mode == 3) { /* only Black allowed to fire */ if(v > 511) { v -= 1023; pixel = BLACK; } errv[3-(step<<2)] += ((3*v+8)>>4); /* 3/16 */ errv[3] = ((5*v+errc[3]+8)>>4);/* 5/16 +1/16 (rest) */ errc[3] = v; errv[0] = errv[0] < -190 ? -190 : errv[0] < 190 ? errv[0] : 190; errv[1] = errv[1] < -190 ? -190 : errv[1] < 190 ? errv[1] : 190; errv[2] = errv[2] < -190 ? -190 : errv[2] < 190 ? errv[2] : 190; errc[0] = 0; errc[1] = 0; errc[2] = 0; } else if(v > 511) { /* black known to fire */ v -= 1023; pixel = BLACK; errv[3-(step<<2)] += ((3*v+8)>>4); /* 3/16 */ errv[3] = ((5*v+errc[3]+8)>>4);/* 5/16 +1/16 (rest) */ errc[3] = v; n = (ci>>12) & 0x3ff; if(mode == 2) { v = k; } else { v = n; n = (ci>>22) & 0x3ff; } v += errv[2]+((7*errc[2])>>4)-1023; if(v < -511) v = -511; errv[2-(step<<2)] += ((3*v+8)>>4); /* 3/16 */ errv[2] = ((5*v+errc[2]+8)>>4);/* 5/16 +1/16 (rest) */ errc[2] = v; if(mode == 1) { v = k; } else { v = n; n = (ci>>22) & 0x3ff; } v += errv[1]+((7*errc[1])>>4)-1023; if(v < -511) v = -511; errv[1-(step<<2)] += ((3*v+8)>>4); /* 3/16 */ errv[1] = ((5*v+errc[1]+8)>>4);/* 5/16 +1/16 (rest) */ errc[1] = v; if(mode == 0) v = k; else v = n; v += errv[0]+((7*errc[0])>>4)-1023; if(v < -511) v = -511; errv[0-(step<<2)] += ((3*v+8)>>4); /* 3/16 */ errv[0] = ((5*v+errc[0]+8)>>4);/* 5/16 +1/16 (rest) */ errc[0] = v; } else { /* Black does not fire initially */ long kv = v; /* Black computed after colors */ n = (ci>>12) & 0x3ff; if(mode == 2) { v = k; } else { v = n; n = (ci>>22) & 0x3ff; } v += errv[2]+((7*errc[2])>>4); if(v > 511) { pixel |= YELLOW; v -= 1023; } errv[2-(step<<2)] += ((3*v+8)>>4); /* 3/16 */ errv[2] = ((5*v+errc[2]+8)>>4);/* 5/16 +1/16 (rest) */ errc[2] = v; if(mode == 1) { v = k; } else { v = n; n = (ci>>22) & 0x3ff; } v += errv[1]+((7*errc[1])>>4); if(v > 511) { pixel |= MAGENTA; v -= 1023; } errv[1-(step<<2)] += ((3*v+8)>>4); /* 3/16 */ errv[1] = ((5*v+errc[1]+8)>>4);/* 5/16 +1/16 (rest) */ errc[1] = v; if(mode == 0) v = k; else v = n; v += errv[0]+((7*errc[0])>>4); if(v > 511) { pixel |= CYAN; v -= 1023; } errv[0-(step<<2)] += ((3*v+8)>>4); /* 3/16 */ errv[0] = ((5*v+errc[0]+8)>>4);/* 5/16 +1/16 (rest) */ errc[0] = v; v = kv; if(pixel == (CYAN|MAGENTA|YELLOW)) { pixel = BLACK; v = v > 511 ? v-1023 : -511; } errv[3-(step<<2)] += ((3*v+8)>>4); /* 3/16 */ errv[3] = ((5*v+errc[3]+8)>>4);/* 5/16 +1/16 (rest) */ errc[3] = v; } errv += step<<2; *out = pixel; out += step; } /* loop over pixels */ /* ============================================================= */ } /* initialisation, white or scanline-processing */ /* ============================================================= */ return 0; }