<<-- BuildTRCImpl.mesa>> <<-- Mik Lamming - December 11, 1984 1:22:03 pm PST>> <> DIRECTORY Buttons, ImagerColorMap, Commander, Containers, Convert, FS, Hist, Icons, ImagerColor, ImagerOps, IO, MessageWindow, Real, RealFns, Rope, Rules, Terminal, TRCViewer, UserProfileOps, UserProfile, ViewerClasses, ViewerOps, ViewerPrivate, ViewerTools; BuildTRCImpl: CEDAR MONITOR IMPORTS Buttons, ImagerColorMap, Commander, Containers, Convert, FS, Hist, Icons, IO, ImagerColor, ImagerOps, MessageWindow, Real, RealFns, Rope, Rules, Terminal, TRCViewer, UserProfileOps, UserProfile, ViewerOps, ViewerPrivate, ViewerTools SHARES Terminal = BEGIN LogFlag: Rope.ROPE _ "Log"; LinFlag: Rope.ROPE _ "Linear"; vt: Terminal.Virtual; DisplayState: TYPE = {bpp8, bpp24, off}; displayState: DisplayState _ off; displayKind: ATOM _ NIL; icon: Icons.IconFlavor _ Icons.NewIconFromFile["BuildTRC.icons", 0]; mapEntries: LIST OF ImagerColorMap.MapEntry; State: TYPE = REF StateRec; StateRec: TYPE = RECORD [ container: ViewerClasses.Viewer, linBut, logBut, negBut, shiftBut, rotateBut, initBut, simBut: Buttons.Button, setHistWhite, setHistBlack, setGamma, setInputModeBut, setOutputModeBut: Buttons.Button, showHistBut, calcHistBut, equaliseBut, histSourceBut, wdBut: Buttons.Button, trcFileBut, saveTRCBut, getTRCBut: Buttons.Button, inputScaleTypeIn, outputScaleTypeIn, histSourceTypeIn, wdTypeIn, trcFileTypeIn, whiteTypeIn, blackTypeIn, gammaTypeIn: ViewerClasses.Viewer, trcViewer: ViewerClasses.Viewer, wd: Rope.ROPE, maxInputDens, maxOutputDens: REAL _ 99.0, inputMode, outputMode: TRCViewer.FeedBackMode _ reflectance, connectMode: TRCViewer.ConnectMode _ linear, histoOn: BOOLEAN _ FALSE, addVertexOnShiftOrRotate: BOOLEAN _ FALSE, histo: Hist.Histogram _ NIL, simRed, simGrn, simBlu, simSat, simHue, simVal, simLight: BOOLEAN _ TRUE, gamma: REAL _ 2.2 ]; Simulate: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift: BOOL _ FALSE, control: BOOL _ FALSE] -- = { ENABLE UNWIND => NULL; state: State _ NARROW[clientData]; IF displayState=off THEN { vt _ Terminal.Current[]; IF NOT vt.hasColorDisplay THEN displayState _ off ELSE IF Terminal.GetColorMode[vt].full THEN { displayState_bpp24; displayKind _ ImagerOps.KindOf[ViewerPrivate.CreateContext[color]]; } ELSE IF Terminal.GetColorMode[vt].bitsPerPixelChannelA=8 THEN { displayKind _ ImagerOps.KindOf[ViewerPrivate.CreateContext[color]]; displayState_bpp8; mapEntries _ ImagerColorMap.StandardColorMapEntries[8]; } ELSE ERROR; -- sorry about this folks - I want to go home its late! UpdateImagerColorMap[state]; Buttons.SetDisplayStyle[state.simBut, $WhiteOnBlack]; } ELSE { Buttons.SetDisplayStyle[state.simBut, $BlackOnWhite]; displayState _ off; } }; UpdateImagerColorMap: PROC [state:State] ~ { GetByteRef: PROC [value:NAT] RETURNS [byteRef: NAT] ~ { reflectance:REAL; IF state.outputMode=density THEN reflectance _ RealFns.Power[10, - ((255 - value) / 255.0) * maxDensityOut] ELSE reflectance _ minROut + rangeR * value / 255.0; SELECT value FROM IN [1..254] => { reflectance _ RealFns.Power[reflectance, oneOverGamma]; }; ENDCASE; byteRef _ MAX[MIN[255, Real.RoundC[reflectance*255]], 0]; }; minROut, rangeR, maxDensityOut: REAL; err: BOOLEAN; oneOverGamma: REAL ; IF displayState=off THEN RETURN []; [state.gamma, err] _ GetRealFromViewer[state.gammaTypeIn]; IF err OR state.gamma <= 0 THEN { MessageWindow.Append["Gamma should be > 0", TRUE]; MessageWindow.Blink[]; RETURN []; }; oneOverGamma _ 1 / state.gamma; [maxDensityOut, err] _ GetDensityFromScaleViewer[state.outputScaleTypeIn, state.outputMode]; IF ~err THEN { trc: Hist.TRCVec _ TRCViewer.Get[state.trcViewer]; minROut _ TRCViewer.DensToRef[maxDensityOut]; rangeR _ 1 - minROut; IF displayState=bpp8 THEN { IF displayKind=$Dithered THEN FOR l: LIST OF ImagerColorMap.MapEntry _ mapEntries, l.rest WHILE l#NIL DO entry: ImagerColorMap.MapEntry _ l.first; red,green,blue: Terminal.ColorValue; [red,green,blue] _ Terminal.GetColor[vt:vt, aChannelValue:entry.mapIndex, bChannelValue:0]; IF state.simRed THEN red _ GetByteRef[trc[entry.red].out]; IF state.simGrn THEN green _ GetByteRef[trc[entry.green].out]; IF state.simBlu THEN blue _ GetByteRef[trc[entry.blue].out]; IF state.simSat THEN { rgb: ImagerColor.RGB; hsv: ImagerColor.HSV; hsv _ ImagerColor.HSVFromRGB[[entry.red/255.0, entry.green/255.0, entry.blue/255.0]]; hsv.S _ trc[Real.RoundC[hsv.S*255]].out/255.0; rgb _ ImagerColor.RGBFromHSV[hsv]; red _ GetByteRef[Real.RoundC[rgb.R*255]]; green _ GetByteRef[Real.RoundC[rgb.G*255]]; blue _ GetByteRef[Real.RoundC[rgb.B*255]]; }; IF state.simVal THEN { rgb: ImagerColor.RGB; hsv: ImagerColor.HSV; hsv _ ImagerColor.HSVFromRGB[[entry.red/255.0, entry.green/255.0, entry.blue/255.0]]; hsv.V _ trc[Real.RoundC[hsv.V*255]].out/255.0; rgb _ ImagerColor.RGBFromHSV[hsv]; red _ GetByteRef[Real.RoundC[rgb.R*255]]; green _ GetByteRef[Real.RoundC[rgb.G*255]]; blue _ GetByteRef[Real.RoundC[rgb.B*255]]; }; IF state.simHue THEN { rgb: ImagerColor.RGB; hsv: ImagerColor.HSV; hsv _ ImagerColor.HSVFromRGB[[entry.red/255.0, entry.green/255.0, entry.blue/255.0]]; hsv.H _ trc[Real.RoundC[hsv.H*255]].out/255.0; rgb _ ImagerColor.RGBFromHSV[hsv]; red _ GetByteRef[Real.RoundC[rgb.R*255]]; green _ GetByteRef[Real.RoundC[rgb.G*255]]; blue _ GetByteRef[Real.RoundC[rgb.B*255]]; }; IF state.simLight THEN { rgb: ImagerColor.RGB; hsl: ImagerColor.HSL; hsl _ ImagerColor.HSLFromRGB[[entry.red/255.0, entry.green/255.0, entry.blue/255.0]]; hsl.L _ trc[Real.RoundC[hsl.L*255]].out/255.0; rgb _ ImagerColor.RGBFromHSL[hsl]; red _ GetByteRef[Real.RoundC[rgb.R*255]]; green _ GetByteRef[Real.RoundC[rgb.G*255]]; blue _ GetByteRef[Real.RoundC[rgb.B*255]]; }; Terminal.SetColor[vt:vt, aChannelValue:entry.mapIndex, bChannelValue:0, red:red, green:green, blue:blue]; ENDLOOP ELSE FOR i: NAT IN [0..255] DO red,green,blue: Terminal.ColorValue; [red,green,blue] _ Terminal.GetColor[vt:vt, aChannelValue:i, bChannelValue:0]; IF state.simRed THEN red _ GetByteRef[trc[i].out]; IF state.simGrn THEN green _ GetByteRef[trc[i].out]; IF state.simBlu THEN blue _ GetByteRef[trc[i].out]; Terminal.SetColor[vt:vt, aChannelValue:i, bChannelValue:0, red:red, green:green, blue:blue]; ENDLOOP; } ELSE FOR i: NAT IN [0..255] DO byteRef: NAT _ GetByteRef[trc[i].out]; IF state.simRed THEN Terminal.SetRedMap[vt, i, byteRef]; IF state.simGrn THEN Terminal.SetGreenMap[vt, i, byteRef]; IF state.simBlu THEN Terminal.SetBlueMap[vt, i, byteRef]; ENDLOOP; }; }; FixUpMap: TRCViewer.ChangeProc ~ { UpdateImagerColorMap[NARROW[clientData]] }; StartNewInstance: Commander.CommandProc ~ { AddButton: PROC [label: Rope.ROPE, proc: Buttons.ButtonProc, left, top: NAT, width:NAT _ 0, clientData: REF ANY _ state] RETURNS [b: Buttons.Button, right, bottom: NAT] ~ { b _ Buttons.Create[ info: [ parent: state.container, name: label, wx: left, wy: top, ww:width ], proc: proc, clientData: clientData ]; RETURN [b, left+b.ww, top+b.wh] }; AddTypeIn: PROC [left, top, width, height: NAT, init:Rope.ROPE _ NIL] RETURNS [t: ViewerClasses.Viewer, right, bottom: NAT] ~ { t _ ViewerTools.MakeNewTextViewer[ info:[ wx:left, wy:top, ww:width, wh:height, parent: state.container, border: FALSE, scrollable: FALSE, data: init]]; RETURN [t, left+t.ww, top+t.wh] }; pStream: IO.STREAM _ IO.RIS[cmd.commandLine]; empty:BOOLEAN _ FALSE; p1: Rope.ROPE; leftMargin: NAT ~ 2; row0: NAT ~ 2; colSep: NAT ~ 2; groupSep: NAT ~ 8; rowSep: NAT ~ 4; scaleTypeInWidth: NAT ~ 85; fileTypeInWidth: NAT ~ 160; wdTypeInWidth: NAT ~ 260; cardWidth: NAT ~ 40; fileNameButTab, butHt, nextX, nextY, tempY : NAT ; state: State _ NEW[StateRec]; p1 _ IO.GetTokenRope[pStream, IO.IDProc ! IO.EndOfStream => { empty _ TRUE; CONTINUE; }].token; state.simRed _ state.simGrn _ state.simBlu _ TRUE; state.simLight _ state.simHue _ state.simSat _ state.simVal _ FALSE; IF NOT empty AND Rope.Length[p1]>0 THEN { -- parameter present state.simRed _ state.simGrn _ state.simBlu _ FALSE; SELECT TRUE FROM Rope.Equal[p1, "-B", FALSE] => state.simBlu _ TRUE; Rope.Equal[p1, "-R", FALSE] => state.simRed _ TRUE; Rope.Equal[p1, "-G", FALSE] => state.simGrn _ TRUE; Rope.Equal[p1, "-H", FALSE] => state.simHue _ TRUE; Rope.Equal[p1, "-S", FALSE] => state.simSat _ TRUE; Rope.Equal[p1, "-V", FALSE] => state.simVal _ TRUE; Rope.Equal[p1, "-L", FALSE] => state.simLight _ TRUE; ENDCASE }; ScanProfile[state]; state.container _ Containers.Create[info: [name:Rope.Cat["TRC Builder", p1], scrollable:FALSE, icon:icon]]; state.container.class.bltH _ none; state.container.class.bltV _ none; nextX _ leftMargin; nextY _ row0; [state.linBut, nextX, tempY] _ AddButton["Linear", SetLinearMode, nextX, nextY]; Buttons.SetDisplayStyle[state.linBut, $WhiteOnBlack]; butHt _ tempY - row0; [state.logBut, nextX, ] _ AddButton["Log", SetLogMode, nextX+colSep, nextY]; [state.negBut, nextX, ] _ AddButton["Negative", Negate, nextX+colSep, nextY]; [state.shiftBut, nextX, ] _ AddButton["Shift", Shift, nextX+colSep, nextY]; [state.rotateBut, nextX, ] _ AddButton["Rotate", Rotate, nextX+colSep, nextY]; [state.initBut, nextX, ] _ AddButton["Init", InitTRC, nextX+colSep, nextY]; [] _ Rules.Create[info:[wx:nextX+groupSep/2-1, wy:0, ww:2, wh:row0+butHt+1, parent:state.container]]; [state.simBut, nextX, ] _ AddButton["Simulate", Simulate, nextX+groupSep, nextY]; [] _ Rules.Create[info:[wx:nextX+groupSep/2-1, wy:0, ww:2, wh:row0+2*(butHt+3), parent:state.container]]; fileNameButTab _ nextX+groupSep; [state.wdBut, nextX, ] _ AddButton["WD", SelectWD, fileNameButTab, nextY]; [state.wdTypeIn, nextX, nextY] _ AddTypeIn[fileNameButTab+40, nextY, wdTypeInWidth, butHt, state.wd]; FS.SetDefaultWDir[state.wd ! FS.Error => { MessageWindow.Append[IO.PutFR["Bad WD: %g is not a local directory", IO.rope[state.wd]], TRUE]; MessageWindow.Blink[]; CONTINUE}]; [] _ Rules.Create[info:[wx:0, wy:nextY+1, ww:1000, wh:2, parent:state.container]]; nextY _ nextY + rowSep; [state.setInputModeBut, nextX, ] _ AddButton["MaxDIn", SelectInScale, leftMargin, nextY]; [state.inputScaleTypeIn, nextX, ] _ AddTypeIn[nextX+colSep, nextY, scaleTypeInWidth, butHt, IO.PutFR["%g", IO.real[TRCViewer.DensToRef[state.maxOutputDens]]]]; [state.setOutputModeBut, nextX, ] _ AddButton["MaxDOut", SelectOutScale, nextX+colSep, nextY]; [state.outputScaleTypeIn, nextX, tempY] _ AddTypeIn[nextX+colSep, nextY, scaleTypeInWidth, butHt, IO.PutFR["%g", IO.real[TRCViewer.DensToRef[state.maxInputDens]]]]; [] _ Rules.Create[info:[wx:nextX+groupSep/2-1, wy:tempY+1, ww:1000, wh:2, parent:state.container]]; [state.trcFileBut, nextX, ] _ AddButton["TRC", SelectTRC, fileNameButTab, nextY]; [state.trcFileTypeIn, nextX, ] _ AddTypeIn[fileNameButTab+40, nextY, fileTypeInWidth, butHt]; [state.saveTRCBut, nextX, ] _ AddButton["Save", SaveTRC, nextX+colSep, nextY]; [state.getTRCBut, nextX, nextY] _ AddButton["Restore", ReadTRC, nextX+colSep, nextY]; [] _ Rules.Create[info:[wx:0, wy:nextY+1, ww:1000, wh:2, parent:state.container]]; nextY _ nextY + rowSep; [] _ Rules.Create[info:[wx:nextX+groupSep/2-1, wy:tempY+1, ww:2, wh:-2*(butHt+rowSep), parent:state.container]]; [state.setGamma, nextX, ] _ AddButton["Gamma", SelGamma, leftMargin, nextY]; [state.gammaTypeIn, nextX, tempY] _ AddTypeIn[nextX+colSep, nextY, scaleTypeInWidth, butHt, IO.PutFR["%g", IO.real[state.gamma]]]; [] _ Rules.Create[info:[wx:nextX+1, wy:tempY+3, ww:2, wh:-(butHt+5), parent:state.container]]; [state.setHistBlack, nextX, ] _ AddButton["Black", SelBlack, nextX+6, nextY]; [state.blackTypeIn, nextX, ] _ AddTypeIn[nextX+colSep, nextY, cardWidth, butHt, "0"]; [state.setHistWhite, nextX, ] _ AddButton["White", SelWhite, nextX, nextY]; [state.whiteTypeIn, nextX, ] _ AddTypeIn[nextX+colSep, nextY, cardWidth, butHt, "255"]; [state.histSourceBut, nextX, ] _ AddButton["Hist", SelectHist, fileNameButTab, nextY]; [state.histSourceTypeIn, nextX, ] _ AddTypeIn[fileNameButTab+40, nextY, fileTypeInWidth, butHt]; [state.showHistBut, nextX, ] _ AddButton["Off", ToggleHisto, nextX+colSep, nextY]; [state.calcHistBut, nextX, ] _ AddButton["Calc", CalcHisto, nextX+colSep, nextY]; [state.equaliseBut, nextX, nextY] _ AddButton["Eq", Equalise, nextX+colSep, nextY]; [] _ Rules.Create[info:[wx:0, wy:nextY+1, ww:1000, wh:2, parent:state.container]]; state.trcViewer _ ViewerOps.CreateViewer[ flavor: $TRCViewer, info: [ parent: state.container, wx: leftMargin, wy: nextY+rowSep, ww:100, wh:100]]; Containers.ChildYBound[state.container, state.trcViewer]; Containers.ChildXBound[state.container, state.trcViewer]; TRCViewer.SetMaxDensityIn[state.trcViewer, state.maxInputDens]; TRCViewer.SetMaxDensityOut[state.trcViewer, state.maxOutputDens]; TRCViewer.RegisterChangeProc[state.trcViewer, FixUpMap, state]; }; ScanProfile: PROC [state:State] ~ { tempRope: Rope.ROPE; state.wd _ UserProfile.Token["BuildTRC.WD", NIL]; IF state.wd=NIL THEN { state.wd _ Commander.PrependWorkingDir["a"]; state.wd _ Rope.Substr[state.wd, 0, Rope.Size[state.wd]-1]; }; state.maxInputDens _ Convert.RealFromRope[ tempRope _ UserProfile.Token[ "BuildTRC.MaxInputDensity", "1.3"] ! Convert.Error => { MessageWindow.Append[IO.PutFR["Bad user profile entry for BuildTRC.MaxInputDensity: %g is not a valid real number", IO.rope[tempRope]], TRUE]; MessageWindow.Blink[]; state.maxInputDens _ 1.3; CONTINUE; }]; state.maxOutputDens _ Convert.RealFromRope[ tempRope _ UserProfile.Token[ "BuildTRC.MaxOutputDensity", "1.3"] ! Convert.Error => { MessageWindow.Append[IO.PutFR["Bad user profile entry for BuildTRC.MaxOutputDensity: %g is not a valid real number", IO.rope[tempRope]], TRUE]; MessageWindow.Blink[]; state.maxOutputDens _ 1.3; CONTINUE; }]; state.gamma _ Convert.RealFromRope[ tempRope _ UserProfile.Token[ "BuildTRC.Gamma", "2.2"] ! Convert.Error => { MessageWindow.Append[IO.PutFR["Bad user profile entry for BuildTRC.Gamma: %g is not a valid real number", IO.rope[tempRope]], TRUE]; MessageWindow.Blink[]; state.gamma _ 2.2; CONTINUE; }]; }; GetDensityFromScaleViewer: PROC [ v: ViewerClasses.Viewer, mode: TRCViewer.FeedBackMode] RETURNS [d:REAL, err:BOOLEAN _ FALSE] ~ { r: REAL; [r, err] _ GetRealFromViewer[v]; IF err THEN RETURN; IF mode=density THEN { IF r<0 THEN { MessageWindow.Append["Scale value should be positive", TRUE]; MessageWindow.Blink[]; err _ TRUE; } ELSE { d _ r; }; } ELSE IF r<0 OR r>1 THEN { MessageWindow.Append["Scale value should be [0..1]", TRUE]; MessageWindow.Blink[]; err _ TRUE; } ELSE { d _ TRCViewer.RefToDens[r]; }; }; GetRealFromViewer: PROC [v: ViewerClasses.Viewer] RETURNS [r:REAL, err:BOOLEAN _ FALSE] ~ { rope: Rope.ROPE _ ViewerTools.GetContents[v]; in:IO.STREAM _ IO.RIS[rope]; r _ IO.GetReal[in ! IO.Error => { MessageWindow.Append["Invalid format in real number specification", TRUE]; MessageWindow.Blink[]; err _ TRUE; CONTINUE }; IO.EndOfStream => { MessageWindow.Append["Parameter absent", TRUE]; MessageWindow.Blink[]; err _ TRUE; CONTINUE }]; }; GetCardFromViewer: PROC [v: ViewerClasses.Viewer] RETURNS [r:NAT, err:BOOLEAN _ FALSE] ~ { rope: Rope.ROPE _ ViewerTools.GetContents[v]; in:IO.STREAM _ IO.RIS[rope]; r _ IO.GetCard[in ! IO.Error => { MessageWindow.Append["Invalid format in number specification", TRUE]; MessageWindow.Blink[]; err _ TRUE; CONTINUE }; IO.EndOfStream => { MessageWindow.Append["Parameter absent", TRUE]; MessageWindow.Blink[]; err _ TRUE; CONTINUE }]; }; ToggleHisto: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift: BOOL _ FALSE, control: BOOL _ FALSE] -- = { ENABLE UNWIND => NULL; state: State _ NARROW[clientData]; IF state.histo=NIL THEN { MessageWindow.Append["No histogram has been calculated yet", TRUE]; MessageWindow.Blink[]; Buttons.SetDisplayStyle[state.histSourceBut, $BlackOnWhite]; RETURN []; }; state.histoOn _ ~state.histoOn; Buttons.SetDisplayStyle[state.histSourceBut, $WhiteOnBlack]; IF state.histoOn THEN { Buttons.ReLabel[state.showHistBut, "On"]; TRCViewer.SetHistogram[state.trcViewer, state.histo]; } ELSE { Buttons.ReLabel[state.showHistBut, "Off"]; TRCViewer.SetHistogram[state.trcViewer, NIL]; }; }; ReadTRC: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift: BOOL _ FALSE, control: BOOL _ FALSE] -- = { ENABLE UNWIND => NULL; SetOutput: TRCViewer.EnumerateProc ~ { xIndex: NAT _ Real.RoundC[x]; IF ~trc[xIndex].pinned THEN trc[xIndex].out _ Real.RoundC[y]; }; state: State _ NARROW[clientData]; trc: Hist.TRCVec; bomb: BOOLEAN _ FALSE; pinned: ARRAY [0..255] OF BOOLEAN _ ALL[FALSE]; fileList: LIST OF Rope.ROPE; dotIndex: INTEGER; in:IO.STREAM; modeRope: Rope.ROPE; prev: NAT _ 0; fileName: Rope.ROPE _ ViewerTools.GetContents[state.trcFileTypeIn]; IF fileName=NIL OR Rope.Length[fileName]=0 THEN { MessageWindow.Append["Enter a TRC filename in TRC field please", TRUE]; MessageWindow.Blink[]; RETURN [] }; dotIndex _ Rope.Find[fileName, ".", 0, FALSE]; IF dotIndex<0 THEN fileList _ UserProfileOps.Expand["%g.%k|TRCExtensions|trc|", IO.rope[fileName]] ELSE fileList _ LIST[fileName]; IF ~SetWDir[state] THEN RETURN []; DO { success:BOOLEAN _ TRUE; IF fileList = NIL THEN { MessageWindow.Append["Couldn't find specified TRC input file", TRUE]; MessageWindow.Blink[]; RETURN []; }; in _ FS.StreamOpen[fileName: fileList.first ! FS.Error => { success _ FALSE; CONTINUE }]; IF success THEN EXIT; fileList _ fileList.rest }; ENDLOOP; <<-- read the file in>> trc _ NEW[Hist.TRCVecRec]; modeRope _ in.GetID[ ! IO.Error => { MessageWindow.Append["TRC format error - Couldn't find interpolation mode flag", TRUE]; MessageWindow.Blink[]; bomb _ TRUE; CONTINUE; } ]; IF bomb THEN RETURN []; SELECT TRUE FROM Rope.Equal[modeRope, LogFlag, FALSE] => { state.connectMode _ log; Buttons.SetDisplayStyle[state.linBut, $BlackOnWhite]; Buttons.SetDisplayStyle[state.logBut, $WhiteOnBlack]; }; Rope.Equal[modeRope, LinFlag, FALSE] => { state.connectMode _ linear; Buttons.SetDisplayStyle[state.linBut, $WhiteOnBlack]; Buttons.SetDisplayStyle[state.logBut, $BlackOnWhite]; }; ENDCASE => { MessageWindow.Append["TRC format error - Invalid interpolation mode flag", TRUE]; MessageWindow.Blink[]; RETURN []; }; FOR i:CARDINAL IN [0..255] DO c: CHAR; index:CARDINAL _ 0; prev _ index; index _ IO.GetCard[in ! IO.EndOfStream => { bomb _ TRUE; CONTINUE; }; IO.Error => { bomb _ TRUE; MessageWindow.Append[IO.PutFR["TRC format error following vertex %g", IO.card[prev]], TRUE]; MessageWindow.Blink[]; CONTINUE; }]; prev _ index; IF bomb THEN EXIT; trc[index].out _ IO.GetCard[in ! IO.EndOfStream => { bomb _ TRUE; MessageWindow.Append["TRC format error - Unexpected EOF", TRUE]; MessageWindow.Blink[]; CONTINUE; }; IO.Error => { bomb _ TRUE; MessageWindow.Append[IO.PutFR["TRC format error at vertex %g", IO.card[index]], TRUE]; MessageWindow.Blink[]; CONTINUE; }]; IF bomb THEN EXIT; trc[index].pinned _ TRUE; c _ in.GetChar[ ! IO.EndOfStream => {bomb _ TRUE; CONTINUE}]; IF bomb THEN EXIT; WHILE (c # IO.CR) DO SELECT c FROM '* => { pinned[index] _ TRUE; EXIT; }; IO.BS, IO.TAB, IO.LF, IO.FF, IO.NUL, IO.SP, IO.DEL, IO.ESC, IO.ControlX, IO.BEL, IO.ControlA => NULL; ENDCASE => { bomb _ TRUE; MessageWindow.Append[IO.PutFR["TRC format error following vertex %g '*' or CR expected", IO.card[prev]], TRUE]; MessageWindow.Blink[]; EXIT; }; c _ in.GetChar[ ! IO.EndOfStream => {bomb _ TRUE; CONTINUE}]; IF bomb THEN EXIT; ENDLOOP; IF bomb THEN EXIT; ENDLOOP; in.Close[]; TRCViewer.Set[state.trcViewer, trc, FALSE]; TRCViewer.Enumerate[state.trcViewer, SetOutput, 0, 255]; FOR i: NAT IN [0..255] DO trc[i].pinned _ pinned[i] ENDLOOP; <> TRCViewer.SetTitle[state.trcViewer, fileList.first]; }; SaveTRC: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift: BOOL _ FALSE, control: BOOL _ FALSE] -- = { ENABLE UNWIND => NULL; PrintOutput: TRCViewer.EnumerateProc ~ { xIndex: NAT _ Real.RoundC[x]; out.PutF["%g %g", IO.card[xIndex], IO.card[trc[xIndex].out]]; IF trc[xIndex].pinned THEN out.PutChar['*]; out.PutChar['\n]; }; state: State _ NARROW[clientData]; trc: Hist.TRCVec; bomb: BOOLEAN _ FALSE; fileList: LIST OF Rope.ROPE; dotIndex: INTEGER; out: IO.STREAM; fileName: Rope.ROPE _ ViewerTools.GetContents[state.trcFileTypeIn]; IF fileName=NIL OR Rope.Length[fileName]=0 THEN { MessageWindow.Append["Enter a TRC filename in TRC field please", TRUE]; MessageWindow.Blink[]; RETURN [] }; dotIndex _ Rope.Find[fileName, ".", 0, FALSE]; IF dotIndex<0 THEN fileList _ UserProfileOps.Expand["%g.%k|TRCExtensions|trc|", IO.rope[fileName]] ELSE fileList _ LIST[fileName]; IF ~SetWDir[state] THEN RETURN []; out _ FS.StreamOpen[fileName: fileList.first, accessOptions:create ! FS.Error => { bomb _ TRUE; CONTINUE }]; IF bomb THEN { MessageWindow.Append["Could not create specified TRC file", TRUE]; MessageWindow.Blink[]; RETURN [] }; out.PutF["-- %g \n", IO.rope[fileList.first]]; SELECT state.connectMode FROM log => out.PutF["Log\n"]; linear => out.PutF["Linear\n"]; ENDCASE => ERROR; trc _ TRCViewer.Get[state.trcViewer]; TRCViewer.Enumerate[state.trcViewer, PrintOutput, 0, 255]; out.Close[]; }; SetWDir: PROC [state: State] RETURNS [ok:BOOLEAN _ TRUE] ~ { dirName: Rope.ROPE _ ViewerTools.GetContents[state.wdTypeIn]; IF dirName=NIL OR Rope.Length[dirName]=0 THEN { dirName _ FS.GetDefaultWDir[]; MessageWindow.Append[IO.PutFR["Assuming working directory %g", IO.rope[dirName]], TRUE]; MessageWindow.Blink[]; RETURN [] }; FS.SetDefaultWDir[dirName ! FS.Error => { MessageWindow.Append[IO.PutFR["Funny working directory name: %g", IO.rope[dirName]], TRUE]; MessageWindow.Blink[]; ok _ FALSE; CONTINUE; }]; }; CalcHisto: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift: BOOL _ FALSE, control: BOOL _ FALSE] -- = { ENABLE UNWIND => NULL; GetHist: PROC [fileList:LIST OF Rope.ROPE] RETURNS [histo:Hist.Histogram _ NIL] ~ { oldList: LIST OF Rope.ROPE _ fileList; DO { success:BOOLEAN _ TRUE; IF fileList = NIL THEN { MessageWindow.Append["Couldn't find possible input files ", TRUE]; WHILE oldList#NIL DO MessageWindow.Append[Rope.Cat[" ", oldList.first], FALSE]; oldList _ oldList.rest; ENDLOOP; MessageWindow.Blink[]; histo _ NIL; state.histoOn _ FALSE; RETURN []; }; MessageWindow.Append[Rope.Cat["Looking for: ", fileList.first], TRUE]; histo _ Hist.Calc[fileList.first, min, max ! FS.Error => { success _ FALSE; CONTINUE }]; IF success THEN EXIT; fileList _ fileList.rest }; ENDLOOP; }; state: State _ NARROW[clientData]; fileList, redList, grnList, bluList: LIST OF Rope.ROPE _ NIL; dotIndex: INTEGER; min, max:NAT; err:BOOLEAN _ FALSE; fileName: Rope.ROPE _ ViewerTools.GetContents[state.histSourceTypeIn]; IF fileName=NIL OR Rope.Length[fileName]=0 THEN { MessageWindow.Append["Enter an AIS filename in Hist field please", TRUE]; MessageWindow.Blink[]; RETURN [] }; dotIndex _ Rope.Find[fileName, ".", 0, FALSE]; IF dotIndex<0 THEN { redList _ UserProfileOps.Expand["%g%k|AISseparationKeys.red|-red|.%k|AISExtensions|AIS|", IO.rope[fileName]]; grnList _ UserProfileOps.Expand["%g%k|AISseparationKeys.green|-grn|.%k|AISExtensions|AIS|", IO.rope[fileName]]; bluList _ UserProfileOps.Expand["%g%k|AISseparationKeys.blue|-blu|.%k|AISExtensions|AIS|", IO.rope[fileName]]; } ELSE fileList _ LIST[fileName]; IF ~SetWDir[state] THEN RETURN []; [min, err] _ GetCardFromViewer[state.blackTypeIn]; IF err OR min NOT IN [0..255] THEN { MessageWindow.Append["Invalid value for histogram black value [0..255]", TRUE]; MessageWindow.Blink[]; RETURN [] }; [max, err] _ GetCardFromViewer[state.whiteTypeIn]; IF err OR max NOT IN [0..255] THEN { MessageWindow.Append["Invalid value for histogram white value [0..255]", TRUE]; MessageWindow.Blink[]; RETURN [] }; state.histoOn _ TRUE; IF fileList=NIL THEN { rHist, gHist, bHist: Hist.Histogram; rHist _ GetHist[redList]; IF state.histoOn THEN { gHist _ GetHist[grnList]; IF state.histoOn THEN { bHist _ GetHist[bluList]; IF state.histoOn THEN { FOR i: NAT IN [0..Hist.MaxPixel) DO rHist[i] _ (rHist[i] + gHist[i] + bHist[i])/3; ENDLOOP; state.histo _ rHist; } } } } ELSE { state.histo _ GetHist[fileList]; }; IF state.histoOn THEN { Buttons.SetDisplayStyle[state.histSourceBut, $WhiteOnBlack]; Buttons.ReLabel[state.showHistBut, "On"]; TRCViewer.SetHistogram[state.trcViewer, state.histo]; } ELSE { Buttons.SetDisplayStyle[state.histSourceBut, $BlackOnWhite]; Buttons.ReLabel[state.showHistBut, "Off"]; TRCViewer.SetHistogram[state.trcViewer, NIL]; }; }; Equalise: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift: BOOL _ FALSE, control: BOOL _ FALSE] -- = { ENABLE UNWIND => NULL; state: State _ NARROW[clientData]; trc: Hist.TRCVec; IF state.histo=NIL THEN { MessageWindow.Append["No histogram has been calculated yet", TRUE]; MessageWindow.Blink[]; RETURN [] }; trc _ Hist.Equalize[state.histo]; trc[0].pinned _ trc[255].pinned _ TRUE; TRCViewer.Set[state.trcViewer, trc]; }; SelGamma: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift: BOOL _ FALSE, control: BOOL _ FALSE] -- = { ENABLE UNWIND => NULL; state: State _ NARROW[clientData]; ViewerTools.SetSelection[NARROW[clientData, State].gammaTypeIn]; UpdateImagerColorMap[state]; }; SelBlack: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift: BOOL _ FALSE, control: BOOL _ FALSE] -- = { ENABLE UNWIND => NULL; state: State _ NARROW[clientData]; ViewerTools.SetSelection[NARROW[clientData, State].blackTypeIn]; }; SelWhite: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift: BOOL _ FALSE, control: BOOL _ FALSE] -- = { ENABLE UNWIND => NULL; state: State _ NARROW[clientData]; ViewerTools.SetSelection[NARROW[clientData, State].whiteTypeIn]; }; Shift: ENTRY Buttons.ButtonProc = { ENABLE UNWIND => NULL; state: State _ NARROW[clientData]; newVertices: Hist.TRCVec _ NEW[Hist.TRCVecRec]; oldVertices: Hist.TRCVec _ TRCViewer.Get[state.trcViewer]; delta: NAT _ 1; dir: INT _ 1; IF shift THEN delta _ delta * 16; IF control THEN delta _ delta * 4; IF mouseButton=blue THEN dir _ -1; FOR i: NAT IN [0..Hist.MaxPixel] DO p:INT _ i+(delta*dir); SELECT TRUE FROM p<0 => { newVertices[i].out _ oldVertices[0].out}; p>255 => { newVertices[i].out _ oldVertices[255].out}; ENDCASE => newVertices[i] _ oldVertices[p]; ENDLOOP; IF state.addVertexOnShiftOrRotate THEN newVertices[0].pinned _ newVertices[255].pinned _ TRUE; TRCViewer.Set[state.trcViewer, newVertices]; }; Rotate: ENTRY Buttons.ButtonProc = { ENABLE UNWIND => NULL; state: State _ NARROW[clientData]; newVertices: Hist.TRCVec _ NEW[Hist.TRCVecRec]; oldVertices: Hist.TRCVec _ TRCViewer.Get[state.trcViewer]; delta: NAT _ 1; dir: INT _ 1; IF shift THEN delta _ delta * 16; IF control THEN delta _ delta * 4; IF mouseButton=blue THEN dir _ -1; FOR i: NAT IN [0..Hist.MaxPixel] DO p:INT _ i+(delta*dir); newVertices[i] _ oldVertices[(256+p) MOD 256]; ENDLOOP; IF state.addVertexOnShiftOrRotate THEN newVertices[0].pinned _ newVertices[255].pinned _ TRUE; TRCViewer.Set[state.trcViewer, newVertices]; }; SelectWD: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift: BOOL _ FALSE, control: BOOL _ FALSE] -- = { ENABLE UNWIND => NULL; ViewerTools.SetSelection[NARROW[clientData, State].wdTypeIn]; }; SelectTRC: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift: BOOL _ FALSE, control: BOOL _ FALSE] -- = { ENABLE UNWIND => NULL; ViewerTools.SetSelection[NARROW[clientData, State].trcFileTypeIn]; }; SelectHist: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift: BOOL _ FALSE, control: BOOL _ FALSE] -- = { ENABLE UNWIND => NULL; ViewerTools.SetSelection[NARROW[clientData, State].histSourceTypeIn]; }; SelectInScale: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift: BOOL _ FALSE, control: BOOL _ FALSE] -- = { ENABLE UNWIND => NULL; state: State _ NARROW[clientData]; d: REAL; err: BOOLEAN; [d, err] _ GetDensityFromScaleViewer[state.inputScaleTypeIn, state.inputMode]; IF ~err THEN { state.maxInputDens _ d; TRCViewer.SetMaxDensityIn[state.trcViewer, d]; }; IF mouseButton=red OR mouseButton=blue THEN { SELECT state.inputMode FROM density => { state.inputMode _ reflectance; Buttons.ReLabel[state.setInputModeBut, "MinRIn"]; ViewerTools.SetContents[state.inputScaleTypeIn, IO.PutFR["%g", IO.real[TRCViewer.DensToRef[state.maxInputDens]]]]; }; ENDCASE => { state.inputMode _ density; Buttons.ReLabel[state.setInputModeBut, "MaxDIn"]; ViewerTools.SetContents[state.inputScaleTypeIn, IO.PutFR["%g", IO.real[state.maxInputDens]]]; }; TRCViewer.SetFeedBackModes[state.trcViewer, state.inputMode, state.outputMode]; }; ViewerTools.SetSelection[state.inputScaleTypeIn]; }; SelectOutScale: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift: BOOL _ FALSE, control: BOOL _ FALSE] -- = { ENABLE UNWIND => NULL; state: State _ NARROW[clientData]; d: REAL; err: BOOLEAN; [d, err] _ GetDensityFromScaleViewer[state.outputScaleTypeIn, state.outputMode]; IF ~err THEN { state.maxOutputDens _ d; TRCViewer.SetMaxDensityOut[state.trcViewer, d]; }; IF mouseButton=red OR mouseButton=blue THEN { SELECT state.outputMode FROM density => { state.outputMode _ reflectance; Buttons.ReLabel[state.setOutputModeBut, "MinROut"]; ViewerTools.SetContents[state.outputScaleTypeIn, IO.PutFR["%g", IO.real[TRCViewer.DensToRef[state.maxOutputDens]]]]; }; ENDCASE => { state.outputMode _ density; Buttons.ReLabel[state.setOutputModeBut, "MaxDOut"]; ViewerTools.SetContents[state.outputScaleTypeIn, IO.PutFR["%g", IO.real[state.maxOutputDens]]]; }; TRCViewer.SetFeedBackModes[state.trcViewer, state.inputMode, state.outputMode]; }; ViewerTools.SetSelection[state.outputScaleTypeIn]; TRCViewer.SetConnectMode[state.trcViewer, state.connectMode]; -- just a refresh really }; SetLinearMode: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift: BOOL _ FALSE, control: BOOL _ FALSE] -- = { ENABLE UNWIND => NULL; state: State _ NARROW[clientData]; state.connectMode _ linear; Buttons.SetDisplayStyle[state.linBut, $WhiteOnBlack]; Buttons.SetDisplayStyle[state.logBut, $BlackOnWhite]; TRCViewer.SetConnectMode[state.trcViewer, state.connectMode]; }; SetLogMode: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift: BOOL _ FALSE, control: BOOL _ FALSE] -- = { ENABLE UNWIND => NULL; state: State _ NARROW[clientData]; state.connectMode _ log; Buttons.SetDisplayStyle[state.linBut, $BlackOnWhite]; Buttons.SetDisplayStyle[state.logBut, $WhiteOnBlack]; TRCViewer.SetConnectMode[state.trcViewer, state.connectMode]; }; InitTRC: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift: BOOL _ FALSE, control: BOOL _ FALSE] -- = { ENABLE UNWIND => NULL; SetOutput: TRCViewer.EnumerateProc ~ { trc[Real.RoundC[x]].out _ Real.RoundC[y]; }; state: State _ NARROW[clientData]; trc: Hist.TRCVec _ NEW[Hist.TRCVecRec]; trc[0].pinned _ trc[255].pinned _ TRUE; trc[0].out _ 0; trc[255].out _ 255; TRCViewer.Set[state.trcViewer, trc, FALSE]; TRCViewer.Enumerate[state.trcViewer, SetOutput, 0, 255]; TRCViewer.SetConnectMode[state.trcViewer, state.connectMode]; -- just a refresh really }; Negate: ENTRY Buttons.ButtonProc -- [parent: REF ANY, clientData: REF ANY _ NIL, mouseButton: Menus.MouseButton _ red, shift: BOOL _ FALSE, control: BOOL _ FALSE] -- = { ENABLE UNWIND => NULL; state: State _ NARROW[clientData]; trc: Hist.TRCVec _ TRCViewer.Get[state.trcViewer]; IF mouseButton=red THEN { FOR i: NAT IN [0..Hist.MaxPixel] DO trc[i].out _ 255 - trc[i].out; ENDLOOP; TRCViewer.Set[state.trcViewer, trc]; } ELSE { old: Hist.TRCVec _ NEW[Hist.TRCVecRec _ trc^]; FOR i: NAT IN [0..Hist.MaxPixel] DO trc[i].pinned _ FALSE; ENDLOOP; FOR i: NAT IN [0..Hist.MaxPixel] DO IF old[i].pinned THEN { trc[old[i].out].out _ i; trc[old[i].out].pinned _ TRUE; }; ENDLOOP; TRCViewer.Set[state.trcViewer, trc]; TRCViewer.SetConnectMode[state.trcViewer, state.connectMode]; }; }; Register: PROC ~ { Commander.Register[key:"BuildTRC", proc:StartNewInstance]; }; Register[]; END.