ref: ec35f468e0eba87c9f09cbbe5fa8af2591e6f914
dir: /appl/lib/print/hp_driver.b/
implement Pdriver; include "sys.m"; sys: Sys; include "draw.m"; draw: Draw; Display, Font, Rect, Point, Image, Screen: import draw; include "bufio.m"; bufio: Bufio; Iobuf: import bufio; include "print.m"; Printer: import Print; include "scaler.m"; scaler: Scaler; K: con 0; C: con 1; M: con 2; Y: con 3; Clight: con 4; Mlight: con 5; HPTRUE: con 1; HPFALSE: con 0; TRUE: con 1; FALSE: con 0; # RGB pixel RGB: adt { r, g, b: byte; }; # KCMY pixel KCMY: adt { k, c, m, y: byte; }; DitherParms: adt { fNumPix: int; fInput: array of byte; fErr: array of int; fSymmetricFlag: int; fFEDRes: array of int; fRasterEvenOrOdd: int; fHifipe: int; fOutput1, fOutput2, fOutput3: array of byte; }; # magic and wondrous HP colour maps map1: array of KCMY; map2: array of KCMY; ABSOLUTE: con 1; RELATIVE: con 0; Compression := 1; DEBUG := 0; stderr: ref Sys->FD; outbuf: ref Iobuf; ESC: con 27; # Palettes for Simple_Color PALETTE_RGB: con 3; PALETTE_CMY: con -3; PALETTE_KCMY: con -4; PALETTE_K: con 1; # Initialization init(debug: int) { sys = load Sys Sys->PATH; stderr = sys->fildes(2); draw = load Draw Draw->PATH; bufio = load Bufio Bufio->PATH; scaler = load Scaler Scaler->PATH; if (scaler == nil) fatal("Failed to load Scaler module"); DEBUG = debug; } # Return printable area in pixels printable_pixels(p: ref Printer): (int, int) { HMARGIN: con 0.6; WMARGIN: con 0.3; winches := p.popt.paper.width_inches - 2.0*WMARGIN; hinches := p.popt.paper.height_inches - 2.0*HMARGIN; wres := real p.popt.mode.resx; hres := real p.popt.mode.resy; (x, y) := (int (winches*wres), int (hinches*hres)); if (p.popt.orientation == Print->PORTRAIT) return (x, y); return (y, x); } # Send image to printer MASK := array[] of {byte 1, byte 3, byte 15, byte 255, byte 255}; SHIFT := array[] of {7, 6, 4, 0}; GSFACTOR := array[] of {255.0, 255.0/3.0, 255.0/7.0, 1.0, 1.0}; lastp : ref Printer; Refint: adt { value: int; }; watchdog(cancel: chan of int, cancelled: ref Refint) { <- cancel; cancelled.value = 1; } sendimage(p: ref Printer, pfd: ref Sys->FD, display: ref Draw->Display, im: ref Draw->Image, width: int, lmargin: int, cancel: chan of int): int { grppid := sys->pctl(Sys->NEWPGRP, nil); cancelled := ref Refint(0); spawn watchdog(cancel, cancelled); outopen(pfd); dbg(sys->sprint("image depth=%d from %d,%d to %d,%d\n", im.depth, im.r.min.x, im.r.min.y, im.r.max.x, im.r.max.y)); if (p != lastp) { (map1, map2) = readmaps(p); lastp = p; } bpp := im.depth; linechan := chan of array of int; if (p.popt.orientation == Print->PORTRAIT) InputWidth := im.r.max.x-im.r.min.x; else InputWidth = im.r.max.y-im.r.min.y; AdjustedInputWidth := (InputWidth+7) - ((InputWidth+7) % 8); dbg(sys->sprint("bpp=%d, InputWidth=%d, AdjustedInputWidth=%d\n", bpp, InputWidth, AdjustedInputWidth)); if (p.popt.orientation == Print->PORTRAIT) spawn row_by_row(im, linechan, AdjustedInputWidth); else spawn rotate(im, linechan, AdjustedInputWidth); DesiredOutputWidth := AdjustedInputWidth; if (width > AdjustedInputWidth) DesiredOutputWidth = width; ScaledWidth := 8*((DesiredOutputWidth)/8); mode := p.popt.mode; Nplanes := 4; if (map2 != nil) Nplanes += 2; Contone := array[Nplanes] of array of byte; ColorDepth := array[Nplanes] of int; ColorDepth[K] = mode.blackdepth; for (col:=1; col<Nplanes; col++) ColorDepth[col] = mode.coldepth; OutputWidth := array[Nplanes] of int; fDitherParms := array[Nplanes] of DitherParms; ErrBuff := array[Nplanes] of array of int; ColorPlane := array[Nplanes] of array of array of array of byte; MixedRes := 0; BaseResX := mode.resx; BaseResY := mode.resy; ResBoost := BaseResX / BaseResY; ResolutionX := array[Nplanes] of int; ResolutionY := array[Nplanes] of int; ResolutionX[K] = mode.resx*mode.blackresmult; ResolutionY[K] = mode.resy*mode.blackresmult; for (col=1; col<Nplanes; col++) { ResolutionX[col] = mode.resx; ResolutionY[col] = mode.resy; } NumRows := array[Nplanes] of int; for (j:=0; j<Nplanes; j++) { if (ResolutionX[j] != ResolutionX[K]) MixedRes++; if (MixedRes) # means res(K) !+ res(C,M,Y) NumRows[j] = ResolutionX[j] / BaseResX; else NumRows[j]=1; OutputWidth[j]= ScaledWidth * NumRows[j] * ResBoost; PlaneSize:= OutputWidth[j]/8; Contone[j] = array[OutputWidth[j]] of byte; ColorPlane[j] = array[NumRows[j]] of array of array of byte; for (jj:=0; jj<NumRows[j]; jj++) { ColorPlane[j][jj] = array[ColorDepth[j]] of array of byte; for (jjj:=0; jjj<ColorDepth[j]; jjj++) { ColorPlane[j][jj][jjj] = array[PlaneSize] of byte; } } ErrBuff[j] = array[OutputWidth[j]+2] of {* => 0}; } pcl_startjob(p); if (p.popt.paper.hpcode != "") PCL_Page_Size(p.popt.paper.hpcode); PCL_Move_CAP_H_Units(lmargin*300/BaseResX, ABSOLUTE); PCL_Configure_Raster_Data4(BaseResX, BaseResY, ColorDepth); PCL_Source_Raster_Width(ScaledWidth); PCL_Compression_Method(Compression); PCL_Start_Raster(1); cmap1 := setup_color_map(display, map1, im.depth); if (map2 != nil) cmap2 := setup_color_map(display, map2, im.depth); numerator, denominator: int; if ((ScaledWidth % AdjustedInputWidth)==0) { numerator = ScaledWidth / AdjustedInputWidth; denominator = 1; } else { numerator = ScaledWidth; denominator = AdjustedInputWidth; } rs := scaler->init(DEBUG, AdjustedInputWidth, numerator, denominator); rasterno := 0; col_row: array of int; eof := 0; while (!eof) { col_row = <- linechan; if (col_row == nil) eof++; scaler->rasterin(rs, col_row); while ((scaled_col_row := scaler->rasterout(rs)) != nil) { rasterno++; fRasterOdd := rasterno & 1; kcmy_row := SimpleColorMatch(cmap1, scaled_col_row); if (DEBUG) { dbg("Scaled Raster line:"); for (q:=0; q<len scaled_col_row; q++) { (r, g, b) := display.cmap2rgb(scaled_col_row[q]); dbg(sys->sprint("%d rgb=(%d,%d,%d) kcmy=(%d,%d,%d,%d)\n", int scaled_col_row[q], r, g, b, int kcmy_row[q].k, int kcmy_row[q].c, int kcmy_row[q].m, int kcmy_row[q].y)); } dbg("\n"); } Contone_K := Contone[K]; Contone_C := Contone[C]; Contone_M := Contone[M]; Contone_Y := Contone[Y]; for (ii:=0; ii<len Contone[K]; ii++) { kcmy := kcmy_row[ii]; Contone_K[ii] = kcmy.k; Contone_C[ii] = kcmy.c; Contone_M[ii] = kcmy.m; Contone_Y[ii] = kcmy.y; } if (map2 != nil) { # For lighter inks kcmy_row_light := SimpleColorMatch(cmap2, scaled_col_row); Contone_Clight := Contone[Clight]; Contone_Mlight := Contone[Mlight]; for (ii=0; ii<len Contone[Clight]; ii++) { kcmy := kcmy_row_light[ii]; Contone_Clight[ii] = kcmy.c; Contone_Mlight[ii] = kcmy.m; } } for (i:=0; i< Nplanes; i++) { # Pixel multiply here!! fDitherParms[i].fNumPix = OutputWidth[i]; fDitherParms[i].fInput = Contone[i]; fDitherParms[i].fErr = ErrBuff[i]; # fDitherParms[i].fErr++; // serpentine (?) fDitherParms[i].fSymmetricFlag = 1; # if (i == K) # fDitherParms[i].fFEDResPtr = fBlackFEDResPtr; # else # fDitherParms[i].fFEDResPtr = fColorFEDResPtr; fDitherParms[i].fFEDRes = FEDarray; fDitherParms[i].fRasterEvenOrOdd = fRasterOdd; fDitherParms[i].fHifipe = ColorDepth[i] > 1; for (j=0; j < NumRows[i]; j++) { fDitherParms[i].fOutput1 = ColorPlane[i][j][0]; if (fDitherParms[i].fHifipe) fDitherParms[i].fOutput2 = ColorPlane[i][j][1]; # dbg(sys->sprint("Dither for Row %d ColorPlane[%d][%d]\n", rasterno, i, j)); Dither(fDitherParms[i]); } } FINALPLANE: con 3; # NfinalPlanes := 4; for (i=0; i<=FINALPLANE; i++) { cp_i := ColorPlane[i]; coldepth_i := ColorDepth[i]; finalrow := NumRows[i]-1; for (j=0; j<=finalrow; j++) { cp_i_j := cp_i[j]; for (k:=0; k<coldepth_i; k++) { if (i == FINALPLANE && j == finalrow && k == coldepth_i-1) PCL_Transfer_Raster_Row(cp_i_j[k]); else PCL_Transfer_Raster_Plane(cp_i_j[k]); if (cancelled.value) { PCL_Reset(); outclose(); killgrp(grppid); return -1; } } } } } } PCL_End_Raster(); PCL_Reset(); outclose(); killgrp(grppid); if (cancelled.value) return -1; #sys->print("dlen %d, clen %d overruns %d\n", dlen, clen, overruns); return 0; } # Send text to printer sendtextfd(p: ref Print->Printer, pfd, tfd: ref Sys->FD, pointsize: real, proportional: int, wrap: int): int { outopen(pfd); pcl_startjob(p); if (wrap) PCL_End_of_Line_Wrap(0); LATIN1: con "0N"; PCL_Font_Symbol_Set(LATIN1); if (proportional) PCL_Font_Spacing(1); if (pointsize > 0.0) { PCL_Font_Height(pointsize); pitch := 10.0*12.0/pointsize; PCL_Font_Pitch(pitch); spacing := int (6.0*12.0/pointsize); PCL_Line_Spacing(spacing); dbg(sys->sprint("Text: pointsize %f pitch %f spacing %d\n", pointsize, pitch, spacing)); } PCL_Line_Termination(3); inbuf := bufio->fopen(tfd, Bufio->OREAD); while ((line := inbuf.gets('\n')) != nil) { ob := array of byte line; outwrite(ob, len ob); } PCL_Reset(); outclose(); return 0; } # Common PCL start pcl_startjob(p: ref Printer) { PCL_Reset(); if (p.popt.duplex) { esc("%-12345X@PJL DEFAULT DUPLEX=ON\n"); esc("%-12345X"); } if (p.popt.paper.hpcode != "") PCL_Page_Size(p.popt.paper.hpcode); PCL_Orientation(p.popt.orientation); PCL_Duplex(p.popt.duplex); } # Spawned to return sequence of rotated image rows rotate(im: ref Draw->Image, linechan: chan of array of int, adjwidth: int) { xmin := im.r.min.x; xmax := im.r.max.x; InputWidth := xmax - xmin; rawchan := chan of array of int; spawn row_by_row(im, rawchan, InputWidth); r_image := array[InputWidth] of {* => array [adjwidth] of {* => 0}}; r_row := 0; while ((col_row := <- rawchan) != nil) { endy := len col_row - 1; for (i:=0; i<len col_row; i++) r_image[endy - i][r_row] = col_row[i]; r_row++; } for (i:=0; i<len r_image; i++) linechan <-= r_image[i]; linechan <-= nil; } # Spawned to return sequence of image rows row_by_row(im: ref Draw->Image, linechan: chan of array of int, adjwidth: int) { xmin := im.r.min.x; ymin := im.r.min.y; xmax := im.r.max.x; ymax := im.r.max.y; InputWidth := xmax - xmin; bpp := im.depth; ld := ldepth(im.depth); bytesperline := (InputWidth*bpp+7)/8; rdata := array[bytesperline+10] of byte; pad0 := array [7] of { * => 0}; for (y:=ymin; y<ymax; y++) { col_row := array[adjwidth] of int; rect := Rect((xmin, y), (xmax, y+1)); np := im.readpixels(rect, rdata); if (np < 0) fatal("Error reading image\n"); dbg(sys->sprint("Input Raster line %d: np=%d\n ", y, np)); ind := 0; mask := MASK[ld]; shift := SHIFT[ld]; col_row[adjwidth-7:] = pad0; # Pad to adjusted width with white data := rdata[ind]; for (q:=0; q<InputWidth; q++) { col := int ((data >> shift) & mask); shift -= bpp; if (shift < 0) { shift = SHIFT[ld]; ind++; data = rdata[ind]; } col_row[q] = col; } linechan <-= col_row; } linechan <-= nil; } # PCL output routines PCL_Reset() { esc("E"); } PCL_Orientation(value: int) { esc(sys->sprint("&l%dO", value)); } PCL_Duplex(value: int) { esc(sys->sprint("&l%dS", value)); } PCL_Left_Margin(value: int) { esc(sys->sprint("&a%dL", value)); } PCL_Page_Size(value: string) { esc(sys->sprint("&l%sA", value)); } PCL_End_of_Line_Wrap(value: int) { esc(sys->sprint("&s%dC", value)); } PCL_Line_Termination(value: int) { esc(sys->sprint("&k%dG", value)); } PCL_Font_Symbol_Set(value: string) { esc(sys->sprint("(%s", value)); } PCL_Font_Pitch(value: real) { esc(sys->sprint("(s%2.2fH", value)); } PCL_Font_Spacing(value: int) { esc(sys->sprint("(s%dP", value)); } PCL_Font_Height(value: real) { esc(sys->sprint("(s%2.2fV", value)); } PCL_Line_Spacing(value: int) { esc(sys->sprint("&l%dD", value)); } PCL_Start_Raster(current: int) { flag := 0; if (current) flag = 1; esc(sys->sprint("*r%dA", flag)); } PCL_End_Raster() { esc("*rC"); } PCL_Raster_Resolution(ppi: int) { esc(sys->sprint("*t%dR", ppi)); } PCL_Source_Raster_Width(pixels: int) { esc(sys->sprint("*r%dS", pixels)); } PCL_Simple_Color(palette: int) { esc(sys->sprint("*r%dU", palette)); } PCL_Compression_Method(ctype: int) { esc(sys->sprint("*b%dM", ctype)); } PCL_Move_CAP_V_Rows(pos: int, absolute: int) { plus := ""; if (!absolute && pos > 0) plus = "+"; esc(sys->sprint("&a%s%dR", plus, pos)); } PCL_Move_CAP_H_Cols(pos: int, absolute: int) { plus := ""; if (!absolute && pos > 0) plus = "+"; esc(sys->sprint("&a%s%dC", plus, pos)); } # These Units are 1/300 of an inch. PCL_Move_CAP_H_Units(pos: int, absolute: int) { plus := ""; if (!absolute && pos > 0) plus = "+"; esc(sys->sprint("*p%s%dX", plus, pos)); } PCL_Move_CAP_V_Units(pos: int, absolute: int) { plus := ""; if (!absolute && pos > 0) plus = "+"; esc(sys->sprint("*p%s%dY", plus, pos)); } PCL_Configure_Raster_Data4(hres, vres: int, ColorDepth: array of int) { ncomponents := 4; msg := array[ncomponents*6 + 2] of byte; i := 0; msg[i++] = byte 2; # Format msg[i++] = byte ncomponents; # KCMY for (c:=0; c<ncomponents; c++) { msg[i++] = byte (hres/256); msg[i++] = byte (hres%256); msg[i++] = byte (vres/256); msg[i++] = byte (vres%256); depth := 1 << ColorDepth[c]; msg[i++] = byte (depth/256); msg[i++] = byte (depth%256); } if (DEBUG) { dbg("CRD: "); for (ii:=0; ii<len msg; ii++) dbg(sys->sprint("%d(%x) ", int msg[ii], int msg[ii])); dbg("\n"); } esc(sys->sprint("*g%dW", len msg)); outwrite(msg, len msg); } dlen := 0; clen := 0; overruns := 0; PCL_Transfer_Raster_Plane(data: array of byte) { if (DEBUG) { dbg("Transfer_Raster_Plane:"); for (i:=0; i<len data; i++) dbg(sys->sprint(" %x", int data[i])); dbg("\n"); } if (Compression) { d := len data; dlen += d; data = compress(data); c := len data; clen += c; if (c > d) overruns += c-d; if (DEBUG) { dbg("Compressed Transfer_Raster_Plane:"); for (i:=0; i<len data; i++) dbg(sys->sprint(" %x", int data[i])); dbg("\n"); } } esc(sys->sprint("*b%dV", len data)); outwrite(data, len data); } PCL_Transfer_Raster_Row(data: array of byte) { if (DEBUG) { dbg("Transfer_Raster_Row:"); for (i:=0; i<len data; i++) dbg(sys->sprint(" %x", int data[i])); dbg("\n"); } if (Compression) { data = compress(data); if (DEBUG) { dbg("Compressed Transfer_Raster_Row:"); for (i:=0; i<len data; i++) dbg(sys->sprint(" %x", int data[i])); dbg("\n"); } } esc(sys->sprint("*b%dW", len data)); outwrite(data, len data); } outopen(fd: ref Sys->FD) { outbuf = bufio->fopen(fd, Bufio->OWRITE); if (outbuf == nil) sys->fprint(stderr, "Failed to open output fd: %r\n"); } outclose() { outbuf.close(); } # Write to output using buffered io outwrite(data: array of byte, length: int) { outbuf.write(data, length); } # Send escape code to printer esc(s: string) { os := sys->sprint("%c%s", ESC, s); ob := array of byte os; outwrite(ob, len ob); } # Read all the maps readmaps(p: ref Printer): (array of KCMY, array of KCMY) { mapfile := p.ptype.hpmapfile; mapf1 := Pdriver->DATAPREFIX + mapfile + ".map"; m1 := read_map(mapf1); if (m1 == nil) fatal("Failed to read map file"); mapf2 := Pdriver->DATAPREFIX + mapfile + "_2.map"; m2 := read_map(mapf2); return (m1, m2); } # Read a map file read_map(mapfile: string) : array of KCMY { mf := bufio->open(mapfile, bufio->OREAD); if (mf == nil) return nil; CUBESIZE: con 9*9*9; marray := array[CUBESIZE] of KCMY; i := 0; while (i <CUBESIZE && (lstr := bufio->mf.gets('\n')) != nil) { (n, toks) := sys->tokenize(lstr, " \t"); if (n >= 4) { marray[i].k = byte int hd toks; toks = tl toks; marray[i].c = byte int hd toks; toks = tl toks; marray[i].m = byte int hd toks; toks = tl toks; marray[i].y = byte int hd toks; i++; } } return marray; } # Big interpolation routine # static data prev := RGB (byte 255, byte 255, byte 255); result: KCMY; offset := array[] of { 0, 1, 9, 10, 81, 82, 90, 91 }; Interpolate(map: array of KCMY, start: int, rgb: RGB, firstpixel: int): KCMY { cyan := array[8] of int; magenta := array[8] of int; yellow := array[8] of int; black := array[8] of int; if (firstpixel || prev.r != rgb.r || prev.g != rgb.g || prev.b != rgb.b) { prev = rgb; for (j:=0; j<8; j++) { ioff := start+offset[j]; cyan[j] = int map[ioff].c; magenta[j] = int map[ioff].m; yellow[j] = int map[ioff].y; black[j] = int map[ioff].k; } diff_red := int rgb.r & 16r1f; diff_green := int rgb.g & 16r1f; diff_blue := int rgb.b & 16r1f; result.c = byte (((cyan[0] + ( ( (cyan[4] - cyan[0] ) * diff_red) >> 5)) + ( ( ((cyan[2] + ( ( (cyan[6] - cyan[2] ) * diff_red) >> 5)) -(cyan[0] + ( ( (cyan[4] - cyan[0] ) * diff_red) >> 5)) ) * diff_green) >> 5)) + ( ( (((cyan[1] + ( ( (cyan[5] - cyan[1] ) * diff_red) >> 5)) + ( ( ((cyan[3] + ( ( (cyan[7] - cyan[3] ) * diff_red) >> 5)) -(cyan[1] + ( ( (cyan[5] - cyan[1] ) * diff_red) >> 5)) ) * diff_green) >> 5)) -((cyan[0] + ( ( (cyan[4] - cyan[0] ) * diff_red) >> 5)) + ( ( ((cyan[2] + ( ( (cyan[6] - cyan[2] ) * diff_red) >> 5)) -(cyan[0] + ( ( (cyan[4] - cyan[0] ) * diff_red) >> 5)) ) * diff_green) >> 5)) ) * diff_blue) >> 5)); result.m = byte (((magenta[0] + ( ( (magenta[4] - magenta[0] ) * diff_red) >> 5)) + ( ( ((magenta[2] + ( ( (magenta[6] - magenta[2] ) * diff_red) >> 5)) -(magenta[0] + ( ( (magenta[4] - magenta[0] ) * diff_red) >> 5)) ) * diff_green) >> 5)) + ( ( (((magenta[1] + ( ( (magenta[5] - magenta[1] ) * diff_red) >> 5)) + ( ( ((magenta[3] + ( ( (magenta[7] - magenta[3] ) * diff_red) >> 5)) -(magenta[1] + ( ( (magenta[5] - magenta[1] ) * diff_red) >> 5)) ) * diff_green) >> 5)) -((magenta[0] + ( ( (magenta[4] - magenta[0] ) * diff_red) >> 5)) + ( ( ((magenta[2] + ( ( (magenta[6] - magenta[2] ) * diff_red) >> 5)) -(magenta[0] + ( ( (magenta[4] - magenta[0] ) * diff_red) >> 5)) ) * diff_green) >> 5)) ) * diff_blue) >> 5)); result.y = byte (((yellow[0] + ( ( (yellow[4] - yellow[0] ) * diff_red) >> 5)) + ( ( ((yellow[2] + ( ( (yellow[6] - yellow[2] ) * diff_red) >> 5)) -(yellow[0] + ( ( (yellow[4] - yellow[0] ) * diff_red) >> 5)) ) * diff_green) >> 5)) + ( ( (((yellow[1] + ( ( (yellow[5] - yellow[1] ) * diff_red) >> 5)) + ( ( ((yellow[3] + ( ( (yellow[7] - yellow[3] ) * diff_red) >> 5)) -(yellow[1] + ( ( (yellow[5] - yellow[1] ) * diff_red) >> 5)) ) * diff_green) >> 5)) -((yellow[0] + ( ( (yellow[4] - yellow[0] ) * diff_red) >> 5)) + ( ( ((yellow[2] + ( ( (yellow[6] - yellow[2] ) * diff_red) >> 5)) -(yellow[0] + ( ( (yellow[4] - yellow[0] ) * diff_red) >> 5)) ) * diff_green) >> 5)) ) * diff_blue) >> 5)); result.k = byte (((black[0] + ( ( (black[4] - black[0] ) * diff_red) >> 5)) + ( ( ((black[2] + ( ( (black[6] - black[2] ) * diff_red) >> 5)) -(black[0] + ( ( (black[4] - black[0] ) * diff_red) >> 5)) ) * diff_green) >> 5)) + ( ( (((black[1] + ( ( (black[5] - black[1] ) * diff_red) >> 5)) + ( ( ((black[3] + ( ( (black[7] - black[3] ) * diff_red) >> 5)) -(black[1] + ( ( (black[5] - black[1] ) * diff_red) >> 5)) ) * diff_green) >> 5)) -((black[0] + ( ( (black[4] - black[0] ) * diff_red) >> 5)) + ( ( ((black[2] + ( ( (black[6] - black[2] ) * diff_red) >> 5)) -(black[0] + ( ( (black[4] - black[0] ) * diff_red) >> 5)) ) * diff_green) >> 5)) ) * diff_blue) >> 5)); } return result; } # Colour RGB to KCMY convertor ColorMatch(map: array of KCMY, row: array of RGB): array of KCMY { kcmy := array[len row] of KCMY; first := 1; for (i:=0; i<len row; i++) { r := int row[i].r; g := int row[i].g; b := int row[i].b; start := ((r & 16re0) << 1) + ((r & 16re0) >> 1) + (r >> 5) + ((g & 16re0) >> 2) + (g >> 5) + (b >> 5); kcmy[i] = Interpolate(map, start, row[i], first); # dbg(sys->sprint("+++ for (%d,%d,%d) Interpolate returned (%d,%d,%d,%d)\n", r, g, b, int kcmy[i].k, int kcmy[i].c, int kcmy[i].m, int kcmy[i].y)); first = 0; } return kcmy; } # Simple version of above to lookup precalculated values SimpleColorMatch(cmap: array of KCMY, colrow: array of int): array of KCMY { ncolrow := len colrow; kcmy_row := array[ncolrow] of KCMY; for (i:=0; i<ncolrow; i++) kcmy_row[i] = cmap[colrow[i]]; return kcmy_row; } ldepth(d: int): int { if(d & (d-1) || d >= 16) return 4; for(i := 0; i < 3; i++) if(d <= (1<<i)) break; return i; } # Set up color map once and for all setup_color_map(display: ref Display, map: array of KCMY, depth: int): array of KCMY { gsfactor := GSFACTOR[ldepth(depth)]; bpp := depth; max := 1 << bpp; rgb_row := array[max] of RGB; for (i:=0; i<max; i++) { if (depth >= 8) { (r, g, b) := display.cmap2rgb(i); rgb_row[i] = RGB (byte r, byte g, byte b); } else { # BW or Greyscale grey := byte (255-int (real i * gsfactor)); rgb_row[i] = RGB (grey, grey, grey); } } kcmy_row := ColorMatch(map, rgb_row); return kcmy_row; } # Dithering tmpShortStore: int; diffusionErrorPtr := 1; # for serpentine?? errPtr: array of int; rasterByte1 := 0; rasterByte2 := 0; rand8 := array [8] of int; pad8 := array [8] of {* => 0}; Dither(ditherParms: DitherParms) { errPtr = ditherParms.fErr; numLoop := ditherParms.fNumPix; inputPtr := 0; fedResTbl := ditherParms.fFEDRes; symmetricFlag := ditherParms.fSymmetricFlag; doNext8Pixels : int; hifipe := ditherParms.fHifipe; outputPtr1 := 0; outputPtr2 := 0; diffusionErrorPtr = 1; fInput := ditherParms.fInput; if(ditherParms.fRasterEvenOrOdd) { tmpShortStore = errPtr[diffusionErrorPtr]; errPtr[diffusionErrorPtr] = 0; for (pixelCount := numLoop + 8; (pixelCount -= 8) > 0; ) { if (pixelCount > 16) { # if next 16 pixels are white, skip 8 # doNext8Pixels = Forward16PixelsNonWhite(fInput, inputPtr); doNext8Pixels = 0; lim := inputPtr + 16; for (i := inputPtr; i < lim; i++) { if (fInput[i] != byte 0) { doNext8Pixels = 1; break; } } } else { doNext8Pixels = 1; } if (doNext8Pixels) { FORWARD_FED8(fInput, inputPtr, fedResTbl); inputPtr += 8; # HPRand8(); # FORWARD_FED(rand8[0], 16r80, fInput[inputPtr++], fedResTbl); # FORWARD_FED(rand8[1], 16r40, fInput[inputPtr++], fedResTbl); # FORWARD_FED(rand8[2], 16r20, fInput[inputPtr++], fedResTbl); # FORWARD_FED(rand8[3], 16r10, fInput[inputPtr++], fedResTbl); # FORWARD_FED(rand8[4], 16r08, fInput[inputPtr++], fedResTbl); # FORWARD_FED(rand8[5], 16r04, fInput[inputPtr++], fedResTbl); # FORWARD_FED(rand8[6], 16r02, fInput[inputPtr++], fedResTbl); # FORWARD_FED(rand8[7], 16r01, fInput[inputPtr++], fedResTbl); ditherParms.fOutput1[outputPtr1++] = byte rasterByte1; rasterByte1 = 0; if (hifipe) { ditherParms.fOutput2[outputPtr2++] = byte rasterByte2; rasterByte2 = 0; } } else { # Do white space skipping inputPtr += 8; ditherParms.fOutput1[outputPtr1++] = byte 0; if (hifipe) { ditherParms.fOutput2[outputPtr2++] = byte 0; } errPtr[diffusionErrorPtr:] = pad8; diffusionErrorPtr += 8; rasterByte1 = 0; rasterByte2 = 0; tmpShortStore = 0; } } # for pixelCount } else { rasterByte1 = 0; rasterByte2 = 0; inputPtr += ( numLoop-1 ); outputPtr1 += ( numLoop/8 - 1 ); outputPtr2 += ( numLoop/8 - 1 ); diffusionErrorPtr += ( numLoop-1 ); tmpShortStore = errPtr[diffusionErrorPtr]; errPtr[diffusionErrorPtr] = 0; for (pixelCount := numLoop + 8; (pixelCount -= 8) > 0; ) { if (pixelCount > 16) { # if next 16 pixels are white, skip 8 # doNext8Pixels = Backward16PixelsNonWhite(fInput, inputPtr); doNext8Pixels = 0; lim := inputPtr - 16; for (i := inputPtr; i > lim; i--) { if (fInput[i] != byte 0) { doNext8Pixels = 1; break; } } } else { doNext8Pixels = HPTRUE; } if (doNext8Pixels) { BACKWARD_FED8(fInput, inputPtr, fedResTbl); inputPtr -= 8; # HPRand8(); # BACKWARD_FED(rand8[0], 16r01, fInput[inputPtr--], fedResTbl); # BACKWARD_FED(rand8[1], 16r02, fInput[inputPtr--], fedResTbl); # BACKWARD_FED(rand8[2], 16r04, fInput[inputPtr--], fedResTbl); # BACKWARD_FED(rand8[3], 16r08, fInput[inputPtr--], fedResTbl); # BACKWARD_FED(rand8[4], 16r10, fInput[inputPtr--], fedResTbl); # BACKWARD_FED(rand8[5], 16r20, fInput[inputPtr--], fedResTbl); # BACKWARD_FED(rand8[6], 16r40, fInput[inputPtr--], fedResTbl); # BACKWARD_FED(rand8[7], 16r80, fInput[inputPtr--], fedResTbl); ditherParms.fOutput1[outputPtr1-- ]= byte rasterByte1; rasterByte1 = 0; if (hifipe) { ditherParms.fOutput2[outputPtr2--] = byte rasterByte2; rasterByte2 = 0; } } else { # Do white space skipping inputPtr -= 8; ditherParms.fOutput1[outputPtr1--] = byte 0; if (hifipe) { ditherParms.fOutput2[outputPtr2--] = byte 0; } diffusionErrorPtr -= 8; errPtr[diffusionErrorPtr:] = pad8; rasterByte1 = 0; rasterByte2 = 0; tmpShortStore = 0; } } } } # Take a step back Backward16PixelsNonWhite(ba: array of byte, inputPtr: int): int { lim := inputPtr - 16; for (i := inputPtr; i > lim; i--) { if (ba[i] != byte 0) return TRUE; } return FALSE; } # Take a step forward Forward16PixelsNonWhite(ba: array of byte, inputPtr: int): int { lim := inputPtr + 16; for (i := inputPtr; i < lim; i++) { if (ba[i] != byte 0) return TRUE; } return FALSE; } FORWARD_FED8(input: array of byte, ix: int, fedResTbl: array of int) { HPRand8(); randix := 0; for (bitMask := 16r80; bitMask; bitMask >>= 1) { tone := int input[ix++]; fedResPtr := tone << 2; level := fedResTbl[fedResPtr]; if (tone != 0) { tone = ( tmpShortStore + int fedResTbl[fedResPtr+1] ); if (tone >= rand8[randix++]) { tone -= 255; level++; } case (level) { 0=> break; 1=> rasterByte1 |= bitMask; break; 2=> rasterByte2 |= bitMask; break; 3=> rasterByte2 |= bitMask; rasterByte1 |= bitMask; break; 4=> break; 5=> rasterByte1 |= bitMask; break; 6=> rasterByte2 |= bitMask; break; 7=> rasterByte2 |= bitMask; rasterByte1 |= bitMask; break; } } else { tone = tmpShortStore; } halftone := tone >> 1; errPtr[diffusionErrorPtr++] = halftone; tmpShortStore = errPtr[diffusionErrorPtr] + (tone - halftone); } } #FORWARD_FED(thresholdValue: int, bitMask: int, toneb: byte, fedResTbl : array of int) #{ # tone := int toneb; # fedResPtr := (tone << 2); # level := fedResTbl[fedResPtr]; # if (tone != 0) { # tone = ( tmpShortStore + int fedResTbl[fedResPtr+1] ); # if (tone >= thresholdValue) { # tone -= 255; # level++; # } # case (level) { # 0=> # break; # 1=> # rasterByte1 |= bitMask; # break; # 2=> # rasterByte2 |= bitMask; # break; # 3=> # rasterByte2 |= bitMask; rasterByte1 |= bitMask; # break; # 4=> # break; # 5=> # rasterByte1 |= bitMask; # break; # 6=> # rasterByte2 |= bitMask; # break; # 7=> # rasterByte2 |= bitMask; rasterByte1 |= bitMask; # break; # } # } else { # tone = tmpShortStore; # } # halftone := tone >> 1; # errPtr[diffusionErrorPtr++] = halftone; # tmpShortStore = errPtr[diffusionErrorPtr] + (tone - halftone); ## dbg(sys->sprint("FORWARD_FED: thresh %d bitMask %x toneb %d => rasterbytes %d,%d,%d\n", thresholdValue, bitMask, int toneb, rasterByte1, rasterByte2)); #} BACKWARD_FED8(input: array of byte, ix: int, fedResTbl: array of int) { HPRand8(); randix := 0; for (bitMask := 16r01; bitMask <16r100; bitMask <<= 1) { tone := int input[ix--]; fedResPtr := (tone << 2); level := fedResTbl[fedResPtr]; if (tone != 0) { tone = ( tmpShortStore + int fedResTbl[fedResPtr+1] ); if (tone >= rand8[randix++]) { tone -= 255; level++; } case (level) { 0=> break; 1=> rasterByte1 |= bitMask; break; 2=> rasterByte2 |= bitMask; break; 3=> rasterByte2 |= bitMask; rasterByte1 |= bitMask; break; 4=> break; 5=> rasterByte1 |= bitMask; break; 6=> rasterByte2 |= bitMask; break; 7=> rasterByte2 |= bitMask; rasterByte1 |= bitMask; break; } } else { tone = tmpShortStore; } halftone := tone >> 1; errPtr[diffusionErrorPtr--] = halftone; tmpShortStore = errPtr[diffusionErrorPtr] + (tone - halftone); } } #BACKWARD_FED(thresholdValue: int, bitMask: int, toneb: byte, fedResTbl : array of int) #{ # tone := int toneb; # fedResPtr := (tone << 2); # level := fedResTbl[fedResPtr]; # if (tone != 0) { # tone = ( tmpShortStore + int fedResTbl[fedResPtr+1] ); # if (tone >= thresholdValue) { # tone -= 255; # level++; # } # case (level) { # 0=> # break; # 1=> # rasterByte1 |= bitMask; # break; # 2=> # rasterByte2 |= bitMask; # break; # 3=> # rasterByte2 |= bitMask; rasterByte1 |= bitMask; # break; # 4=> # break; # 5=> # rasterByte1 |= bitMask; # break; # 6=> # rasterByte2 |= bitMask; # break; # 7=> # rasterByte2 |= bitMask; rasterByte1 |= bitMask; # break; # } # } else { # tone = tmpShortStore; # } # halftone := tone >> 1; # errPtr[diffusionErrorPtr--] = halftone; # tmpShortStore = errPtr[diffusionErrorPtr] + (tone - halftone); ## dbg(sys->sprint("BACWARD_FED: thresh %d bitMask %x toneb %d => rasterbytes %d,%d,%d\n", thresholdValue, bitMask, int toneb, rasterByte1, rasterByte2)); #} # Pixel replication pixrep(in: array of RGB): array of RGB { out := array[2*len in] of RGB; for (i:=0; i<len in; i++) { out[i*2] = in[i]; out[i*2+1] = in[i]; } return out; } # Random numbers IM: con 139968; IA: con 3877; IC: con 29573; last := 42; # Use a really simple and quick random number generator HPRand(): int { return (74 * (last = (last* IA + IC) % IM) / IM ) + 5; } HPRand8() { for (i:= 0; i < 8; i++) rand8[i] = (74 * (last = (last* IA + IC) % IM) / IM ) + 5; } # Compression compress(rawdata: array of byte): array of byte { nraw := len rawdata; comp := array [2*nraw] of byte; # worst case ncomp := 0; for (i:=0; i<nraw;) { rpt := 0; val := rawdata[i++]; while (i<nraw && rpt < 255 && rawdata[i] == val) { rpt++; i++; } comp[ncomp++] = byte rpt; comp[ncomp++] = val; } return comp[0:ncomp]; } # Print error message and exit fatal(s: string) { sys->fprint(stderr, "%s\n", s); exit; } killgrp(pid: int) { sys->fprint(sys->open("/prog/" + string pid +"/ctl", Sys->OWRITE), "killgrp"); } dbg(s: string) { if (DEBUG) sys->fprint(stderr, "%s", s); } # Uninteresting constants FEDarray := array[1024] of { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 2 , 0 , 0 , 0 , 3 , 0 , 0 , 0 , 4 , 0 , 0 , 0 , 5 , 0 , 0 , 0 , 6 , 0 , 0 , 0 , 7 , 0 , 0 , 0 , 8 , 0 , 0 , 0 , 9 , 0 , 0 , 0 , 10 , 0 , 0 , 0 , 11 , 0 , 0 , 0 , 12 , 0 , 0 , 0 , 13 , 0 , 0 , 0 , 14 , 0 , 0 , 0 , 15 , 0 , 0 , 0 , 16 , 0 , 0 , 0 , 17 , 0 , 0 , 0 , 18 , 0 , 0 , 0 , 19 , 0 , 0 , 0 , 20 , 0 , 0 , 0 , 21 , 0 , 0 , 0 , 22 , 0 , 0 , 0 , 23 , 0 , 0 , 0 , 24 , 0 , 0 , 0 , 25 , 0 , 0 , 0 , 26 , 0 , 0 , 0 , 27 , 0 , 0 , 0 , 28 , 0 , 0 , 0 , 29 , 0 , 0 , 0 , 30 , 0 , 0 , 0 , 31 , 0 , 0 , 0 , 32 , 0 , 0 , 0 , 33 , 0 , 0 , 0 , 34 , 0 , 0 , 0 , 35 , 0 , 0 , 0 , 36 , 0 , 0 , 0 , 37 , 0 , 0 , 0 , 38 , 0 , 0 , 0 , 39 , 0 , 0 , 0 , 40 , 0 , 0 , 0 , 41 , 0 , 0 , 0 , 42 , 0 , 0 , 0 , 43 , 0 , 0 , 0 , 44 , 0 , 0 , 0 , 45 , 0 , 0 , 0 , 46 , 0 , 0 , 0 , 47 , 0 , 0 , 0 , 48 , 0 , 0 , 0 , 49 , 0 , 0 , 0 , 50 , 0 , 0 , 0 , 51 , 0 , 0 , 0 , 52 , 0 , 0 , 0 , 53 , 0 , 0 , 0 , 54 , 0 , 0 , 0 , 55 , 0 , 0 , 0 , 56 , 0 , 0 , 0 , 57 , 0 , 0 , 0 , 58 , 0 , 0 , 0 , 59 , 0 , 0 , 0 , 60 , 0 , 0 , 0 , 61 , 0 , 0 , 0 , 62 , 0 , 0 , 0 , 63 , 0 , 0 , 0 , 64 , 0 , 0 , 0 , 65 , 0 , 0 , 0 , 66 , 0 , 0 , 0 , 67 , 0 , 0 , 0 , 68 , 0 , 0 , 0 , 69 , 0 , 0 , 0 , 70 , 0 , 0 , 0 , 71 , 0 , 0 , 0 , 72 , 0 , 0 , 0 , 73 , 0 , 0 , 0 , 74 , 0 , 0 , 0 , 75 , 0 , 0 , 0 , 76 , 0 , 0 , 0 , 77 , 0 , 0 , 0 , 78 , 0 , 0 , 0 , 79 , 0 , 0 , 0 , 80 , 0 , 0 , 0 , 81 , 0 , 0 , 0 , 82 , 0 , 0 , 0 , 83 , 0 , 0 , 0 , 84 , 0 , 0 , 0 , 85 , 0 , 0 , 0 , 86 , 0 , 0 , 0 , 87 , 0 , 0 , 0 , 88 , 0 , 0 , 0 , 89 , 0 , 0 , 0 , 90 , 0 , 0 , 0 , 91 , 0 , 0 , 0 , 92 , 0 , 0 , 0 , 93 , 0 , 0 , 0 , 94 , 0 , 0 , 0 , 95 , 0 , 0 , 0 , 96 , 0 , 0 , 0 , 97 , 0 , 0 , 0 , 98 , 0 , 0 , 0 , 99 , 0 , 0 , 0 , 100 , 0 , 0 , 0 , 101 , 0 , 0 , 0 , 102 , 0 , 0 , 0 , 103 , 0 , 0 , 0 , 104 , 0 , 0 , 0 , 105 , 0 , 0 , 0 , 106 , 0 , 0 , 0 , 107 , 0 , 0 , 0 , 108 , 0 , 0 , 0 , 109 , 0 , 0 , 0 , 110 , 0 , 0 , 0 , 111 , 0 , 0 , 0 , 112 , 0 , 0 , 0 , 113 , 0 , 0 , 0 , 114 , 0 , 0 , 0 , 115 , 0 , 0 , 0 , 116 , 0 , 0 , 0 , 117 , 0 , 0 , 0 , 118 , 0 , 0 , 0 , 119 , 0 , 0 , 0 , 120 , 0 , 0 , 0 , 121 , 0 , 0 , 0 , 122 , 0 , 0 , 0 , 123 , 0 , 0 , 0 , 124 , 0 , 0 , 0 , 125 , 0 , 0 , 0 , 126 , 0 , 0 , 0 , 127 , 0 , 0 , 0 , 128 , 0 , 0 , 0 , 129 , 0 , 0 , 0 , 130 , 0 , 0 , 0 , 131 , 0 , 0 , 0 , 132 , 0 , 0 , 0 , 133 , 0 , 0 , 0 , 134 , 0 , 0 , 0 , 135 , 0 , 0 , 0 , 136 , 0 , 0 , 0 , 137 , 0 , 0 , 0 , 138 , 0 , 0 , 0 , 139 , 0 , 0 , 0 , 140 , 0 , 0 , 0 , 141 , 0 , 0 , 0 , 142 , 0 , 0 , 0 , 143 , 0 , 0 , 0 , 144 , 0 , 0 , 0 , 145 , 0 , 0 , 0 , 146 , 0 , 0 , 0 , 147 , 0 , 0 , 0 , 148 , 0 , 0 , 0 , 149 , 0 , 0 , 0 , 150 , 0 , 0 , 0 , 151 , 0 , 0 , 0 , 152 , 0 , 0 , 0 , 153 , 0 , 0 , 0 , 154 , 0 , 0 , 0 , 155 , 0 , 0 , 0 , 156 , 0 , 0 , 0 , 157 , 0 , 0 , 0 , 158 , 0 , 0 , 0 , 159 , 0 , 0 , 0 , 160 , 0 , 0 , 0 , 161 , 0 , 0 , 0 , 162 , 0 , 0 , 0 , 163 , 0 , 0 , 0 , 164 , 0 , 0 , 0 , 165 , 0 , 0 , 0 , 166 , 0 , 0 , 0 , 167 , 0 , 0 , 0 , 168 , 0 , 0 , 0 , 169 , 0 , 0 , 0 , 170 , 0 , 0 , 0 , 171 , 0 , 0 , 0 , 172 , 0 , 0 , 0 , 173 , 0 , 0 , 0 , 174 , 0 , 0 , 0 , 175 , 0 , 0 , 0 , 176 , 0 , 0 , 0 , 177 , 0 , 0 , 0 , 178 , 0 , 0 , 0 , 179 , 0 , 0 , 0 , 180 , 0 , 0 , 0 , 181 , 0 , 0 , 0 , 182 , 0 , 0 , 0 , 183 , 0 , 0 , 0 , 184 , 0 , 0 , 0 , 185 , 0 , 0 , 0 , 186 , 0 , 0 , 0 , 187 , 0 , 0 , 0 , 188 , 0 , 0 , 0 , 189 , 0 , 0 , 0 , 190 , 0 , 0 , 0 , 191 , 0 , 0 , 0 , 192 , 0 , 0 , 0 , 193 , 0 , 0 , 0 , 194 , 0 , 0 , 0 , 195 , 0 , 0 , 0 , 196 , 0 , 0 , 0 , 197 , 0 , 0 , 0 , 198 , 0 , 0 , 0 , 199 , 0 , 0 , 0 , 200 , 0 , 0 , 0 , 201 , 0 , 0 , 0 , 202 , 0 , 0 , 0 , 203 , 0 , 0 , 0 , 204 , 0 , 0 , 0 , 205 , 0 , 0 , 0 , 206 , 0 , 0 , 0 , 207 , 0 , 0 , 0 , 208 , 0 , 0 , 0 , 209 , 0 , 0 , 0 , 210 , 0 , 0 , 0 , 211 , 0 , 0 , 0 , 212 , 0 , 0 , 0 , 213 , 0 , 0 , 0 , 214 , 0 , 0 , 0 , 215 , 0 , 0 , 0 , 216 , 0 , 0 , 0 , 217 , 0 , 0 , 0 , 218 , 0 , 0 , 0 , 219 , 0 , 0 , 0 , 220 , 0 , 0 , 0 , 221 , 0 , 0 , 0 , 222 , 0 , 0 , 0 , 223 , 0 , 0 , 0 , 224 , 0 , 0 , 0 , 225 , 0 , 0 , 0 , 226 , 0 , 0 , 0 , 227 , 0 , 0 , 0 , 228 , 0 , 0 , 0 , 229 , 0 , 0 , 0 , 230 , 0 , 0 , 0 , 231 , 0 , 0 , 0 , 232 , 0 , 0 , 0 , 233 , 0 , 0 , 0 , 234 , 0 , 0 , 0 , 235 , 0 , 0 , 0 , 236 , 0 , 0 , 0 , 237 , 0 , 0 , 0 , 238 , 0 , 0 , 0 , 239 , 0 , 0 , 0 , 240 , 0 , 0 , 0 , 241 , 0 , 0 , 0 , 242 , 0 , 0 , 0 , 243 , 0 , 0 , 0 , 244 , 0 , 0 , 0 , 245 , 0 , 0 , 0 , 246 , 0 , 0 , 0 , 247 , 0 , 0 , 0 , 248 , 0 , 0 , 0 , 249 , 0 , 0 , 0 , 250 , 0 , 0 , 0 , 251 , 0 , 0 , 0 , 252 , 0 , 0 , 0 , 253 , 0 , 0 , 0 , 254 , 0 , 0 , 0 , 254 , 0 , 0 };