~
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 BOOLEAN ← ALL[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: CARDINAL ← LAST[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]];
};