PrintColorTransformationsImpl.mesa
Copyright Ó 1987 by Xerox Corporation. All rights reserved.
Maureen Stone, July 2, 1989 6:05:52 pm PDT
Color Transformation routines for printing monitor images
DIRECTORY
PrintColorTransformations,
PrintColor USING [ColorCorrection, CorrectionProc, ColorCorrectionRep],
ImagerSample USING [PointerToSamples],
ImagerPixel USING [PixelBuffer],
NewInterpressCC,
Real, RealFns, Basics,
FS USING [StreamOpen],
IO USING [STREAM, GetCard, GetLineRope, Close, GetID],
Rope USING [ROPE];
PrintColorTransformationsImpl: CEDAR PROGRAM
IMPORTS Real, RealFns, ImagerSample, FS, IO, NewInterpressCC
EXPORTS PrintColorTransformations
~ BEGIN OPEN PrintColorTransformations;
ROPE: TYPE ~ Rope.ROPE;
ColorCorrection: TYPE ~ PrintColor.ColorCorrection;
Matrix3: TYPE = ARRAY[0..3) OF ARRAY[0..3) OF REAL;
SWOP Transformation
SWOP Standard GCR and black
SWOPData: TYPE = REF SWOPDataRec;
RGBToCMYProc: TYPE = PROC[maxSampleIn: ARRAY [0..3) OF CARDINAL, rgbIn, cmyOut: ImagerPixel.PixelBuffer, data: REF];
SWOPDataRec: TYPE = RECORD[gcTable, cyanTable, magentaTable, yellowTable, blackTable: TRCTable ← NIL, rgbToCMY: RGBToCMYProc, rgbToCMYData: REFNIL];
SWOPLinearDotArea: PUBLIC PROC RETURNS[ColorCorrection] = {
maxSampleOut: NAT = 255;
cc: ColorCorrection ← NEW[PrintColor.ColorCorrectionRep ← [
type: $SWOP,
correctionProc: SWOPColorCorrectionProc,
maxSampleIn: [255, 255, 255],
samplesPerPixelOut: maxSampleOut,
data: NEW[SWOPDataRec ← [
cyanTable: cyanTable,
magentaTable: magentaTable,
yellowTable: yellowTable,
blackTable: blackTable,
gcTable: IdentityTRC[],
rgbToCMY: FlipRGBCMYProc,
rgbToCMYData: NIL
]]
]];
RETURN[cc];
};
SWOPWithGCLinearLStar: PUBLIC PROC RETURNS[ColorCorrection] = {
maxSampleOut: NAT = 255;
cc: ColorCorrection ← NEW[PrintColor.ColorCorrectionRep ← [
type: $SWOPLinearLStar,
correctionProc: SWOPColorCorrectionProc,
maxSampleIn: [255, 255, 255],
samplesPerPixelOut: maxSampleOut,
data: NEW[SWOPDataRec ← [
cyanTable: cyanTable,
magentaTable: magentaTable,
yellowTable: yellowTable,
blackTable: blackTable,
gcTable: convertToLStar,
rgbToCMY: FlipRGBCMYProc,
rgbToCMYData: NIL
]]
]];
RETURN[cc];
};
FlipRGBCMYProc: RGBToCMYProc = { --CMY ← [255,255, 255] -RGB
maxRed: CARDINAL ← maxSampleIn[0];
maxGreen: CARDINAL ← maxSampleIn[1];
maxBlue: CARDINAL ← maxSampleIn[2];
FOR i: NAT IN [0..rgbIn.length) DO
cmyOut[0][i] ← maxRed-rgbIn[0][i];
cmyOut[1][i] ← maxGreen-rgbIn[1][i];
cmyOut[2][i] ← maxBlue-rgbIn[2][i];
ENDLOOP;
};
SWOPWithMatrix: PUBLIC PROC[matrixTables: MatrixTables] RETURNS[ColorCorrection] = {
maxSampleOut: NAT = 255;
cc: ColorCorrection ← NEW[PrintColor.ColorCorrectionRep ← [
type: $SWOPWithMatrix,
correctionProc: SWOPColorCorrectionProc,
maxSampleIn: [255, 255, 255],
samplesPerPixelOut: maxSampleOut,
data: NEW[SWOPDataRec ← [
cyanTable: cyanTable,
magentaTable: magentaTable,
yellowTable: yellowTable,
blackTable: blackTable,
gcTable: convertToLStar,
rgbToCMY: MatrixTransform,
rgbToCMYData: matrixTables
]]
]];
RETURN[cc];
};
SWOPColorCorrectionProc: PrintColor.CorrectionProc = {
c,m,y,k, gc: NAT;
data: SWOPData ← NARROW[self.data];
data.rgbToCMY[maxSampleIn: self.maxSampleIn, rgbIn: rgbIn, cmyOut: pixelsOut, data: data.rgbToCMYData];
FOR i: NAT IN [0..pixelsOut.length) DO
c ← pixelsOut[0][i];
m ← pixelsOut[1][i];
y ← pixelsOut[2][i];
gc ← data.gcTable[MIN[c,m,y]];
c ← MAX[0, MIN[255, c-gc+data.cyanTable[gc]]];
m ← MAX[0, MIN[255, m-gc+data.magentaTable[gc]]];
y ← MAX[0, MIN[255, y-gc+data.yellowTable[gc]]];
k ← data.blackTable[gc];
pixelsOut[0][i] ← c;
pixelsOut[1][i] ← m;
pixelsOut[2][i] ← y;
pixelsOut[3][i] ← k;
ENDLOOP;
};
Rhodes-Lamming color correction
Largest24bitNumber: INT ~ 77777777B;
BYTE: TYPE ~ [0..377B];
InitMatrixTables: PUBLIC PROC[rgbToLStar, densityToDotArea: TRCTable, printerDMax, saturation, contrast: REAL, values: Values] RETURNS[MatrixTables] ~ {
LToDTable: PROC [matrixEl:REAL, trc:TRCTable ← NIL] RETURNS [table: MatrixEltTable] ~ {
-- table values range from -LAST[INT]...LAST[INT]
-- representation for printerDMax = Largest24bitNumber
-- trc=NIL means that no mapping is to be performed. i.e. inputs are density coded
Dens24FromLStarRel : PROC [pixel:NAT] RETURNS [tableValue: INT] ~ {
dens: REAL ← LStarToDens[printerLStarMin + (printerRange * (pixel / 255.0))] * matrixEl;
tableValue ← Real.InlineRound[ (dens / printerDMax) * Largest24bitNumber];
};
table ← NEW[MatrixEltTableRec];
FOR i: NAT IN [0..255] DO
table[i] ← Dens24FromLStarRel[trc[i]];
ENDLOOP
};
blackValue:NAT = 255;
printerLStarMin, printerRange: REAL;
tables: MatrixTables ← NEW[MatrixTablesRec];
matrix: Matrix3 ← MatrixFromValues[values];
FOR i:NAT IN [0..2] DO -- add required saturation boost
FOR j:NAT IN [0..2] DO
IF i=j THEN
matrix[i][j] ← matrix[i][j] + saturation*2
ELSE
matrix[i][j] ← matrix[i][j] - saturation
ENDLOOP;
ENDLOOP;
FOR i:NAT IN [0..2] DO -- add required contrast boost
matrix[i][i] ← matrix[i][i] + contrast;
ENDLOOP;
printerLStarMin ← DensToLStar[printerDMax];
printerRange ← 100.0 - printerLStarMin;
tables.m00 ← LToDTable[matrix[0][0], rgbToLStar];
tables.m10 ← LToDTable[matrix[1][0], rgbToLStar];
tables.m20 ← LToDTable[matrix[2][0], rgbToLStar];
tables.m01 ← LToDTable[matrix[0][1], rgbToLStar];
tables.m11 ← LToDTable[matrix[1][1], rgbToLStar];
tables.m21 ← LToDTable[matrix[2][1], rgbToLStar];
tables.m02 ← LToDTable[matrix[0][2], rgbToLStar];
tables.m12 ← LToDTable[matrix[1][2], rgbToLStar];
tables.m22 ← LToDTable[matrix[2][2], rgbToLStar];
tables.cyan ← densityToDotArea;
tables.magenta ← densityToDotArea;
tables.yellow ← densityToDotArea;
RETURN [tables]
};
ProcFromCCSpec: PUBLIC PROC[ccSpec: ROPE, correctionType: CorrectionType, maxSampleOut, maxSampleIn: NAT ← 255] RETURNS[ColorCorrection] = {
Calls NewInterpressCC to get the color correction
NewInterpressCC is just like InterpressCC except for the color correction type
RETURN[NewInterpressCC.InitCC[file: ccSpec, colorCorrect: correctionType=full]];
};
MatrixTransform: RGBToCMYProc = {
tables: MatrixTables ← NARROW[data];
rPtr: LONG POINTER TO WORDLOOPHOLE[ImagerSample.PointerToSamples[rgbIn[0], 0, rgbIn.length]];
gPtr: LONG POINTER TO WORDLOOPHOLE[ImagerSample.PointerToSamples[rgbIn[1], 0, rgbIn.length]];
bPtr: LONG POINTER TO WORDLOOPHOLE[ImagerSample.PointerToSamples[rgbIn[2], 0, rgbIn.length]];
yPtr: LONG POINTER TO WORDLOOPHOLE[ImagerSample.PointerToSamples[cmyOut[2], 0, cmyOut.length]];
mPtr: LONG POINTER TO WORDLOOPHOLE[ImagerSample.PointerToSamples[cmyOut[1], 0, cmyOut.length]];
cPtr: LONG POINTER TO WORDLOOPHOLE[ImagerSample.PointerToSamples[cmyOut[0], 0, cmyOut.length]];
m00: MatrixEltTable ← tables.m00;
m01: MatrixEltTable ← tables.m01;
m02: MatrixEltTable ← tables.m02;
m10: MatrixEltTable ← tables.m10;
m11: MatrixEltTable ← tables.m11;
m12: MatrixEltTable ← tables.m12;
m20: MatrixEltTable ← tables.m20;
m21: MatrixEltTable ← tables.m21;
m22: MatrixEltTable ← tables.m22;
yellow: TRCTable ← tables.yellow;
magenta: TRCTable ← tables.magenta;
cyan: TRCTable ← tables.cyan;
FOR j: NAT IN [0..cmyOut.length) DO TRUSTED {
r: CARDINAL ← rPtr^; g: CARDINAL ← gPtr^; b: CARDINAL ← bPtr^;
cyan24: INT ~ MAX[
MIN[m00[r] + m01[g] + m02[b], Largest24bitNumber],
0];
mag24: INT ~ MAX[
MIN[m10[r] + m11[g] + m12[b], Largest24bitNumber],
0];
yel24: INT ~ MAX[
MIN[m20[r] + m21[g] + m22[b], Largest24bitNumber],
0];
yPtr^ ← 255-yellow[LOOPHOLE[yel24, Basics.LongNumber].hl];
mPtr^ ← 255-magenta[LOOPHOLE[mag24, Basics.LongNumber].hl];
cPtr^ ← 255-cyan[LOOPHOLE[cyan24, Basics.LongNumber].hl];
rPtr ← rPtr + 1; gPtr ← gPtr + 1; bPtr ← bPtr + 1;
yPtr ← yPtr + 1; mPtr ← mPtr + 1; cPtr ← cPtr + 1;
} ENDLOOP;
};
LStarToRef: PROC [lstar: REAL] RETURNS [ref: REAL] ~ {
IF lstar<8.9 THEN ref ← lstar / 903.29
ELSE {
t: REAL ← (lstar+16) / 116.0;
ref ← t * t * t;
}
};
RefToLstar: PROC [ref: REAL] RETURNS [lstar: REAL] ~ {
IF ref<0.01 THEN lstar ← ref * 903.29
ELSE {
lstar ← 116.0 * RealFns.Root[3, ref] - 16;
}
};
RefToDens: PROC [ref: REAL] RETURNS [dens: REAL] ~ {
IF ref=0 THEN RETURN [Real.LargestNumber];
dens ← -RealFns.Log[10, ref]
};
LStarToDens: PROC [lstar: REAL] RETURNS [dens: REAL] ~ {
dens ← RefToDens[LStarToRef[lstar]];
};
DensToLStar: PROC [dens: REAL] RETURNS [lstar: REAL] ~ {
lstar ← RefToLstar[DensToRef[dens]];
};
DensToRef: PROC [dens: REAL] RETURNS [ref: REAL] ~ {
ref ← RealFns.Power[10, -dens];
};
Black only
LuminanceToDotArea: PUBLIC PROC[maxSampleOut, maxSampleIn: NAT ← 255] RETURNS[ColorCorrection] = {
RBG => luminance => dot area. Good if images are designed already in dot area
cc: ColorCorrection ← NEW[PrintColor.ColorCorrectionRep ← [
type: $LuminanceToDotArea,
correctionProc: LuminanceToDotAreaProc,
maxSampleIn: [maxSampleIn, maxSampleIn, maxSampleIn],
samplesPerPixelOut: maxSampleOut,
data: NIL
]];
RETURN[cc];
};
LuminanceToDotAreaProc: PrintColor.CorrectionProc = {
FOR i: NAT IN [0..rgbIn.length) DO
l: NAT ←Real.Round[maxSampleOut[3]-(0.30*rgbIn[0][i]+0.59*rgbIn[1][i]+0.11*rgbIn[2][i])];
pixelsOut[0][i] ← 0;
pixelsOut[1][i] ← 0;
pixelsOut[2][i] ← 0;
pixelsOut[3][i] ← l;
ENDLOOP;
};
Trivial CC procs
NullRGB: PUBLIC PROC[maxSampleOut, maxSampleIn: NAT ← 255] RETURNS[ColorCorrection] = {
RGB ← RGB
cc: ColorCorrection ← NEW[PrintColor.ColorCorrectionRep ← [
type: $NullRGB,
correctionProc: NullRGBProc,
maxSampleIn: [maxSampleIn, maxSampleIn, maxSampleIn],
samplesPerPixelOut: maxSampleOut,
data: NIL
]];
RETURN[cc];
};
NullRGBProc: PrintColor.CorrectionProc = {
FOR i: NAT IN [0..rgbIn.length) DO
pixelsOut[0][i] ← rgbIn[0][i];
pixelsOut[1][i] ← rgbIn[1][i];
pixelsOut[2][i] ← rgbIn[2][i];
IF pixelsOut.length=4 THEN pixelsOut[3][i] ← 0;
ENDLOOP;
};
FlipRGB: PUBLIC PROC[maxSampleOut, maxSampleIn: NAT ← 255] RETURNS[ColorCorrection] = {
CMYK = [C: 255-R, M: 255-G, Y: 255-B, K: 0]. Also the default color correction behavior
cc: ColorCorrection ← NEW[PrintColor.ColorCorrectionRep ← [
type: $FlipRGB,
correctionProc: FlipRGBProc,
maxSampleIn: [maxSampleIn, maxSampleIn, maxSampleIn],
samplesPerPixelOut: maxSampleOut,
data: NIL
]];
RETURN[cc];
};
FlipRGBProc: PrintColor.CorrectionProc = {
FOR i: NAT IN [0..rgbIn.length) DO
pixelsOut[0][i] ← self.maxSampleIn[0]-rgbIn[0][i];
pixelsOut[1][i] ← self.maxSampleIn[1]-rgbIn[1][i];
pixelsOut[2][i] ← self.maxSampleIn[2]-rgbIn[2][i];
pixelsOut[3][i] ← 0;
ENDLOOP;
};
FlipAndFullGCR: PUBLIC PROC[maxSampleOut, maxSampleIn: NAT ← 255] RETURNS[ColorCorrection] = {
C,M,Y computed as for flipRGB, then modified such that
K= MIN[C, M, Y]. [C: C-K, M: M-K, Y: M-K, K: K]
cc: ColorCorrection ← NEW[PrintColor.ColorCorrectionRep ← [
type: $FlipRGB,
correctionProc: FlipAndFullGCRProc,
maxSampleIn: [maxSampleIn, maxSampleIn, maxSampleIn],
samplesPerPixelOut: maxSampleOut,
data: NIL
]];
RETURN[cc];
};
FlipAndFullGCRProc: PrintColor.CorrectionProc = {
c,m,y,k: NAT;
FOR i: NAT IN [0..rgbIn.length) DO
c ← self.maxSampleIn[0]-rgbIn[0][i];
m ← self.maxSampleIn[1]-rgbIn[1][i];
y ← self.maxSampleIn[2]-rgbIn[2][i];
k ← MIN[c,m,y];
pixelsOut[0][i] ← c-k;
pixelsOut[1][i] ← m-k;
pixelsOut[2][i] ← y-k;
pixelsOut[3][i] ← k;
ENDLOOP;
};
Utility Procedures
ReadTRC: PUBLIC PROC [trcFn: ROPE] RETURNS [trc: TRCTable] ~ {
in: IO.STREAM;
in ← FS.StreamOpen[trcFn];
trc ← NEW[TRCTableRec ← ALL[0]];
[] ← in.GetID[];
FOR i:CARDINAL IN [0..255] DO
index:CARDINAL;
prev:CARDINAL ← index;
index ← in.GetCard[];
IF index>0 AND prev+1#index THEN ERROR;
prev ← index;
trc[index] ← IO.GetCard[in];
[] ← in.GetLineRope[];
ENDLOOP;
in.Close[];
};
DensityToLStar: PUBLIC PROC [dMax: REAL] RETURNS [trc:TRCTable] ~ {
minLStar: REAL ← DensToLStar[dMax];
scale: REAL ← 2.55*100.0/(100-minLStar);
trc ← NEW[TRCTableRec ← ALL[0]];
FOR i: NAT IN [0..255] DO
trc[i] ← Real.Round[scale*(DensToLStar[dMax*(i/255.0)]-minLStar)];
ENDLOOP
};
RGBToLStar: PUBLIC PROC [] RETURNS [convertRGB:TRCTable] = {
Define the TRC along the gray axis, that is, where R=G=B.
This is independent of the monitor phosphors because
Y/Yn = f(YR+YG+YB)/(YR+YG+YB) = f for R=G=B
getLStar: PROC [rel: REAL] RETURNS[lStar: REAL] = { --val in [0..1]
IF rel > 0.008856 THEN
lStar ← 116.0*RealFns.Power[base: rel, exponent: 1.0/3.0] -16.0
ELSE lStar ← 903.29*rel;
};
step: REAL ← 1.0/255.0;
convertRGB ← NEW[TRCTableRec];
FOR val: INT IN [0..256) DO
convertRGB[val] ← Real.Round[2.55*getLStar[val*step]];
ENDLOOP;
};
IdentityTRC: PUBLIC PROC [] RETURNS [initTrc:TRCTable] ~ {
initTrc ← NEW[TRCTableRec ← ALL[0]];
FOR i: NAT IN [0..255] DO
initTrc[i] ← i;
ENDLOOP
};
IdentityValues: PUBLIC PROC RETURNS[Values] = {
RETURN[[c0: 1,m0: 0,y0: 0,c1: 0,m1: 1,y1: 0,c2: 0,m2: 0,y2: 1]];
};
MatrixFromValues: PROC[v: Values] RETURNS[matrix: Matrix3] = {
matrix[0][0] ← v.c0;
matrix[0][1] ← v.m0;
matrix[0][2] ← v.y0;
matrix[1][0] ← v.c1;
matrix[1][1] ← v.m1;
matrix[1][2] ← v.y1;
matrix[2][0] ← v.c2;
matrix[2][1] ← v.m2;
matrix[2][2] ← v.y2;
RETURN[matrix];
};
BuildTables: PROC = { --use of this is odd. Run it to read the TRC's, print result and copy it into the code below. Prefer to keep result pickled in code. Data comes from measuring and processing a gray wedge produced by Kedie-Orent.
cyanTable ← ReadTRC["/ivy/stone/coloroffset/SWOP-cyan.trc"];
magentaTable ← ReadTRC["/ivy/stone/coloroffset/SWOP-magenta.trc"];
yellowTable ← ReadTRC["/ivy/stone/coloroffset/SWOP-yellow.trc"];
blackTable ← ReadTRC["/ivy/stone/coloroffset/SWOP-black.trc"];
};
cyanTable: TRCTable ← NEW[TRCTableRec ←
[0, 1, 3, 4, 6, 7, 9, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20, 22, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 36, 37, 38, 39, 40, 42, 43, 44, 46, 47, 48, 50, 51, 52, 54, 55, 57, 58, 59, 61, 62, 63, 65, 66, 67, 69, 70, 72, 73, 75, 76, 77, 79, 80, 82, 83, 85, 86, 87, 89, 90, 92, 93, 95, 96, 97, 98, 99, 100, 101, 102, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177, 178, 178, 179, 180, 181, 181, 182, 183, 184, 184, 185, 186, 187, 187, 188, 189, 190, 190, 191, 192, 193, 193, 194, 195, 196, 196, 197, 198, 199, 199, 200, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207, 207, 208, 208, 209, 209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215, 215, 216, 216, 217, 217, 218, 218, 219, 219, 219, 220, 220, 221, 221, 221, 222, 222, 223, 223, 223, 224, 224, 225, 225, 225, 226, 226, 227, 227, 228, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 234, 235]];
magentaTable: TRCTable ← NEW[TRCTableRec ←
[0, 0, 1, 1, 2, 2, 3, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 52, 53, 54, 55, 56, 58, 59, 60, 61, 62, 63, 65, 66, 67, 68, 69, 71, 72, 73, 74, 75, 75, 76, 77, 78, 79, 79, 80, 81, 82, 83, 84, 84, 85, 86, 87, 88, 88, 89, 90, 91, 92, 92, 93, 94, 95, 96, 97, 97, 98, 99, 100, 101, 102, 102, 103, 104, 105, 106, 107, 108, 108, 109, 110, 111, 112, 113, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 138, 139, 140, 141, 141, 142, 143, 144, 144, 145, 146, 147, 147, 148, 149, 150, 150, 151, 152, 153, 153, 154, 155, 155, 156, 157, 157, 158, 159, 159, 160, 160, 161, 162, 162, 163, 164, 164, 165, 166, 166, 167, 168, 168, 169, 169, 170, 170, 171, 171, 172, 172, 173, 173, 174, 174, 175, 175, 176, 176, 177, 177, 178, 178, 179, 179, 180, 180, 181, 182, 182, 183, 183, 184, 184, 185, 185, 186, 186, 187, 187, 188, 188, 189, 189, 190, 190, 191, 191, 192, 192, 193, 193, 194, 195, 195, 196, 196, 197, 197, 198, 198, 199, 199, 200, 200, 201]];
yellowTable: TRCTable ← NEW[TRCTableRec ←
[0, 0, 1, 1, 2, 2, 3, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 25, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 56, 57, 58, 59, 60, 62, 63, 64, 65, 66, 67, 69, 70, 71, 72, 73, 75, 76, 77, 78, 79, 80, 81, 82, 83, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 95, 96, 97, 98, 99, 100, 101, 102, 103, 103, 104, 105, 106, 107, 107, 108, 109, 110, 111, 112, 112, 113, 114, 115, 116, 116, 117, 118, 119, 120, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 143, 144, 145, 145, 146, 147, 147, 148, 149, 149, 150, 151, 151, 152, 153, 153, 154, 155, 155, 156, 157, 157, 158, 158, 159, 160, 160, 161, 161, 162, 163, 163, 164, 165, 165, 166, 166, 167, 168, 168, 169, 169, 170, 170, 171, 171, 172, 172, 172, 173, 173, 174, 174, 174, 175, 175, 176, 176, 177, 177, 177, 178, 178, 179, 179, 179, 180, 180, 181, 181, 181, 182, 182, 183, 183, 183, 184, 184, 185, 185, 185, 186, 186, 187, 187, 187, 188, 188, 189, 189, 189, 190, 190, 191, 191, 192, 192, 193, 193, 194, 195, 195, 196, 197, 197, 198, 198, 199]];
blackTable: TRCTable ← NEW[TRCTableRec ←
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 10, 10, 11, 11, 12, 13, 13, 14, 15, 15, 16, 17, 17, 18, 18, 19, 20, 20, 21, 22, 22, 23, 24, 24, 25, 26, 26, 27, 28, 29, 30, 31, 32, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 134, 135, 136, 137, 138, 139, 140, 142, 144, 146, 147, 149, 151, 153, 155, 157, 158, 160, 162, 164]];
convertToLStar: TRCTable ← NEW[TRCTableRec ←
[0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 28, 28, 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 37, 37, 38, 39, 40, 41, 42, 43, 43, 44, 45, 46, 47, 48, 49, 49, 50, 51, 52, 53, 53, 54, 55, 56, 56, 57, 58, 59, 59, 60, 61, 61, 62, 63, 63, 64, 65, 65, 66, 67, 67, 68, 68, 69, 70, 70, 71, 71, 72, 72, 73, 74, 75, 76, 77, 79, 80, 81, 82, 83, 84, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 116, 117, 118, 119, 120, 121, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 137, 138, 139, 140, 141, 141, 142, 143, 144, 144, 145, 146, 147, 148, 150, 151, 152, 154, 155, 156, 158, 159, 160, 162, 163, 164, 165, 167, 168, 169, 170, 171, 172, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 214, 216, 218, 221, 224, 228, 231, 234, 236, 239, 241, 243, 245, 247, 248, 250, 251, 253, 254, 255]];
END.