summaryrefslogtreecommitdiff
path: root/appl/lib/print
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /appl/lib/print
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'appl/lib/print')
-rw-r--r--appl/lib/print/hp_driver.b1536
-rw-r--r--appl/lib/print/mkfile26
-rw-r--r--appl/lib/print/print.b625
-rw-r--r--appl/lib/print/scaler.b186
-rw-r--r--appl/lib/print/scaler.m30
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