IJColorFloyd.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Eric Nickell, June 18, 1985 2:55:28 pm PDT
DIRECTORY
AIS, PrincOps, Rope;
IJColorFloyd: CEDAR PROGRAM
IMPORTS AIS, Rope
~ BEGIN
ROPE: TYPE ~ Rope.ROPE;
CMYK: TYPE ~ {cyan, magenta, yellow, black, red, green, blue, white}; --If desired, add {darkcyan, darkyellow, darkmagenta, darkred, darkgreen, threecolorblack, allinkblack}
RGB: TYPE ~ {r, g, b};
Color: TYPE ~ RECORD [r, g, b: INTEGER ← 0];
MaxBufferSize: INT ~ 2000;
Buffer: TYPE ~ ARRAY [-1..MaxBufferSize+1] OF Color;
lastPixel: INT ~ MaxBufferSize;
CMYKPixel: TYPE ~ CARDINAL ← 0;
cyan: ARRAY CMYK OF CMYKPixel ~ [cyan: 1, green: 1, blue: 1];
magenta: ARRAY CMYK OF CMYKPixel ~ [magenta: 1, red: 1, blue: 1];
yellow: ARRAY CMYK OF CMYKPixel ~ [yellow: 1, red: 1, green: 1];
black: ARRAY CMYK OF CMYKPixel ~ [black: 1];
valid: ARRAY CMYK OF BOOLEANALL[TRUE]; -- Is this particular combination around?
colors: ARRAY CMYK OF Color ~ [
cyan: [r: 0, g: 255, b: 255],
magenta: [r: 255, g: 0, b: 255],
yellow: [r: 255, g: 255, b: 0],
red: [r: 255, g: 0, b: 0],
green: [r: 0, g: 255, b: 0],
blue: [r: 0, g: 0, b: 255],
black: [r: 0, g: 0, b: 0],
white: [r: 255, g: 255, b: 255]
];
FloydAIS: PROC [name: ROPE] ~ {
red, green, blue, c, m, y, k: AIS.WRef;
raster: AIS.Raster;
buffer: REF Buffer ~ NEW[Buffer ← ALL[]];
WriteOutput: PROC [cmyk: CMYK, scan, pixel: CARDINAL] ~ {
AIS.WriteSample[c, cyan[cmyk], scan, pixel];
AIS.WriteSample[m, magenta[cmyk], scan, pixel];
AIS.WriteSample[y, yellow[cmyk], scan, pixel];
AIS.WriteSample[k, black[cmyk], scan, pixel];
};
CleanUp: PROC ~ {
CloseWindowAndFile[red];
CloseWindowAndFile[green];
CloseWindowAndFile[blue];
CloseWindowAndFile[c];
CloseWindowAndFile[m];
CloseWindowAndFile[y];
CloseWindowAndFile[k];
};
{
ENABLE UNWIND => CleanUp[];
red ← OpenWindow[Rope.Cat[name, "-red.ais"]];
green ← OpenWindow[Rope.Cat[name, "-grn.ais"]];
blue ← OpenWindow[Rope.Cat[name, "-blu.ais"]];
raster ← AIS.ReadRaster[red.fref];
c ← CreateIJSeparation[Rope.Cat[name, "-c.ais"], raster.scanCount, raster.scanLength];
m ← CreateIJSeparation[Rope.Cat[name, "-m.ais"], raster.scanCount, raster.scanLength];
y ← CreateIJSeparation[Rope.Cat[name, "-y.ais"], raster.scanCount, raster.scanLength];
k ← CreateIJSeparation[Rope.Cat[name, "-k.ais"], raster.scanCount, raster.scanLength];
FOR scan: CARDINAL IN [c.firstScan..c.lastScan] DO
this, next, d, dr: Color;
cmyk: CMYK;
FOR pixel: CARDINAL IN [c.firstPixel..c.lastPixel] DO
this ← Add3Colors[
[r: AIS.ReadSample[red, scan, pixel], g: AIS.ReadSample[green, scan, pixel], b: AIS.ReadSample[blue, scan, pixel]],
buffer[pixel],
next
];
this ← SubtractColor[this, colors[cmyk ← NearestColor[this]]];
WriteOutput[cmyk, scan, pixel];
[buffer[pixel-1], d, dr, next] ← Propagate[this, d, dr];
ENDLOOP;
buffer[lastPixel] ← d;
ENDLOOP;
CleanUp[];
}; --END ENABLE CleanUp[]
};
OpenWindow: PROC [name: ROPE] RETURNS [w: AIS.WRef] ~ {
f: AIS.FRef ~ AIS.OpenFile[name, FALSE];
RETURN [AIS.OpenWindow[f ! UNWIND => AIS.CloseFile[f]]]
};
CloseWindowAndFile: PROC [w: AIS.WRef] ~ {
f: AIS.FRef;
IF w=NIL THEN RETURN;
f ← w.fref;
AIS.CloseWindow[w];
w ← NIL;
AIS.CloseFile[f];
};
CreateIJSeparation: PROC [name: ROPE, h, w: CARDINAL] RETURNS [AIS.WRef] ~ {
raster: AIS.Raster ~ NEW[AIS.RasterPart ← [
scanCount: h,
scanLength: w,
scanMode: rd,
bitsPerPixel: 1,
linesPerBlock: -1,
paddingPerBlock: LAST[CARDINAL]
]];
RETURN[AIS.OpenWindow[f: AIS.CreateFile[name, raster], firstScan: 0, lastScan: h, firstPixel: 0, lastPixel: w]];
};
SubtractColor: PROC [c1, c2: Color] RETURNS [Color] ~ {
RETURN[[r: c1.r-c2.r, g: c1.g-c2.g, b: c1.b-c2.b]];
};
AddColor: PROC [c1, c2: Color] RETURNS [Color] ~ INLINE {
RETURN[[r: c1.r+c2.r, g: c1.g+c2.g, b: c1.b+c2.b]];
};
Add3Colors: PROC [c1, c2, c3: Color] RETURNS [Color] ~ INLINE {
RETURN[[r: c1.r+c2.r+c3.r, g: c1.g+c2.g+c3.g, b: c1.b+c2.b+c3.b]];
};
Propagate: PROC [this, oldd, olddr: Color] RETURNS [dl, d, dr, next: Color] ~ INLINE {
one, three, five, seven: Color;
[one.r, three.r, five.r, seven.r] ← Parts[this.r];
[one.g, three.g, five.g, seven.g] ← Parts[this.g];
[one.b, three.b, five.b, seven.b] ← Parts[this.b];
RETURN [
dl: AddColor[three, oldd],
d: AddColor[olddr, five],
dr: one,
next: seven
]
};
offset: CARDINAL ~ LONG[FIRST[CARDINAL]] - LONG[FIRST[INTEGER]];
Parts: PROC [whole: INTEGER] RETURNS [one, three, five, seven: INTEGER] ~ INLINE {
OPEN PrincOps;
UnsignedQuarterAnd16th: PROC [whole: INTEGER] RETURNS [quarter, sixteenth: INTEGER] ~ TRUSTED MACHINE CODE {
zLINB, 256-2 ; zSHIFT; zDUP; zLINB, 256-2; zSHIFT
};
quarter, sixteenth: INTEGER;
[quarter, sixteenth] ← UnsignedQuarterAnd16th[whole+offset];
quarter ← quarter-offset/4;
sixteenth ← sixteenth-offset/16;
RETURN [sixteenth, quarter-sixteenth, quarter+sixteenth, whole-quarter-quarter-sixteenth];
};
NearestColor: PROC [toMatch: Color] RETURNS [index: CMYK] ~ {
temp, mag: CARDINALLAST[CARDINAL];
FOR cmyk: CMYK IN CMYK DO
IF valid[cmyk] AND (temp ← ColorDistance[toMatch, colors[cmyk]])<=mag THEN {
index ← cmyk;
mag ← temp;
};
ENDLOOP;
};
ColorDistance: PROC [c1, c2: Color] RETURNS [mag: CARDINAL] ~ {
Square: PROC [a: INTEGER] RETURNS [INT] ~ INLINE {
RETURN [ABS[a]]
};
RETURN [Square[c1.r-c2.r]+Square[c1.g-c2.g]+Square[c1.b-c2.b]];
};
END.