diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
| commit | 37da2899f40661e3e9631e497da8dc59b971cbd0 (patch) | |
| tree | cbc6d4680e347d906f5fa7fca73214418741df72 /appl/lib/print | |
| parent | 54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff) | |
20060303a
Diffstat (limited to 'appl/lib/print')
| -rw-r--r-- | appl/lib/print/hp_driver.b | 1536 | ||||
| -rw-r--r-- | appl/lib/print/mkfile | 26 | ||||
| -rw-r--r-- | appl/lib/print/print.b | 625 | ||||
| -rw-r--r-- | appl/lib/print/scaler.b | 186 | ||||
| -rw-r--r-- | appl/lib/print/scaler.m | 30 |
5 files changed, 2403 insertions, 0 deletions
diff --git a/appl/lib/print/hp_driver.b b/appl/lib/print/hp_driver.b new file mode 100644 index 00000000..15fb2eb7 --- /dev/null +++ b/appl/lib/print/hp_driver.b @@ -0,0 +1,1536 @@ +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 +}; diff --git a/appl/lib/print/mkfile b/appl/lib/print/mkfile new file mode 100644 index 00000000..786daf06 --- /dev/null +++ b/appl/lib/print/mkfile @@ -0,0 +1,26 @@ + +<../../../mkconfig + +TARG=\ + print.dis \ + hp_driver.dis \ + scaler.dis \ + + +MODULES=\ + scaler.m \ + + +SYSMODULES= \ + bufio.m\ + draw.m\ + string.m\ + sys.m\ + print.m \ + + +DISBIN=$ROOT/dis/lib/print + +<$ROOT/mkfiles/mkdis +# force compilation or it's very slow +LIMBOFLAGS= -c $LIMBOFLAGS diff --git a/appl/lib/print/print.b b/appl/lib/print/print.b new file mode 100644 index 00000000..090136a6 --- /dev/null +++ b/appl/lib/print/print.b @@ -0,0 +1,625 @@ +implement Print; + +include "sys.m"; + sys: Sys; +include "draw.m"; + draw: Draw; + Display, Font, Rect, Point, Image, Screen: import draw; +include "bufio.m"; + bufio: Bufio; +include "string.m"; + str: String; + +include "print.m"; + +MAXNAME: con 80; +DEFMODE: con 8r664; + +PAPER_CONFIG: con CONFIG_PATH + "paper.cfg"; +PTYPE_CONFIG: con CONFIG_PATH + "ptype.cfg"; +PMODE_CONFIG: con CONFIG_PATH + "pmode.cfg"; +POPT_CONFIG: con CONFIG_PATH + "popt.cfg"; +PRINTER_CONFIG: con CONFIG_PATH + "printer.cfg"; +DEFPRINTER: con CONFIG_PATH + "defprinter"; + + +Cfg: adt { + name: string; + pairs: list of (string, string); +}; + +DEBUG :=0; + + +all_papers: list of ref Paper; +all_pmodes: list of ref Pmode; +all_ptypes: list of ref Ptype; +all_popts: list of ref Popt; +all_printers: list of ref Printer; +default_printer: ref Printer; +stderr: ref Sys->FD; +printfd: ref Sys->FD; + +# Initialization + +init(): int +{ + sys = load Sys Sys->PATH; + stderr = sys->fildes(2); + draw = load Draw Draw->PATH; + bufio = load Bufio Bufio->PATH; + str = load String String->PATH; + all_papers = read_paper_config(); + if (all_papers == nil) return 1; + all_pmodes = read_pmode_config(); + if (all_pmodes == nil) return 1; + all_ptypes = read_ptype_config(); + if (all_ptypes == nil) return 1; + all_printers = read_printer_config(); + if (all_printers == nil) return 1; + all_popts = read_popt_config(); + for (pl:=all_printers; pl!=nil; pl=tl pl) { + p := hd pl; + opt := find_popt(all_popts, p.name); + if (opt != nil) p.popt = opt; + else { + p.popt = ref Popt (p.name, hd all_pmodes, hd all_papers, 0, 0); + all_popts = p.popt :: all_popts; + } + } + return 0; +} + +# Set printer FD + +set_printfd(fd: ref Sys->FD) +{ + printfd = fd; +} + + +# Get default printer + +get_defprinter(): ref Printer +{ + if (len all_printers == 1) return hd all_printers; # If there's only 1 printer + df := sys->open(DEFPRINTER, Sys->OREAD); + if (df == nil) { + if (all_printers != nil) return hd all_printers; + else return nil; + } + a := array[MAXNAME] of byte; + nb := sys->read(df, a, MAXNAME); + if (nb < 2) return nil; + name := string a[:nb-1]; + def := find_printer(all_printers, name); + if (def != nil) return def; + else return hd all_printers; +} + +# Set default printer + +set_defprinter(p: ref Printer) +{ + df := sys->create(DEFPRINTER, Sys->OWRITE, DEFMODE); + if (df == nil) return; + sys->fprint(df, "%s\n", p.name); +} + +# Set paper size + +get_size(p: ref Printer): (int, int, int) # dpi, xpixels, ypixels +{ + if (p == nil) return (0, 0, 0); + load_driver(p); + dpi := p.popt.mode.resx; + (xpix, ypix) := p.pdriver->printable_pixels(p); # This takes account of orientation + return (dpi, xpix, ypix); +} + + + +# Get list of all printers + +get_printers(): list of ref Printer +{ + return all_printers; +} + +# Return list of printer types + +get_ptypes(): list of ref Ptype +{ + return all_ptypes; +} + +# Return list of print modes + +get_pmodes(): list of ref Pmode +{ + return all_pmodes; +} + +# Return list of paper types + +get_papers(): list of ref Paper +{ + return all_papers; +} + +# Return list of print options + +get_popts(): list of ref Popt +{ + return all_popts; +} + +# Save option settings + +save_settings(): int +{ + return write_popt_config(all_popts); + +} + + +# Print an image + +print_image(p: ref Printer, display: ref Draw->Display, im: ref Draw->Image, pcwidth: int, cancel: chan of int): int +{ + if (p == nil || im == nil) return 1; + load_driver(p); + popen(p); + (xpix, ypix) := p.pdriver->printable_pixels(p); + imwidth := im.r.max.x - im.r.min.x; + imheight := im.r.max.y - im.r.min.y; + if (pcwidth > 0) pixwidth := int (real xpix * real pcwidth/100.0); + else pixwidth = imwidth; + lmar := (xpix - pixwidth)/2; + fpixwidth := pixwidth; + if (p.popt.orientation != PORTRAIT) { + lmar += pixwidth; + fpixwidth = pixwidth*imheight/imwidth; + } + if (lmar < 0) lmar = 0; + return p.pdriver->sendimage(p, printfd, display, im, fpixwidth, lmar, cancel); +} + +# Print text + +print_textfd(p: ref Printer, fd: ref Sys->FD, ps: real, pr: int, wrap: int): int +{ + load_driver(p); + popen(p); + return p.pdriver->sendtextfd(p, printfd, fd, ps, pr, wrap); + +} + + +# Open printer device if necessary + +popen(p: ref Printer) +{ + if (printfd != nil) return; + printfd = sys->create(p.device, Sys->OWRITE, DEFMODE); +} + +# Find printer item + +find_printer(all: list of ref Printer, name: string): ref Printer +{ + for (p:=all; p!=nil; p=tl p) if ((hd p).name == name) return hd p; + return nil; +} + +# Find popt item + +find_popt(all: list of ref Popt, name: string): ref Popt +{ + for (p:=all; p!=nil; p=tl p) if ((hd p).name == name) return hd p; + return nil; +} + + +# Find paper item + +find_paper(all: list of ref Paper, name: string): ref Paper +{ + for (p:=all; p!=nil; p=tl p) if ((hd p).name == name) return hd p; + return nil; +} + +# Find pmode item + +find_pmode(all: list of ref Pmode, name: string): ref Pmode +{ + for (p:=all; p!=nil; p=tl p) if ((hd p).name == name) return hd p; + return nil; +} + +# Find ptype item + +find_ptype(all: list of ref Ptype, name: string): ref Ptype +{ + for (p:=all; p!=nil; p=tl p) if ((hd p).name == name) return hd p; + return nil; +} + + +# Read paper config file + +read_paper_config(): list of ref Paper +{ + (clist, aliases) := read_config(PAPER_CONFIG); + rlist: list of ref Paper; + while (clist != nil) { + this := hd clist; + clist = tl clist; + item := ref Paper(this.name, "", 0.0, 0.0); + for (pairs:= this.pairs; pairs != nil; pairs = tl pairs) { + (name, value) := hd pairs; + case (name) { + "hpcode" => + item.hpcode = value; + + "width_inches" => + item.width_inches = real value; + + "height_inches" => + item.height_inches = real value; + + * => + sys->fprint(stderr, "Unknown paper config file option: %s\n", name); + } + } + rlist =item :: rlist; + } + for (al:=aliases; al!=nil; al=tl al) { + (new, old) := hd al; + olda := find_paper(rlist, old); + if (olda == nil) sys->fprint(stderr, "Paper alias %s not found\n", old); + else { + newa := ref *olda; + newa.name = new; + rlist = newa :: rlist; + } + } + return rlist; +} + + +# Read pmode config file + +read_pmode_config(): list of ref Pmode +{ + (clist, aliases) := read_config(PMODE_CONFIG); + rlist: list of ref Pmode; + while (clist != nil) { + this := hd clist; + clist = tl clist; + item := ref Pmode(this.name, "", 0, 0, 1, 1, 1); + for (pairs:= this.pairs; pairs != nil; pairs = tl pairs) { + (name, value) := hd pairs; + case (name) { + "desc" => + item.desc = value; + + "resx" => + item.resx = int value; + + "resy" => + item.resy = int value; + + "coldepth" => + item.coldepth = int value; + + "blackdepth" => + item.blackdepth = int value; + + "blackresmult" => + item.blackresmult = int value; + + * => + sys->fprint(stderr, "Unknown pmode config file option: %s\n", name); + + } + } + rlist =item :: rlist; + } + for (al:=aliases; al!=nil; al=tl al) { + (new, old) := hd al; + olda := find_pmode(rlist, old); + if (olda == nil) sys->fprint(stderr, "Pmode alias %s not found\n", old); + else { + newa := ref *olda; + newa.name = new; + rlist = newa :: rlist; + } + } + return rlist; +} + + + + +# Readp Ptype config file + +read_ptype_config(): list of ref Ptype +{ + (clist, aliases) := read_config(PTYPE_CONFIG); + rlist: list of ref Ptype; + while (clist != nil) { + this := hd clist; + clist = tl clist; + item := ref Ptype(this.name, "", nil, "", ""); + for (pairs:= this.pairs; pairs != nil; pairs = tl pairs) { + (name, value) := hd pairs; + case (name) { + "desc" => + item.desc = value; + + "driver" => + item.driver = value; + + "hpmapfile" => + item.hpmapfile = value; + + "modes" => + item.modes = make_pmode_list(value); + + * => + sys->fprint(stderr, "Unknown ptype config file option: %s\n", name); + } + } + if (item.modes == nil) { + sys->fprint(stderr, "No print modes for ptype %s\n", item.name); + continue; + } + rlist = item :: rlist; + } + for (al:=aliases; al!=nil; al=tl al) { + (new, old) := hd al; + olda := find_ptype(rlist, old); + if (olda == nil) sys->fprint(stderr, "Ptype alias %s not found\n", old); + else { + newa := ref *olda; + newa.name = new; + rlist = newa :: rlist; + } + } + return rlist; +} + + +# Make a list of pmodes from a string + +make_pmode_list(sl: string): list of ref Pmode +{ + pml: list of ref Pmode; + (n, toks) := sys->tokenize(sl, " \t"); + if (n == 0) return nil; + for (i:=0; i<n; i++) { + pms := hd toks; + toks = tl toks; + pm := find_pmode(all_pmodes, pms); + if (pm == nil) { + sys->fprint(stderr, "unknown pmode: %s\n", pms); + continue; + } + pml = pm :: pml; + } + return pml; +} + + +# Read popt config file + +read_popt_config(): list of ref Popt +{ + (clist, aliases) := read_config(POPT_CONFIG); + rlist: list of ref Popt; + while (clist != nil) { + this := hd clist; + clist = tl clist; + item := ref Popt(this.name, nil, nil, 0, 0); + for (pairs:= this.pairs; pairs != nil; pairs = tl pairs) { + (name, value) := hd pairs; + case (name) { + + "mode" => + item.mode = find_pmode(all_pmodes, value); + if (item.mode == nil) sys->fprint(stderr, "Config error: Pmode not found: %s\n", value); + + "paper" => + item.paper = find_paper(all_papers, value); + if (item.paper == nil) sys->fprint(stderr, "Config error: paper not found: %s\n", value); + + "orientation" => + item.orientation = int value; + "duplex" => + item.duplex = int value; + + * => + sys->fprint(stderr, "Unknown popt config file option: %s\n", name); + } + } + if (item.mode == nil) { + sys->fprint(stderr, "No print mode for printer %s\n", item.name); + continue; + } + if (item.paper == nil) { + sys->fprint(stderr, "No paper size for printer %s\n", item.name); + continue; + } + rlist = item :: rlist; + } + for (al:=aliases; al!=nil; al=tl al) { + (new, old) := hd al; + olda := find_popt(rlist, old); + if (olda == nil) sys->fprint(stderr, "Popt alias %s not found\n", old); + else { + newa := ref *olda; + newa.name = new; + rlist = newa :: rlist; + } + } + return rlist; +} + + + + +# Read printer config file + +read_printer_config(): list of ref Printer +{ + (clist, aliases) := read_config(PRINTER_CONFIG); + rlist: list of ref Printer; + while (clist != nil) { + this := hd clist; + clist = tl clist; + item := ref Printer(this.name, nil, "", nil, nil); + for (pairs:= this.pairs; pairs != nil; pairs = tl pairs) { + (name, value) := hd pairs; + case (name) { + "ptype" => + item.ptype = find_ptype(all_ptypes, value); + if (item.ptype == nil) sys->fprint(stderr, "Config error: Ptype not found: %s\n", value); + + "device" => + item.device = value; + + * => + sys->fprint(stderr, "Unknown printer config file option: %s\n", name); + } + } + if (item.ptype == nil) { + sys->fprint(stderr, "No printer type for printer %s\n", item.name); + continue; + } + rlist = item :: rlist; + } + for (al:=aliases; al!=nil; al=tl al) { + (new, old) := hd al; + olda := find_printer(rlist, old); + if (olda == nil) sys->fprint(stderr, "Ptype alias %s not found\n", old); + else { + newa := ref *olda; + newa.name = new; + rlist = newa :: rlist; + } + } + return rlist; +} + +# Write opt config file + +write_popt_config(plist: list of ref Popt): int +{ + cfl: list of Cfg; + for (pl:=plist; pl!=nil; pl=tl pl) { + po := hd pl; + cf := Cfg(po.name, nil); + cf.pairs = ("mode", po.mode.name) :: cf.pairs; + cf.pairs = ("paper", po.paper.name) :: cf.pairs; + cf.pairs = ("orientation", sys->sprint("%d", po.orientation)) :: cf.pairs; + cf.pairs = ("duplex", sys->sprint("%d", po.duplex)) :: cf.pairs; + cfl = cf :: cfl; + } + return write_config(POPT_CONFIG, cfl, nil); +} + + +write_config(fspec: string, clist: list of Cfg, aliases: list of (string, string)): int +{ + fd := sys->create(fspec, Sys->OWRITE, DEFMODE); + if (fd == nil) { + sys->fprint(stderr, "Failed to write to config file %s: %r\n", fspec); + return 1; + } + for (cfl:=clist; cfl!=nil; cfl=tl cfl) { + cf := hd cfl; + sys->fprint(fd, "%s=\n", cf.name); + for (pl:=cf.pairs; pl!=nil; pl=tl pl) { + (name, value) := hd pl; + if (sys->fprint(fd, "\t%s=%s\n", name, value) < 0) return 2; + } + } + for (al:=aliases; al!=nil; al=tl al) { + (new, old) := hd al; + if (sys->fprint(fd, "%s=%s\n", new, old)) return 2; + } + return 0; +} + + +# Read in a config file and return list of items and aliases + +read_config(fspec: string): (list of Cfg, list of (string, string)) +{ + ib := bufio->open(fspec, Bufio->OREAD); + if (ib == nil) { + sys->fprint(stderr, "Failed to open config file %s: %r\n", fspec); + return (nil, nil); + } + clist: list of Cfg; + plist: list of (string, string); + section := ""; + aliases : list of (string, string); + while ((line := bufio->ib.gets('\n')) != nil) { + if (line[0] == '#') continue; + if (line[len line-1] == '\n') line = line[:len line-1]; + if (len line == 0) continue; + if (line[0] != ' ' && line[0] != '\t') { + if (section != "") clist = Cfg (section, plist) :: clist; + section = ""; + plist = nil; + sspec := strip(line); + (n, toks) := sys->tokenize(sspec, "="); + if (n == 0) continue; + if (n > 2) { + sys->fprint(stderr, "Error in config file %s\n", fspec); + continue; + } + if (n == 2) { + asection := hd toks; + toks = tl toks; + alias := hd toks; + aliases = (asection, alias) :: aliases; + continue; + } + section = hd toks; + } else { + (n, toks) := sys->tokenize(line, "="); + if (n == 2) { + name := strip(hd toks); + toks = tl toks; + value := strip(hd toks); + plist = (name, value) :: plist; + } + } + } + if (section != "") clist = Cfg (section, plist) :: clist; + return (clist, aliases); +} + + +# Load printer driver if necessary +load_driver(p: ref Printer) +{ + if (p.pdriver != nil) return; + modpath := Pdriver->PATHPREFIX + p.ptype.driver; + p.pdriver = load Pdriver modpath; + if (p.pdriver == nil) sys->fprint(stderr, "Failed to load driver %s: %r\n", modpath); + p.pdriver->init(DEBUG); +} + + +# Strip leading/trailing spaces + +strip(s: string): string +{ + (dummy1, s1) := str->splitl(s, "^ \t"); + (s2, dummy2) := str->splitr(s1, "^ \t"); + return s2; +} diff --git a/appl/lib/print/scaler.b b/appl/lib/print/scaler.b new file mode 100644 index 00000000..fd33b591 --- /dev/null +++ b/appl/lib/print/scaler.b @@ -0,0 +1,186 @@ +implement Scaler; + +include "sys.m"; + sys: Sys; +include "draw.m"; +include "print.m"; +include "scaler.m"; + +DEBUG := 0; + +# Scaler initialisation + +init(debug: int, WidthInPixels, ScaleFactorMultiplier, ScaleFactorDivisor: int): ref RESSYNSTRUCT +{ + DEBUG = debug; + ScaleFactor := real ScaleFactorMultiplier / real ScaleFactorDivisor; + ScaleBound := int ScaleFactor; + if (ScaleFactor > real ScaleBound) ScaleBound++; + ResSynStruct := ref RESSYNSTRUCT ( + WidthInPixels+2, # add 2 for edges + ScaleFactorMultiplier, + ScaleFactorDivisor, + ScaleFactor, + int ((real WidthInPixels / real ScaleFactorDivisor))*ScaleFactorMultiplier + 1, + ScaleFactorMultiplier != ScaleFactorDivisor, + ScaleFactor < 2.0, + (ScaleFactorMultiplier * 256 / ScaleFactorDivisor) + - ((ScaleFactorMultiplier/ScaleFactorDivisor) * 256), + 0, + 0, + array[NUMBER_RASTERS] of array of int, + array[ScaleBound] of array of int, + 0, + 0 + ); + if (ResSynStruct.ScaleFactor > real ScaleBound) ScaleBound++; + for (i:=0; i<len ResSynStruct.Buffer; i++) ResSynStruct.Buffer[i] = array[WidthInPixels*NUMBER_RASTERS] of int; + for (i=0; i<len ResSynStruct.oBuffer; i++) ResSynStruct.oBuffer[i] = array[ResSynStruct.iOutputWidth] of int; + return ResSynStruct; +} + + +# Input a raster line to the scaler + +rasterin(rs: ref RESSYNSTRUCT, inraster: array of int) +{ + if (!rs.scaling) { # Just copy to output buffer + if (inraster == nil) return; + rs.oBuffer[0] = inraster; + rs.nready = 1; + rs.ndelivered = 0; + return; + } + + if (rs.ReplicateOnly) { # for scaling between 1 and 2 +# for (i:=0; i<len inraster; i++) rs.oBuffer[0][i] = inraster[i]; + rs.oBuffer[0][:] = inraster[0:]; + create_out(rs, 1); + return; + } + + if (rs.RastersinBuffer == 0) { # First time through + if (inraster == nil) return; + for (i:=0; i<2; i++) { + rs.Buffer[i][0] = inraster[0]; +# for (j:=1; j<rs.Width-1; j++) rs.Buffer[i][j] = inraster[j-1]; + rs.Buffer[i][1:] = inraster[0:rs.Width-2]; + rs.Buffer[i][rs.Width-1] = inraster[rs.Width-3]; + } + rs.RastersinBuffer = 2; + return; + } + + if (rs.RastersinBuffer == 2) { # Just two buffers in so far + if (inraster != nil) { + i := 2; + rs.Buffer[i][0] = inraster[0]; +# for (j:=1; j<rs.Width-1; j++) rs.Buffer[i][j] = inraster[j-1]; + rs.Buffer[i][1:] = inraster[0:rs.Width-2]; + rs.Buffer[i][rs.Width-1] = inraster[rs.Width-3]; + rs.RastersinBuffer = 3; + } else { # nil means end of image + rez_synth(rs, rs.oBuffer[0], rs.oBuffer[1]); + create_out(rs, 0); + } + return; + } + if (rs.RastersinBuffer == 3) { # All three buffers are full + (rs.Buffer[0], rs.Buffer[1], rs.Buffer[2]) = (rs.Buffer[1], rs.Buffer[2], rs.Buffer[0]); + if (inraster != nil) { + i := 2; + rs.Buffer[i][0] = inraster[0]; +# for (j:=1; j<rs.Width-1; j++) rs.Buffer[i][j] = inraster[j-1]; + rs.Buffer[i][1:] = inraster[0:rs.Width-2]; + rs.Buffer[i][rs.Width-1] = inraster[rs.Width-3]; + } else { # nil means end of image +# for (j:=0; j<len rs.Buffer[1]; j++) rs.Buffer[2][j] = rs.Buffer[1][j]; + rs.Buffer[2][:] = rs.Buffer[1]; + rs.RastersinBuffer = 0; + + } + rez_synth(rs, rs.oBuffer[0], rs.oBuffer[1]); + create_out(rs, 0); + } + +} + + +# Get a raster output line from the scaler + +rasterout(rs: ref RESSYNSTRUCT): array of int +{ + if (rs.nready-- > 0) { + return rs.oBuffer[rs.ndelivered++][:rs.iOutputWidth-1]; + } else return nil; +} + + + +# Create output raster + +create_out(rs: ref RESSYNSTRUCT, simple: int) +{ + factor: int; + if (simple) factor = 1; + else factor = 2; + + out_width := (rs.Width-2) * rs.ScaleFactorMultiplier / rs.ScaleFactorDivisor; + number_out := rs.ScaleFactorMultiplier / rs.ScaleFactorDivisor; + if (number_out == 2 && !(rs.ScaleFactorMultiplier % rs.ScaleFactorDivisor) ) { + rs.nready = 2; + rs.ndelivered = 0; + return; + } + + if (rs.ScaleFactorMultiplier % rs.ScaleFactorDivisor) + { + rs.Remainder = rs.Remainder + rs.Repeat; + + if (rs.Remainder >= 256) # send extra raster + { + number_out++; + rs.Remainder = rs.Remainder - 256; + } + } + # set up pointers into the output buffer + output_raster := array[number_out] of array of int; + output_raster[:] = rs.oBuffer[0:number_out]; + + ScaleFactorMultiplier := rs.ScaleFactorMultiplier; + ScaleFactorDivisor := rs.ScaleFactorDivisor; + sf := factor * ScaleFactorDivisor; + + # Convert the input data by starting at the bottom right hand corner and move left + up + for (i:=(number_out-1); i>=0; i--) { + y_index := i*sf/ScaleFactorMultiplier; + orast_i := output_raster[i]; + orast_y := output_raster[y_index]; + for (lx := out_width-1; lx>=0; --lx) { + x_index := lx*sf/ScaleFactorMultiplier; + orast_i[lx] = orast_y[x_index]; + } + } + + rs.nready = number_out; + rs.ndelivered = 0; + return; +} + + +# Synthesise raster line + +rez_synth(rs: ref RESSYNSTRUCT, output_raster0, output_raster1: array of int) +{ + + i := 1; + Buffer := rs.Buffer[i]; + h_offset := 0; + for (j:=1; j<rs.Width-1; j++) { + rgb := Buffer[j]; + output_raster0[h_offset] = rgb; + output_raster1[h_offset++] = rgb; + output_raster0[h_offset] = rgb; + output_raster1[h_offset++] = rgb; + } +} diff --git a/appl/lib/print/scaler.m b/appl/lib/print/scaler.m new file mode 100644 index 00000000..e73dfdb4 --- /dev/null +++ b/appl/lib/print/scaler.m @@ -0,0 +1,30 @@ +Scaler: module +{ + PATH: con "/dis/lib/print/scaler.dis"; + + init: fn(debug: int, WidthInPixels, ScaleFactorMultiplier, ScaleFactorDivisor: int): ref RESSYNSTRUCT; + rasterin: fn(rs: ref RESSYNSTRUCT, inraster: array of int); + rasterout: fn(rs: ref RESSYNSTRUCT ): array of int; + + RESSYNSTRUCT: adt { + Width: int; + ScaleFactorMultiplier: int; + ScaleFactorDivisor: int; + ScaleFactor: real; + iOutputWidth: int; + scaling: int; + ReplicateOnly: int; + Repeat: int; + RastersinBuffer: int; + Remainder: int; + Buffer: array of array of int; + oBuffer: array of array of int; + nready: int; + ndelivered: int; + }; + + +}; + + +NUMBER_RASTERS: con 3; # no of rasters to buffer |
