DIRECTORY ImageGamuts, CalibratedColor, AIS, SampleCache, IO, FS, ColorPlotGamuts, UserProfileOps, ImagerColor, ImagerColorFns, Rope, CreateCalibration, CalibratedColorFns, Process, PrintColorXForms, ImagerPixel, Real, TRCData; ImageGamutsImpl: CEDAR PROGRAM IMPORTS AIS, SampleCache, UserProfileOps, ColorPlotGamuts, CalibratedColor, CalibratedColorFns, IO, FS,Rope, CreateCalibration, Process, ImagerColorFns, PrintColorXForms, ImagerPixel, Real, TRCData EXPORTS ImageGamuts ~ BEGIN OPEN ImageGamuts; State: TYPE ~ ColorPlotGamuts.State; Projection: TYPE ~ ColorPlotGamuts.Projection; RGBCalibration: TYPE = CalibratedColor.RGBCalibration; SampledCalibration: TYPE = CalibratedColor.SampledCalibration; Sample: TYPE = SampleCache.Sample; Cache: TYPE = SampleCache.Cache; RefCache: TYPE = SampleCache.RefCache; XYZ: TYPE = CalibratedColor.XYZ; CIELAB: TYPE = CalibratedColor.CIELAB; RGB: TYPE = ImagerColor.RGB; ROPE: TYPE = Rope.ROPE; InputData: TYPE = REF InputDataRec; InputDataRec: TYPE = RECORD[rgb: RGB]; CreateInputData: PUBLIC PROC [fileStem: ROPE, rgbCal: RGBCalibration] RETURNS [inputData: RefCache] ~ { aisFiles: AISFiles _ OpenFiles[fileStem]; nLines: NAT _ aisFiles[r].raster.scanCount; nPixels: NAT _ aisFiles[r].raster.scanLength; white: XYZ _ CalibratedColor.XYZFromRGB[[1,1,1], rgbCal]; ref: REF _ NIL; key: Sample; valid: BOOLEAN _ FALSE; inputData _ SampleCache.CreateRefCache[]; Process.SetPriority[Process.priorityBackground]; FOR line: NAT IN [0..nLines) DO FOR pixel: NAT IN [0..nPixels) DO key.s0 _ AIS.ReadSample[w: aisFiles[r].wRef,line: line, pixel: pixel]; key.s1 _ AIS.ReadSample[w: aisFiles[g].wRef,line: line, pixel: pixel]; key.s2 _ AIS.ReadSample[w: aisFiles[b].wRef,line: line, pixel: pixel]; [valid, ref] _ SampleCache.FetchRef[inputData, key]; IF NOT valid THEN { data: InputData _ NEW[InputDataRec]; data.rgb _ [key.s0/255.0, key.s1/255.0, key.s2/255.0]; SampleCache.StoreRef[inputData, key, data] }; ENDLOOP; ENDLOOP; CloseFiles[aisFiles]; }; OpenFiles: PUBLIC PROC [fileStem: ROPE] RETURNS [aisFiles: AISFiles] ~ { aisFiles[r].name _ FindFile[fileStem, "AISseparationKeys.red", "-red"]; aisFiles[g].name _ FindFile[fileStem, "AISseparationKeys.green", "-grn"]; aisFiles[b].name _ FindFile[fileStem, "AISseparationKeys.blue", "-blu"]; FOR c: AISColors IN [r..b] DO aisFiles[c].fRef _ AIS.OpenFile[aisFiles[c].name]; aisFiles[c].wRef _ AIS.OpenWindow[aisFiles[c].fRef]; aisFiles[c].raster _ AIS.ReadRaster[aisFiles[c].fRef] ENDLOOP; }; CloseFiles: PUBLIC PROC [aisFiles: AISFiles] ~ { FOR c: AISColors IN [r..b] DO AIS.CloseFile[aisFiles[c].fRef]; ENDLOOP; IF aisFiles[clipped].name#NIL THEN AIS.CloseFile[aisFiles[clipped].fRef]; }; CreateFiles: PUBLIC PROC [fileStem: ROPE, raster: AIS.Raster] RETURNS [aisFiles: AISFiles] ~ { aisFiles[r].name _ Rope.Cat[fileStem, "-red.ais"]; aisFiles[g].name _ Rope.Cat[fileStem, "-grn.ais"]; aisFiles[b].name _ Rope.Cat[fileStem, "-blu.ais"]; FOR c: AISColors IN [r..b] DO aisFiles[c].fRef _ AIS.CreateFile[aisFiles[c].name, raster]; aisFiles[c].wRef _ AIS.OpenWindow[aisFiles[c].fRef]; aisFiles[c].raster _ raster; ENDLOOP; aisFiles[clipped].raster _ NEW[AIS.RasterPart _ [ scanCount: raster.scanCount, scanLength: raster.scanLength, scanMode: raster.scanMode, bitsPerPixel: 0, linesPerBlock: -1, paddingPerBlock: 0 ]]; aisFiles[clipped].name _ Rope.Cat[fileStem, "-clipped.ais"]; aisFiles[clipped].fRef _ AIS.CreateFile[aisFiles[clipped].name, aisFiles[clipped].raster]; aisFiles[clipped].wRef _ AIS.OpenWindow[aisFiles[clipped].fRef]; }; FindFile: PUBLIC PROC [stem, key, default: ROPE] RETURNS [ROPE] ~ { fileList: LIST OF ROPE _ UserProfileOps.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 RETURN [NIL]; IF FileExists[fileList.first] THEN RETURN [fileList.first]; fileList _ fileList.rest }; ENDLOOP; }; PlotInputData: PUBLIC PROC [state: State, inputData: RefCache, mapData: REF, mapProc: MapProc, imageColorProc: ColorProc _ NIL] ~ { plot: PROC[key: Sample, data: REF, hits: INT] = { inputData: InputData _ NARROW[data]; xyz: XYZ _ mapProc[key, inputData.rgb, mapData]; x,y: REAL; rgb: RGB _ imageColorProc[key]; [x,y] _ ColorPlotGamuts.MapValues[state, xyz]; ColorPlotGamuts.MarkPoint[state, Real.Round[x], Real.Round[y], rgb]; }; Process.SetPriority[Process.priorityBackground]; SampleCache.EnumerateRefCache[inputData, plot]; }; GetCalibrations: PUBLIC PROC[rgbAtom, sampledAtom: ATOM] RETURNS[rgbCal: RGBCalibration, sampledCal: SampledCalibration] = { rgbCal _ CreateCalibration.CreateRGB[CreateCalibration.GetRGBDataValues[rgbAtom]]; sampledCal _ CreateCalibration.CreateSampled[CreateCalibration.GetSampledFiles[sampledAtom], sampledAtom]; }; MakeChromaPlot: PUBLIC PROC [pi: PlotInfo, xAxis, yAxis: Projection, mapInfo: MapInfo] ~ { rgbState: State _ ColorPlotGamuts.StateFromRGBCalibration[pi.rgbCal, xAxis, yAxis, pi.res, ColorPlotGamuts.RGBRainbow, pi.rgbCal]; sampledState: State _ ColorPlotGamuts.StateFromCalibration[pi.sampledCal, xAxis, yAxis, pi.res, ColorPlotGamuts.SampledRainbow, pi.sampledCal]; inputData: RefCache _ pi.inputData; IF inputData = NIL THEN { inputData _ CreateInputData[pi.aisRoot, pi.rgbCal]; pi.inputData _ inputData}; ColorPlotGamuts.RGBSampleAndPlot[rgbState, pi.rgbCal, 256, ColorPlotGamuts.HueCircle]; ColorPlotGamuts.SampleAndPlot[sampledState, pi.sampledCal, 256, ColorPlotGamuts.HueCircle]; IF mapInfo.rgbState THEN PlotInputData[rgbState, inputData, mapInfo.mapData, mapInfo.mapProc, Rainbow] ELSE PlotInputData[sampledState, inputData, mapInfo.mapData, mapInfo.mapProc, Rainbow]; ColorPlotGamuts.StatesToInterpress[states: LIST[rgbState, sampledState], ipName: Rope.Cat[pi.ipRoot, ".ip"], label: TRUE, note: pi.note, labelColor: pi.labelColor, bleedBackground: pi.bleedBackground]; }; MakeLStarPlot: PUBLIC PROC [pi: PlotInfo, xAxis: Projection, mapInfo: MapInfo] ~ { rgbState: State _ ColorPlotGamuts.StateFromRGBCalibration[pi.rgbCal, xAxis, lStar, pi.res, ColorPlotGamuts.White, pi.rgbCal]; sampledState: State _ ColorPlotGamuts.StateFromCalibration[pi.sampledCal, xAxis, lStar, pi.res, ColorPlotGamuts.Black, pi.sampledCal]; inputData: RefCache _ pi.inputData; states: LIST OF State _ LIST[sampledState, rgbState]; IF inputData = NIL THEN { inputData _ CreateInputData[pi.aisRoot, pi.rgbCal]; pi.inputData _ inputData}; ColorPlotGamuts.RGBSampleAndPlot[rgbState, pi.rgbCal, 8, ColorPlotGamuts.WholeGamut]; ColorPlotGamuts.SampleAndPlot[sampledState, pi.sampledCal, 16, ColorPlotGamuts.WholeGamut, FALSE]; IF mapInfo.rgbState THEN PlotInputData[rgbState, inputData, mapInfo.mapData, mapInfo.mapProc, SatRainbow] ELSE { PlotInputData[sampledState, inputData, mapInfo.mapData, mapInfo.mapProc, SatRainbow]; states _ LIST[rgbState, sampledState]; }; ColorPlotGamuts.StatesToInterpress[states: states, ipName: Rope.Cat[pi.ipRoot, ".ip"], label: TRUE, note: pi.note, labelColor: pi.labelColor, bleedBackground: pi.bleedBackground]; }; Make3LABViews: PUBLIC PROC [pi: PlotInfo, mapInfo: MapInfo] ~ { ipRoot: ROPE _ pi.ipRoot; pi.ipRoot _ Rope.Cat[ipRoot, "AB"]; MakeChromaPlot[pi: pi, xAxis: aStar, yAxis: bStar, mapInfo: mapInfo]; pi.ipRoot _ Rope.Cat[ipRoot, "AL"]; MakeLStarPlot[pi: pi, xAxis: aStar, mapInfo: mapInfo]; pi.ipRoot _ Rope.Cat[ipRoot, "BL"]; MakeLStarPlot[pi: pi, xAxis: bStar, mapInfo: mapInfo]; }; Rainbow: ColorProc = { RETURN[[R: sample.s0/255.0, G: sample.s1/255.0, B: sample.s2/255.0]]; }; DoSat: PROC[in: RGB] RETURNS[out: RGB] = { hsl: ImagerColorFns.HSL_ ImagerColorFns.HSLFromRGB[boundRGB[in]]; boundRGB: PROC[val: RGB] RETURNS[RGB] = { RETURN[[R: MAX[MIN[val.R, 1],0], G: MAX[MIN[val.G, 1],0], B: MAX[MIN[val.B, 1],0]]]}; out _ ImagerColorFns.RGBFromHSL[[H: hsl.H, S: hsl.S, L: 0.5]]; }; SatRainbow: ColorProc = { rgb: RGB _ [R: sample.s0/255.0, G: sample.s1/255.0, B: sample.s2/255.0]; rgb _ DoSat[rgb]; RETURN[rgb]; }; SatRGB: ColorPlotGamuts.GetColorProc = { --assumes data is RGBCalibration cal: RGBCalibration _ NARROW[data]; rgb: RGB _ CalibratedColor.RGBFromXYZ[xyz, cal]; rgb _ DoSat[rgb]; RETURN[rgb]; }; SatSampled: ColorPlotGamuts.GetColorProc = { --assumes data is RGBCalibration cal: SampledCalibration _ NARROW[data]; triple: CalibratedColor.Triple _ CalibratedColor.TripleFromXYZ[xyz, cal].triple; rgb: RGB _ [triple.v0, triple.v1, triple.v2]; rgb _ DoSat[rgb]; RETURN[rgb]; }; GetPlotInfo: PUBLIC PROC [aisRoot, ipRoot, note: ROPE, res: NAT, rgbCal: RGBCalibration, sampledCal: SampledCalibration, labelColor: ImagerColor.Color, bleedBackground: BOOLEAN] RETURNS[PlotInfo] = { RETURN[[aisRoot: aisRoot, ipRoot: ipRoot, note: note, res: res, rgbCal: rgbCal, sampledCal: sampledCal, labelColor: labelColor, bleedBackground: bleedBackground]]; }; GetMonitorMapInfo: PUBLIC PROC [rgbCal: RGBCalibration] RETURNS[MapInfo] = { RETURN[[mapProc: RGBMap, mapData: rgbCal, rgbState: TRUE]]; }; GetMappedMapInfo: PUBLIC PROC [tables: PrintColorXForms.MatrixTables, rgbCal: RGBCalibration] RETURNS[MapInfo] = { data: MatrixMapData _ NEW[MatrixMapDataRec _ [ tables: tables, rgbCal: rgbCal ]]; RETURN[[mapProc: MatrixMap, mapData: data, rgbState: TRUE]]; }; GetPrinterMapInfo: PUBLIC PROC [tables: PrintColorXForms.MatrixTables, sampledCal: SampledCalibration] RETURNS[MapInfo] = { data: PrinterMapData _ NEW[PrinterMapDataRec _ [ tables: tables, sampledCal: sampledCal ]]; RETURN[[mapProc: PrinterMap, mapData: data, rgbState: FALSE]]; }; RGBMap: PUBLIC MapProc = { rgbCal: RGBCalibration _ NARROW[data]; xyz: XYZ _ CalibratedColor.XYZFromRGB[rgb, rgbCal]; RETURN[xyz]; }; MatrixMap: PUBLIC MapProc = { mmData: MatrixMapData _ NARROW[data]; mapped: Sample _ MatrixMapProc[rgbBytes, mmData.tables]; xyz: XYZ _ CalibratedColor.XYZFromRGB[[R: mapped.s0/255.0, G: mapped.s1/255.0, B: mapped.s2/255.0], mmData.rgbCal]; RETURN[xyz]; }; PrinterMap: PUBLIC MapProc = { pmData: PrinterMapData _ NARROW[data]; mapped: Sample _ MatrixMapProc[rgbBytes, pmData.tables]; xyz: XYZ _ CalibratedColor.XYZFromTriple[ [v0: mapped.s0/255.0, v1: mapped.s1/255.0, v2: mapped.s2/255.0], pmData.sampledCal]; RETURN[xyz]; }; AdjustFiles: PUBLIC PROC [fileStem, adjusted: ROPE, proc: SampleProc] ~ { inFiles: AISFiles _ OpenFiles[fileStem]; outFiles: AISFiles _ CreateFiles[adjusted, inFiles[r].raster]; nLines: NAT _ inFiles[r].raster.scanCount; nPixels: NAT _ inFiles[r].raster.scanLength; key, sample: Sample; valid: BOOLEAN _ FALSE; cache: Cache _ SampleCache.Create[]; Process.SetPriority[Process.priorityBackground]; FOR line: NAT IN [0..nLines) DO FOR pixel: NAT IN [0..nPixels) DO key.s0 _ AIS.ReadSample[w: inFiles[r].wRef,line: line, pixel: pixel]; key.s1 _ AIS.ReadSample[w: inFiles[g].wRef,line: line, pixel: pixel]; key.s2 _ AIS.ReadSample[w: inFiles[b].wRef,line: line, pixel: pixel]; [valid, sample] _ SampleCache.Fetch[cache, key]; IF NOT valid THEN { sample _ proc[key]; SampleCache.Store[cache, key, sample] }; AIS.WriteSample[w: outFiles[r].wRef,value: sample.s0, line: line, pixel: pixel]; AIS.WriteSample[w: outFiles[g].wRef,value: sample.s1, line: line, pixel: pixel]; AIS.WriteSample[w: outFiles[b].wRef,value: sample.s2, line: line, pixel: pixel]; AIS.WriteSample[w: outFiles[clipped].wRef,value: sample.s3, line: line, pixel: pixel]; ENDLOOP; ENDLOOP; CloseFiles[inFiles]; CloseFiles[outFiles]; }; SaturationMatrix: PUBLIC PROC [rgbToLStar: PrintColorXForms.TRCTable, saturation: REAL, printerDMax: REAL] RETURNS [PrintColorXForms.MatrixTables]~ { matrix: PrintColorXForms.MatrixN _ PrintColorXForms.IdentityMatrix[]; RETURN[PrintColorXForms.InitMatrixTables[ rgbToLStar: rgbToLStar, densityToDotArea: PrintColorXForms.DensityToLStar[printerDMax], printerDMax: printerDMax, saturation: saturation, contrast: -0.0, matrix: matrix]]; }; MatrixMapProc: PROC[in: Sample, matrixTables: PrintColorXForms.MatrixTables] RETURNS [out: Sample] = { rgbIn: ImagerPixel.PixelBuffer _ ImagerPixel.NewPixels[3,1]; cmyOut: ImagerPixel.PixelBuffer _ ImagerPixel.NewPixels[3,1]; maxSampleIn: ARRAY [0..3) OF CARDINAL _ [255, 255, 255]; rgbIn[0][0] _ in.s0; rgbIn[1][0] _ in.s1; rgbIn[2][0] _ in.s2; PrintColorXForms.MatrixTransform[maxSampleIn, rgbIn, cmyOut, matrixTables]; out.s0 _ 255-cmyOut[0][0]; out.s1 _ 255-cmyOut[1][0]; out.s2 _ 255-cmyOut[2][0]; out.s3 _ 0; }; AdjustWithMatrix: PUBLIC PROC [fileStem, adjusted: ROPE, matrixTables: PrintColorXForms.MatrixTables] ~ { rgbIn: ImagerPixel.PixelBuffer _ ImagerPixel.NewPixels[3,1]; cmyOut: ImagerPixel.PixelBuffer _ ImagerPixel.NewPixels[3,1]; maxSampleIn: ARRAY [0..3) OF CARDINAL _ [255, 255, 255]; map: SampleProc = { rgbIn[0][0] _ in.s0; rgbIn[1][0] _ in.s1; rgbIn[2][0] _ in.s2; PrintColorXForms.MatrixTransform[maxSampleIn, rgbIn, cmyOut, matrixTables]; out.s0 _ 255-cmyOut[0][0]; out.s1 _ 255-cmyOut[1][0]; out.s2 _ 255-cmyOut[2][0]; out.s3 _ 0; }; AdjustFiles[fileStem, adjusted, map]; }; AdjustRGBToLStar: PUBLIC PROC [fileStem, adjusted: ROPE, array: ARRAY[0..255] OF BYTE] ~ { map: SampleProc = { out.s0 _ array[in.s0]; out.s1 _ array[in.s1]; out.s2 _ array[in.s2]; out.s3 _ 0; }; AdjustFiles[fileStem, adjusted, map]; }; AdjustOutOfGamut: PUBLIC PROC [fileStem, adjusted: ROPE, useCIELAB: BOOLEAN _ FALSE] ~ { rgbCal: RGBCalibration; sampledCal: SampledCalibration; sampleWhite, rgbWhite: XYZ; map: SampleProc = { clipped: BOOLEAN; xyz: XYZ _ CalibratedColor.XYZFromRGB[[in.s0/255.0, in.s1/255.0, in.s2/255.0],rgbCal]; IF useCIELAB THEN { cielab: CIELAB _ CalibratedColorFns.CIELABFromXYZ[xyz,rgbWhite]; xyz _ [cielab.lStar, cielab.aStar, cielab.bStar]; }; [,,clipped] _ CalibratedColor.TripleFromXYZ[xyz,sampledCal, 0.1]; IF clipped THEN out _ [0,0,0,1] ELSE { out.s0 _ in.s0; out.s1 _ in.s1; out.s2 _ in.s2; out.s3 _ 0; }; }; [rgbCal, sampledCal] _ GetCalibrations[$Conrac, $Cromalin]; sampleWhite _ CalibratedColor.XYZFromTriple[[1,1,1], sampledCal]; rgbWhite _ CalibratedColor.XYZFromRGB[[1,1,1], rgbCal]; IF useCIELAB THEN FOR v1: NAT IN [0..8) DO FOR v2: NAT IN [0..8) DO FOR v3: NAT IN [0..8) DO xyz: XYZ; cielab: CIELAB; xyz.X _ sampledCal.cieX[v1][v2][v3]; xyz.Y _ sampledCal.cieY[v1][v2][v3]; xyz.Z _ sampledCal.cieX[v1][v2][v3]; cielab _ CalibratedColorFns.CIELABFromXYZ[xyz,sampleWhite]; sampledCal.cieX[v1][v2][v3] _ cielab.lStar; sampledCal.cieY[v1][v2][v3] _ cielab.aStar; sampledCal.cieZ[v1][v2][v3] _ cielab.bStar; ENDLOOP; ENDLOOP; ENDLOOP; AdjustFiles[fileStem, adjusted, map]; }; RGBToLStar: ARRAY[0..255] OF BYTE _ [0, 9, 18, 26, 33, 39, 44, 48, 52, 56, 60, 63, 66, 69, 72, 74, 77, 79, 81, 84, 86, 88, 90, 92, 94, 96, 97, 99, 101, 103, 104, 106, 107, 109, 110, 112, 113, 115, 116, 117, 119, 120, 121, 123, 124, 125, 126, 128, 129, 130, 131, 132, 133, 134, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 151, 152, 153, 154, 155, 156, 157, 158, 159, 159, 160, 161, 162, 163, 163, 164, 165, 166, 167, 167, 168, 169, 170, 171, 171, 172, 173, 174, 174, 175, 176, 176, 177, 178, 179, 179, 180, 181, 181, 182, 183, 183, 184, 185, 185, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 192, 193, 194, 194, 195, 196, 196, 197, 197, 198, 198, 199, 200, 200, 201, 201, 202, 203, 203, 204, 204, 205, 205, 206, 206, 207, 208, 208, 209, 209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 215, 215, 216, 216, 217, 217, 218, 218, 219, 219, 220, 220, 221, 221, 222, 222, 223, 223, 224, 224, 225, 225, 225, 226, 226, 227, 227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 232, 233, 233, 234, 234, 235, 235, 236, 236, 236, 237, 237, 238, 238, 239, 239, 240, 240, 240, 241, 241, 242, 242, 242, 243, 243, 244, 244, 245, 245, 245, 246, 246, 247, 247, 247, 248, 248, 249, 249, 249, 250, 250, 251, 251, 251, 252, 252, 253, 253, 253, 254, 254, 255, 255]; AdjustRGBToLStarGC: PUBLIC PROC [fileStem, adjusted: ROPE] ~ { map: SampleProc = { gc: BYTE _ MIN[in.s0, in.s1, in.s2]; newgc: BYTE _ RGBToLStar[gc]; r: NAT _ in.s0-gc+newgc; g: NAT _ in.s1-gc+newgc; b: NAT _ in.s2-gc+newgc; IF r >255 OR g>255 OR b>255 THEN out.s3 _ 1 ELSE out.s3 _ 0; out.s0 _ MIN[255, r]; out.s1 _ MIN[255, g]; out.s2 _ MIN[255, b]; }; AdjustFiles[fileStem, adjusted, map]; }; CMYToLStar: ARRAY[0..255] OF BYTE _ [0, 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6, 6, 6, 7, 7, 8, 8, 8, 9, 9, 10, 10, 10, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 30, 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37, 38, 38, 39, 39, 40, 40, 41, 42, 42, 43, 43, 44, 44, 45, 45, 46, 46, 47, 47, 48, 49, 49, 50, 50, 51, 51, 52, 52, 53, 54, 54, 55, 55, 56, 57, 57, 58, 58, 59, 59, 60, 61, 61, 62, 63, 63, 64, 64, 65, 66, 66, 67, 68, 68, 69, 70, 70, 71, 72, 72, 73, 74, 74, 75, 76, 76, 77, 78, 79, 79, 80, 81, 81, 82, 83, 84, 84, 85, 86, 87, 88, 88, 89, 90, 91, 92, 92, 93, 94, 95, 96, 96, 97, 98, 99, 100, 101, 102, 103, 104, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 121, 122, 123, 124, 125, 126, 127, 129, 130, 131, 132, 134, 135, 136, 138, 139, 140, 142, 143, 145, 146, 148, 149, 151, 152, 154, 156, 158, 159, 161, 163, 165, 167, 169, 171, 174, 176, 178, 181, 183, 186, 189, 192, 195, 199, 203, 207, 211, 216, 222, 229, 237, 246, 255]; AdjustCMYToLStar: PUBLIC PROC [fileStem, adjusted: ROPE] ~ { map: SampleProc = { c: NAT _ 255-in.s0; m: NAT _ 255-in.s1; y: NAT _ 255-in.s2; gc: BYTE _ MIN[c,m,y]; newgc: BYTE _ CMYToLStar[gc]; r: NAT _ 255-(c-gc+newgc); g: NAT _ 255-(m-gc+newgc); b: NAT _ 255-(y-gc+newgc); IF r >255 OR g>255 OR b>255 THEN out.s3 _ 1 ELSE out.s3 _ 0; out.s0 _ MIN[255, r]; out.s1 _ MIN[255, g]; out.s2 _ MIN[255, b]; }; AdjustFiles[fileStem, adjusted, map]; }; ConracToLStarTRC: PROC RETURNS[trc: PrintColorXForms.TRCTable] = { trc _ NEW[PrintColorXForms.TRCTableRec]; FOR i: NAT IN [0..256) DO trc[i] _ ConracToLStar[i]; ENDLOOP; }; ConracToLStar: ARRAY[0..255] OF BYTE _ [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 9, 11, 14, 16, 19, 22, 25, 29, 32, 35, 37, 39, 42, 44, 46, 48, 51, 53, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 83, 85, 87, 88, 90, 91, 93, 94, 95, 97, 98, 100, 101, 103, 104, 106, 107, 109, 110, 112, 113, 114, 116, 117, 118, 119, 121, 122, 123, 125, 126, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 143, 144, 145, 146, 147, 149, 150, 151, 152, 153, 153, 154, 155, 156, 157, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 168, 169, 170, 171, 172, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 181, 182, 183, 184, 185, 185, 186, 187, 188, 189, 189, 190, 191, 192, 193, 193, 194, 195, 196, 197, 197, 198, 199, 200, 201, 201, 202, 203, 204, 205, 205, 206, 207, 208, 208, 209, 209, 210, 211, 212, 212, 213, 214, 215, 216, 216, 217, 218, 218, 219, 219, 220, 220, 221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 227, 227, 228, 228, 229, 230, 230, 231, 231, 232, 232, 233, 233, 234, 234, 235, 235, 236, 236, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 245, 246, 246, 247, 247, 247, 248, 248, 249, 249, 249, 250, 250, 251, 251, 251, 252, 252, 253, 253, 253, 254, 254, 255, 255]; END. ΆImageGamutsImpl.mesa Copyright Σ 1987 by Xerox Corporation. All rights reserved. Maureen Stone, July 27, 1989 1:02:44 pm PDT Reads images, maps colors, Plots colors AISColors: TYPE = {r,g,b, clipped}; AISFile: TYPE = RECORD[name: ROPE _ NIL, fRef: AIS.FRef _ NIL, wRef: AIS.WRef _ NIL, raster: AIS.Raster _ NIL]; AISFiles: TYPE = ARRAY AISColors OF AISFile; Read Images Creates a ref cache of InputData values for an RGB image Does all the usual AIS open stuff closes the files in the handle Does all the usual AIS open stuff Read and Write Log files LogInputData: PROC [refCache: SampleCache.RefCache, logName, note: ROPE] ~ { log: IO.STREAM _ FS.StreamOpen[logName, $create]; logEntry: PROC[key: Sample, data: REF, hits: INT] = { in: InputData _ NARROW[data]; IO.PutF[log,"n: %g RGB: %g %g %g ", IO.int[hits+1], IO.int[key.s0], IO.int[key.s1], IO.int[key.s2]]; IO.PutF[log,"XYZ: %g %g %g ", IO.real[in.xyz.X], IO.real[in.xyz.Y], IO.real[in.xyz.Z]]; IO.PutF[log,"CIELAB: %g %g %g\n", IO.real[in.cielab.lStar], IO.real[in.cielab.aStar], IO.real[in.cielab.bStar]]; }; IO.PutF[log, "%g\n", IO.rope[note]]; IO.PutF[log,"probes: %g hits: %g entries: %g\n", IO.int[refCache.probes], IO.int[refCache.hits], IO.int[refCache.entries]]; SampleCache.EnumerateRefCache[refCache, logEntry]; IO.Close[log]; }; ReadInputData: PROC [logName: ROPE] RETURNS [inputData: SampleCache.RefCache] = { data: InputData _ NEW[InputDataRec]; key: Sample; log: STREAM _ FS.StreamOpen[logName]; checkKeyword: PROC[keyword: ROPE] = { word: ROPE; [word, ] _ IO.GetTokenRope[stream]; IF NOT Rope.Match[keyword, word, FALSE] THEN ERROR; [] _ IO.GetChar[stream]; --strip off the : }; inputData _ SampleCache.CreateRefCache[]; [] _ IO.GetToken checkKeyword["n"]; hits _ IO.GetInt[stream]; checkKeyword["RGB"]; key.s0 _ IO.GetInt[stream]; --red key.s1 _ IO.GetInt[stream]; --green key.s2 _ IO.GetInt[stream]; --blue checkKeyword["XYZ"]; data.xyz.X _ IO.GetReal[stream]; --X data.xyz.Y _ IO.GetReal[stream]; --Y data.xyz.Z _ IO.GetReal[stream]; --Z checkKeyword["CIELAB"]; data.cielab.lStar _ IO.GetReal[stream]; --L* data.cielab.aStar _ IO.GetReal[stream]; --a* data.cielab.bStar _ IO.GetReal[stream]; --b* SampleCache.StoreRef[inputData, key, data] }; Plot Image Gamuts Enumerates the input data and makes a plot Mapped Plots MatrixMapData: TYPE = REF MatrixMapDataRec; MatrixMapDataRec: TYPE = RECORD [tables: PrintColorXForms.MatrixTables, rgbCal: RGBCalibration]; -- used to see mapped values PrinterMapData: TYPE = REF PrinterMapDataRec; PrinterMapDataRec: TYPE = RECORD [tables: PrintColorXForms.MatrixTables, sampledCal: SampledCalibration]; -- used to see printed values Map Image Gamuts SampleProc: TYPE = PROC[in: Sample] RETURNS[out: Sample]; Opens the files indicated by the fileStem and creates files adjusted by lightness Maps R, G, B through LStar map independently. Can use either ConracToLStar or RGBToLStar for the array. This works like a gamma correction Maps R, G, B through LStar map independently. Can use either ConracToLStar or RGBToLStar for the array. This works like a gamma correction Makes an image that is black wherever the rgb to xyz (or cielab) to cmy conversion is out-of-gamut, otherwise just copy the color over. convert the sampled calibration to CIELAB. Maps MIN[R,G,B] through the RGBToLStar trc and adds it back into the image Maps MIN[cmy] through the CMYToLStar trc and adds it back into the image CMYToLStar is derived from RGBToLStar, so this whole thing is highly dubious Κƒ˜code•Mark outsideHeaderšœ™Kšœ<™Kšœœ˜"Kšœœ˜ Kšœ œ˜&Kšœœœ˜ Kšœœœ˜&Kšœœœ˜Kšœœœ˜—˜Kšœ œ™#Kšœ œœœœœœœœ œ œ™oKšœ œœ œ ™,K˜Kšœ œœ˜$Kšœœœœ˜&—head™ š Οnœœœ œœ˜gK™8Kšœ)˜)Kšœœ ˜+Kšœ œ!˜-K˜9Kšœœœ˜K˜ Kšœœœ˜Kšœ)˜)Kšœ0˜0šœœœ ˜šœœœ˜!Kšœ œ:˜FKšœ œ:˜FKšœ œ:˜FKšœ4˜4šœœœ˜Kšœœ˜$Kšœ6˜6Kšœ*˜*K˜—Kšœ˜—Kšœ˜—K˜K˜K˜—š Ÿ œœœ œœ˜HK™!KšœG˜GKšœI˜IKšœH˜Hšœœ˜Kšœœ˜2Kšœœ˜4Kšœœ˜5Kšœ˜—K˜—šŸ œœœ˜0K™Kš œœœœœ˜GKšœœœœ#˜IK˜—š Ÿ œœœ œ œ œ˜^K™!Kšœ2˜2Kšœ3˜3Kšœ2˜2šœœ˜Kšœœ&˜˜ZKšœœ$˜@K˜—š Ÿœ œœœœ˜Cšœ œœœ˜/Jšœ$˜$Jšœ˜Jšœ ˜ —šœ˜procš Ÿ œ œœœ œœ˜Lšœœœœ˜-šΟbΠbk œœ˜Jšœœ˜ Jšœ ˜Jšœ˜——Jšœœ ˜ Jšœ œ˜J˜—Kšœ œ˜$Kšœ œ˜;Jšœ˜Jšœ˜Jšœ˜—J˜J˜——™šŸ œœ1œ™LKšœ œœ™1šœ œœœ™5Kšœœ™Kš œ"œœœœ™dKšœœœœ™WKšœ œœœ™pK™—Kšœœ ™$Kšœ/œœœ™{Kšœ2™2K™K™—šŸ œœ œœ%™QKšœœ™$K™ Kšœœœ™%šœœ œ™%Jšœœ™ Jšœ œ™#Jš œœœœœ™3JšœœΟc™*J™—Kšœ)™)K™K™Kšœœ™K™Kšœ œ™!Kšœ œ™#Kšœ œ™"K™Kšœ œ™$Kšœ œ™$Kšœ œ™$K™Kšœœ™,Kšœœ™,Kšœœ™,K™Kšœ*™*K™K™—L™—™š Ÿ œœœ.œ0œ˜ƒK™*šœœœœ˜1Kšœœ˜$Kšœœ*˜2Kšœœ˜ Kšœœ˜Kšœ.˜.KšœD˜DK˜—Kšœ0˜0Kšœ/˜/K˜K˜—šŸœ œœœ<˜|KšœR˜RKšœj˜jK˜—šŸœ œ?˜ZK˜Kšœ‚˜‚Kšœ˜Kšœ#˜#šœ œœ˜Kšœ3˜3Kšœ˜—KšœV˜VKšœ[˜[KšœœN˜fKšœS˜WKšœ+œEœQ˜ΙK˜—šŸ œ œ8˜RKšœ}˜}Kšœ†˜†Kšœ#˜#Kšœœœ œ˜5šœ œœ˜Kšœ3˜3Kšœ˜—K˜KšœU˜UKšœb˜bKšœœQ˜išœ˜KšœU˜UKšœ œ˜&K˜—Kšœ^œQ˜³K˜—šŸ œ œ%˜?Kšœœ ˜Kšœ#˜#KšœE˜EKšœ#˜#Jšœ6˜6Kšœ#˜#Jšœ6˜6K˜—šŸœ˜Kšœ?˜EK˜—š Ÿœœœœœ˜*Kšœœ*˜Aš œ œœœœ˜)KšœŸœœœŸœœœŸœœœ˜U—Kšœ>˜>K˜—šŸ œ˜Kšœœ@˜HKšœ˜Kšœ˜ K˜—š œ#’ ˜IKšœœ˜#Kšœœ(˜0Kšœ˜Kšœ˜ K˜—š  œ#’ ˜MKšœœ˜'KšœP˜PKšœœ%˜-Kšœ˜Kšœ˜ K˜——™ Kšœœœ™+KšœœœC’™~Kšœœœ™-KšœœœK’™ˆš Ÿ œ œœœjœœ˜ΗKšœ˜£K˜—šŸœ œœ ˜LKšœ.œ˜;K˜—šŸœ œAœ ˜ršœœ˜.Kšœ˜Kšœ˜K˜—Kšœ/œ˜K˜—šŸœœ ˜Kšœœ˜&Jšœœ+˜4Jšœ˜ K˜—šŸ œœ ˜Kšœœ˜%Kšœ8˜8Jšœœk˜tJšœ˜ K˜—šŸ œœ ˜Kšœœ˜&Kšœ8˜8šœœ!˜*JšœT˜T—Jšœ˜ K˜——™Kšœ œœ œ™9šŸ œœœœ˜IKšœQ™QKšœ(˜(Kšœ>˜>Kšœœ˜*Kšœ œ ˜,K˜Kšœœœ˜Kšœ$˜$Kšœ0˜0šœœœ ˜šœœœ˜!Kšœ œ9˜EKšœ œ9˜EKšœ œ9˜EKšœ0˜0šœœœ˜K˜Kšœ%˜%K˜—KšœQ˜QKšœQ˜QKšœQ˜QKšœW˜WKšœ˜—Kšœ˜—Kšœ˜Kšœ˜K˜K˜—š Ÿœœœ5œœœ#˜–KšœE˜Ešœ#˜)Kšœ˜Kšœ?˜?Kšœ˜Kšœ˜Kšœ˜Kšœ˜—K˜—šŸ œœS˜fK˜Ÿ œA™ŒK˜Ÿ œA™Œšœ˜Kšœ˜Kšœ˜Kšœ˜K˜ K˜—KšŸ œ˜%K˜K˜—š Ÿœœœœ œœ˜XK™SK™4Kšœ˜Kšœ˜K˜šœ˜Kšœ œ˜KšœœN˜Všœ œ˜Kšœœ2˜@Kšœ1˜1K˜—KšœA˜AKšœ œ˜šœ˜Kšœ˜Kšœ˜Kšœ˜K˜ K˜—K˜—Kšœ;˜;KšœA˜AKšœ7˜7K™+š œ œœœœ˜*šœœœ˜šœœœ˜Kšœœ˜ Kšœœ˜Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ;˜;Kšœ+˜+Kšœ+˜+Kšœ+˜+Kšœ˜—Kšœ˜—Kšœ˜—Kšœ%˜%K˜K˜—šŸ œœ œœ˜#Jšœγ ˜γ —šŸœœœœ˜>KšœœB™Jšœ˜Kšœœœ˜$Kšœœ˜Kšœœ˜Kšœœ˜Kšœœ˜Kš œœœœ œ ˜