<> <> <> <<>> 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 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]]; }; END.