<> <> <<>> 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.STREAM _ FS.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:BOOLEAN _ TRUE -- 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:BOOLEAN _ FALSE; 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: NAT _ MAX[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.