FourColorSeparation.Mesa
Created by Rick Beach, July 19, 1984 11:25:40 am PDT
DIRECTORY
AIS, Commander, FS, IO, Rope;
FourColorSeparation: CEDAR PROGRAM
IMPORTS AIS, Commander, FS, IO, Rope
=
{
ROPE: TYPE ~ Rope.ROPE;
Pixel: TYPE ~ [0..256);
BufferMax: NAT ~ 3000;
BufferRep: TYPE ~ RECORD[
length: NAT ← 0,
buffer: PACKED ARRAY [0..BufferMax] OF Pixel ← ALL[LAST[Pixel]]];
ColorSeparateCommand: Commander.CommandProc ~ TRUSTED {
fileStem: ROPE ~ IO.GetTokenRope[IO.RIS[cmd.commandLine], IO.IDProc].token;
localStem: ROPE ~ LocalName[fileStem];
redAIS: AIS.FRef ~ AIS.OpenFile[fileStem.Concat["-red.AIS"]];
greenAIS: AIS.FRef ~ AIS.OpenFile[fileStem.Concat["-green.AIS"]];
blueAIS: AIS.FRef ~ AIS.OpenFile[fileStem.Concat["-blue.AIS"]];
comment: ROPE ← AIS.ReadComment[redAIS];
these three muat be the same to proceed safefly
redRaster: AIS.Raster ~ AIS.ReadRaster[redAIS];
greenRaster: AIS.Raster ~ AIS.ReadRaster[greenAIS];
blueRaster: AIS.Raster ~ AIS.ReadRaster[blueAIS];
redW: AIS.WRef ~ AIS.OpenWindow[redAIS];
greenW: AIS.WRef ~ AIS.OpenWindow[greenAIS];
blueW: AIS.WRef ~ AIS.OpenWindow[blueAIS];
redBuffer: REF BufferRep ← NEW[BufferRep ← [redRaster.scanLength]];
greenBuffer: REF BufferRep ← NEW[BufferRep ← [redRaster.scanLength]];
blueBuffer: REF BufferRep ← NEW[BufferRep ← [redRaster.scanLength]];
redBufferDesc: AIS.Buffer ← [length: redRaster.scanLength, addr: @redBuffer.buffer];
greenBufferDesc: AIS.Buffer ← [length: redRaster.scanLength, addr: @greenBuffer.buffer];
blueBufferDesc: AIS.Buffer ← [length: redRaster.scanLength, addr: @blueBuffer.buffer];
blackAIS: AIS.FRef ~ AIS.CreateFile[localStem.Concat["-black.AIS"], redRaster, 1];
cyanAIS: AIS.FRef ~ AIS.CreateFile[localStem.Concat["-cyan.AIS"], redRaster, 1];
magentaAIS: AIS.FRef ~ AIS.CreateFile[localStem.Concat["-magenta.AIS"], redRaster, 1];
yellowAIS: AIS.FRef ~ AIS.CreateFile[localStem.Concat["-yellow.AIS"], redRaster, 1];
blackW: AIS.WRef ~ AIS.OpenWindow[blackAIS];
cyanW: AIS.WRef ~ AIS.OpenWindow[cyanAIS];
magentaW: AIS.WRef ~ AIS.OpenWindow[magentaAIS];
yellowW: AIS.WRef ~ AIS.OpenWindow[yellowAIS];
blackRaster: AIS.Raster ~ redRaster;
blackBuffer: REF BufferRep ← NEW[BufferRep ← [redRaster.scanLength]];
blackBufferDesc: AIS.Buffer ← [length: redRaster.scanLength, addr: @blackBuffer.buffer];
this is where the mapping of color separations is buried
cyanBufferDesc: AIS.Buffer ← [length: redRaster.scanLength, addr: @redBuffer.buffer];
magentaBufferDesc: AIS.Buffer ← [length: redRaster.scanLength, addr: @greenBuffer.buffer];
yellowBufferDesc: AIS.Buffer ← [length: redRaster.scanLength, addr: @blueBuffer.buffer];
cmd.out.PutRope[comment];
If the comment is longer than 256 characters (an AIS file format limitation) then truncate it with an ellipsis.
IF comment.Length > 256 THEN comment ← Rope.Cat[comment.Substr[0, 251], "...\n"];
IF redRaster.bitsPerPixel # 8 THEN
RETURN [$Failure, "sorry, but only 8-bits-per-pixel implemented"];
IF redRaster^ # greenRaster^ OR redRaster^ # blueRaster^ THEN
RETURN [$Failure, "rasters for the three input separations did not match"];
cmd.out.PutRope["Starting color separations"];
AIS.WriteComment[blackAIS, comment];
AIS.WriteComment[cyanAIS, comment];
AIS.WriteComment[magentaAIS, comment];
AIS.WriteComment[yellowAIS, comment];
FOR i: NAT IN [0..redRaster.scanCount) DO
read the three input color separations
AIS.UnsafeReadLine[redW, redBufferDesc, i];
AIS.UnsafeReadLine[greenW, greenBufferDesc, i];
AIS.UnsafeReadLine[blueW, blueBufferDesc, i];
FOR i: NAT IN [0..redRaster.scanCount) DO
blackBuffer.buffer[i] ← LAST[Pixel];
ENDLOOP;
ColorSeparate[redBuffer, greenBuffer, blueBuffer, blackBuffer];
AIS.UnsafeWriteLine[blackW, blackBufferDesc, i];
AIS.UnsafeWriteLine[cyanW, cyanBufferDesc, i];
AIS.UnsafeWriteLine[magentaW, magentaBufferDesc, i];
AIS.UnsafeWriteLine[yellowW, yellowBufferDesc, i];
ENDLOOP;
AIS.CloseFile[blackAIS];
AIS.CloseFile[cyanAIS];
AIS.CloseFile[magentaAIS];
AIS.CloseFile[yellowAIS];
cmd.out.PutRope[". . . Done\n"]
};
ColorSeparate: PROC [red, green, blue, black: REF BufferRep] ~ {
FOR i: NAT IN [0..red.length) DO
remove any component of black in the pixel
blackComponent: Pixel ← LAST[Pixel] - MAX[red.buffer[i], green.buffer[i], blue.buffer[i]];
red.buffer[i] ← red.buffer[i] + blackComponent;
green.buffer[i] ← green.buffer[i] + blackComponent;
blue.buffer[i] ← blue.buffer[i] + blackComponent;
black.buffer[i] ← LAST[Pixel] - blackComponent;
remove any grey pixel
IF red.buffer[i] = green.buffer[i] AND red.buffer[i] = blue.buffer[i] THEN {
black.buffer[i] ← red.buffer[i];
red.buffer[i] ← green.buffer[i] ← blue.buffer[i] ← LAST[Pixel];
};
ENDLOOP;
};
LocalName: PROC [fileName: ROPE] RETURNS [localName: ROPE] ~ {
fullName: ROPE;
cp: FS.ComponentPositions;
[fullName, cp] ← FS.ExpandName[fileName];
localName ← fullName.Substr[cp.base.start, cp.ext.start+cp.ext.length];
};
Commander.Register[key: "FourColorSeparation", proc: ColorSeparateCommand, doc: "FourColorSeparation fileStem produces the <black, cyan, magenta, yellow> AIS files from <red, green, blue> AIS input files"];
}.