CCImpl.mesa
Mik Lamming - March 4, 1985 10:16:33 am PST
DIRECTORY
AIS, IO, FS, Real, Rope, UPOps;
CCImpl: CEDAR PROGRAM
IMPORTS AIS, IO, FS, Real, UPOps
= BEGIN
TranslateTable: TYPE = REF TranslateTableRec;
TranslateTableRec: TYPE = ARRAY[0..255] OF REAL;
TRCTable: TYPE = REF TRCTableRec;
TRCTableRec: TYPE = ARRAY[0..255] OF NAT;
MatrixN: TYPE = REF MatrixSeq;
MatrixSeq: TYPE = RECORD[SEQUENCE nrows: INTEGER OF RowN];
RowN: TYPE = REF VecSeq;
VecSeq: TYPE = RECORD[SEQUENCE ncols: INTEGER OF Real0];
Real0: TYPE = REAL ← 0;
ReadTRC: PROC [trcFn:Rope.ROPE] RETURNS [trc: TRCTable] ~ {
in: IO.STREAMFS.StreamOpen[fileName: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[];
};
ReadMatrix: PROC [matrixFn:Rope.ROPE] RETURNS [matrix: MatrixN] ~ {
in :IO.STREAM;
matrix ← NEW[MatrixSeq[3]];
in ← FS.StreamOpen[fileName:matrixFn];
FOR i:NAT IN [0..2] DO
matrix[i] ← NEW[VecSeq[3]];
FOR j:NAT IN [0..2] DO
matrix[i][j] ← IO.GetReal[in];
ENDLOOP;
ENDLOOP;
IO.Close[in];
};
CCMode: TYPE = {Color3, Color4, UCR};
ApplyMatrix: PROC [
inStem, outStem: Rope.ROPE,     -- filename stems
matrix: MatrixN,        -- correction matrix
inTRCRed: TRCTable ← NIL,    -- red input TRC
inTRCGrn: TRCTable ← NIL,    -- green input TRC
inTRCBlu: TRCTable ← NIL,    -- blu input TRC
outTRCCyan: TRCTable ← NIL,   -- cyan device linearization trc
outTRCMag: TRCTable ← NIL,    -- magenta device linearization trc
outTRCYel: TRCTable ← NIL,    -- yellow device linearization trc
outTRCBlack: TRCTable ← NIL,   -- black device linearization trc
ucrTRC: TRCTable ← NIL,     -- Under Color Removal trc
bpTRC: TRCTable ← NIL,     -- black printer trc
mode: CCMode ← Color4,     -- Ouput: 3 color; 4 color or 4 color+UCR
normalize:BOOLEANTRUE    -- CC matrix rows need fixing to sum to 1
] ~ {
Buffer: TYPE = REF BufferRec;
BufferRec: TYPE = PACKED ARRAY [0..2048) OF [0..255];
redBufIn, grnBufIn, bluBufIn, cyanBufOut, magBufOut, yelBufOut, blackBufOut: Buffer;
redInF, grnInF, bluInF, cyanOutF, magOutF, yelOutF, blackOutF: AIS.FRef;
redInW, grnInW, bluInW, cyanOutW, magOutW, yelOutW, blackOutW: AIS.WRef;
raster: AIS.Raster ← NEW[AIS.RasterPart];
singular:BOOLEANFALSE;
m00, m01, m02, m10, m11, m12, m20, m21, m22: TranslateTable;
CreateTable: PROC [matrixEl:REAL, trc:TRCTable] RETURNS [table: TranslateTable] ~ {
-- creates table such that AIS pixel value i => matrixEl*(255-i)
-- This means AIS 0 = Dmax => 255*matrixEl
table ← NEW[TranslateTableRec];
IF trc=NIL THEN
FOR i: NAT IN [0..255] DO
table[i] ← (255-i)*matrixEl;
ENDLOOP
ELSE
FOR i: NAT IN [0..255] DO
table[i] ← (255-trc[i])*matrixEl;
ENDLOOP
};
Normalise: PROC[m:MatrixN] ~ {
FOR i: NAT IN [0..2] DO
sum: REAL ← 0;
FOR j:NAT IN [0..2] DO
sum ← sum + m[i][j];
ENDLOOP;
FOR j:NAT IN [0..2] DO
m[i][j] ← m[i][j] / sum;
ENDLOOP;
ENDLOOP;
};
CreateSeparation: PROC [stem, key, default: Rope.ROPE]
RETURNS [fd:AIS.FRef, wd:AIS.WRef] ~ {
fileList: LIST OF Rope.ROPE ← UPOps.Expand[
"%g%k|%g|%g|.%k|AISExtensions|AIS|",
IO.rope[stem],
IO.rope[key], IO.rope[default]];
fd ← AIS.CreateFile[name: fileList.first, raster: raster];
wd ← AIS.OpenWindow[fd];
};
OpenSeparation: PROC [stem, key, default: Rope.ROPE]
RETURNS [fd:AIS.FRef, wd:AIS.WRef] ~ {
fileList: LIST OF Rope.ROPE ← UPOps.Expand[
"%g%k|%g|%g|.%k|AISExtensions|AIS|",
IO.rope[stem],
IO.rope[key], IO.rope[default]];
DO {
FileExists: PROCEDURE [fileName:Rope.ROPE] RETURNS [answer:BOOLEAN←TRUE] = {
s:IO.STREAM ← FS.StreamOpen[fileName:fileName
! FS.Error => TRUSTED {
answer←FALSE;
GOTO notThere;
}];
IO.Close[s];
EXITS
notThere => NULL;
};
IF fileList = NIL THEN ERROR;
IF FileExists[fileList.first] THEN EXIT;
fileList ← fileList.rest
};
ENDLOOP;
fd ← AIS.OpenFile[name:fileList.first];
wd ← AIS.OpenWindow[fd];
};
CloseAll: PROC [] ~ {
CloseSeparation: PROC [fd:AIS.FRef, wd:AIS.WRef] = {
AIS.CloseWindow[wd];
AIS.CloseFile[fd];
};
CloseSeparation[redInF, redInW];
CloseSeparation[grnInF, grnInW];
CloseSeparation[bluInF, bluInW];
CloseSeparation[cyanOutF, cyanOutW];
CloseSeparation[magOutF, magOutW];
CloseSeparation[yelOutF, yelOutW];
IF mode=Color4 OR mode=UCR THEN
CloseSeparation[blackOutF, blackOutW];
};
Default: PROC [trc:TRCTable] RETURNS [initTrc:TRCTable] ~ {
IF trc=NIL THEN {
initTrc ← NEW[TRCTableRec ← ALL[0]];
FOR i: NAT IN [0..255] DO
initTrc[i] ← i;
ENDLOOP;
}
ELSE
initTrc ← trc;
};
outTRCCyan ← Default[outTRCCyan];
outTRCMag ← Default[outTRCMag];
outTRCYel ← Default[outTRCYel];
outTRCBlack ← Default[outTRCBlack];
bpTRC ← Default[bpTRC];
ucrTRC ← Default[ucrTRC];
IF normalize THEN Normalise[matrix];
m00 ← CreateTable[matrix[0][0], inTRCRed];
m01 ← CreateTable[matrix[0][1], inTRCGrn];
m02 ← CreateTable[matrix[0][2], inTRCBlu];
m10 ← CreateTable[matrix[1][0], inTRCRed];
m11 ← CreateTable[matrix[1][1], inTRCGrn];
m12 ← CreateTable[matrix[1][2], inTRCBlu];
m20 ← CreateTable[matrix[2][0], inTRCRed];
m21 ← CreateTable[matrix[2][1], inTRCGrn];
m22 ← CreateTable[matrix[2][2], inTRCBlu];
-- **** Open up the input files ***
[redInF, redInW] ← OpenSeparation[inStem, "AISseparationKeys.red", "-red"];
[grnInF, grnInW] ← OpenSeparation[inStem, "AISseparationKeys.green", "-green"];
[bluInF, bluInW] ← OpenSeparation[inStem, "AISseparationKeys.blue", "-blue"];
-- **** Create the output files ****
raster ← AIS.ReadRaster[redInF];
[cyanOutF, cyanOutW] ← CreateSeparation[outStem, "AISseparationKeys.cyan", "-cyan"];
[magOutF, magOutW] ← CreateSeparation[outStem, "AISseparationKeys.magenta", "-magenta"];
[yelOutF, yelOutW] ← CreateSeparation[outStem, "AISseparationKeys.yellow", "-yellow"];
-- **** Process files ***
redBufIn ← NEW[BufferRec];
grnBufIn ← NEW[BufferRec];
bluBufIn ← NEW[BufferRec];
cyanBufOut ← NEW[BufferRec];
magBufOut ← NEW[BufferRec];
yelBufOut ← NEW[BufferRec];
IF mode=Color4 OR mode=UCR THEN { -- Color3 doesn't make a black sep
[blackOutF, blackOutW] ← CreateSeparation[outStem, "AISseparationKeys.black", "-black"];
blackBufOut ← NEW[BufferRec];
};
FOR i:CARDINAL IN [0..raster.scanCount) DO TRUSTED {
-- read in a line of pixels
AIS.UnsafeReadLine[w:redInW, buffer:[length:raster.scanLength, addr:LOOPHOLE[redBufIn]], line:i];
AIS.UnsafeReadLine[w:grnInW, buffer:[length:raster.scanLength, addr:LOOPHOLE[grnBufIn]], line:i];
AIS.UnsafeReadLine[w:bluInW, buffer:[length:raster.scanLength, addr:LOOPHOLE[bluBufIn]], line:i];
-- Process each pixel on the line
FOR j: NAT IN [0..raster.scanLength) DO
-- get input pixel and apply input TRCs
r: NAT ← redBufIn[j];
g: NAT ← grnBufIn[j];
b: NAT ← bluBufIn[j];
c, m, y: NAT;
-- find out how much black is required: Color3 => NONE
k: NATMAX[r, g, b]; -- this is the black component
SELECT mode FROM
UCR => { -- UCR => subtract ucrTRC determined amount of black from r,g,b
-- need to adjust input values before correction for UCR
k ← ucrTRC[k];
r ← MIN[r + (255 - k), 255];
g ← MIN[g + (255 - k), 255];
b ← MIN[b + (255 - k), 255];
};
Color4 => { -- Black printer => just add bpTRC determined amount of black
k ← bpTRC[k];
}
ENDCASE => NULL;
-- apply 3*3 color corretcion matrix to input seps
c ← Real.RoundC[MAX[MIN[m00[r] + m01[g] + m02[b], 255], 0]];
m ← Real.RoundC[MAX[MIN[m10[r] + m11[g] + m12[b], 255], 0]];
y ← Real.RoundC[MAX[MIN[m20[r] + m21[g] + m22[b], 255], 0]];
-- apply output (normally only device linearisation) TRCs
cyanBufOut[j] ← outTRCCyan[255 - c];
magBufOut[j] ← outTRCMag[255 - m];
yelBufOut[j] ← outTRCYel[255 - y];
IF mode#Color3 THEN
blackBufOut[j] ← outTRCBlack[k];
ENDLOOP;
-- write out this line of results
IF mode#Color3 THEN
AIS.UnsafeWriteLine[w:blackOutW, buffer:[length:raster.scanLength, addr:LOOPHOLE[blackBufOut]], line:i];
AIS.UnsafeWriteLine[w:cyanOutW, buffer:[length:raster.scanLength, addr:LOOPHOLE[cyanBufOut]], line:i];
AIS.UnsafeWriteLine[w:magOutW, buffer:[length:raster.scanLength, addr:LOOPHOLE[magBufOut]], line:i];
AIS.UnsafeWriteLine[w:yelOutW, buffer:[length:raster.scanLength, addr:LOOPHOLE[yelBufOut]], line:i];
} -- end of trusted block
ENDLOOP;
-- shut up shop and go home
CloseAll[];
};
END.