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