-- BuildTRCImpl.mesa
-- Mik Lamming - December 11, 1984 1:22:03 pm PST
Last edited by: Mik Lamming - January 29, 1986 4:20:52 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: ATOMNIL;
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: BOOLEANFALSE,
addVertexOnShiftOrRotate: BOOLEANFALSE,
histo: Hist.Histogram ← NIL,
simRed, simGrn, simBlu, simSat, simHue, simVal, simLight: BOOLEANTRUE,
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] -- = {
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𡤋pp24;
displayKind ← ImagerOps.KindOf[ViewerPrivate.CreateContext[color]];
}
ELSE
IF Terminal.GetColorMode[vt].bitsPerPixelChannelA=8 THEN {
displayKind ← ImagerOps.KindOf[ViewerPrivate.CreateContext[color]];
displayState𡤋pp8;
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.ROPENIL] 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.STREAMIO.RIS[cmd.commandLine];
empty:BOOLEANFALSE;
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:BOOLEANFALSE] ~ {
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:BOOLEANFALSE] ~ {
rope: Rope.ROPE ← ViewerTools.GetContents[v];
in:IO.STREAMIO.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:BOOLEANFALSE] ~ {
rope: Rope.ROPE ← ViewerTools.GetContents[v];
in:IO.STREAMIO.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] -- = {
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] -- = {
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: BOOLEANFALSE;
pinned: ARRAY [0..255] OF BOOLEANALL[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 []
};
dotIndexRope.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:BOOLEANTRUE;
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;
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.SetConnectMode[state.trcViewer, state.connectMode]; -- just a refresh really
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] -- = {
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: BOOLEANFALSE;
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 []
};
dotIndexRope.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:BOOLEANTRUE] ~ {
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] -- = {
GetHist: PROC [fileList:LIST OF Rope.ROPE] RETURNS [histo:Hist.Histogram ← NIL] ~ {
oldList: LIST OF Rope.ROPE ← fileList;
DO {
success:BOOLEANTRUE;
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.ROPENIL;
dotIndex: INTEGER;
min, max:NAT;
err:BOOLEANFALSE;
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 []
};
dotIndexRope.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] -- = {
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] -- = {
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] -- = {
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] -- = {
state: State ← NARROW[clientData];
ViewerTools.SetSelection[NARROW[clientData, State].whiteTypeIn];
};
Shift: ENTRY Buttons.ButtonProc = {
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 = {
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] -- = {
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] -- = {
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] -- = {
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] -- = {
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] -- = {
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] -- = {
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] -- = {
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] -- = {
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] -- = {
state: State ← NARROW[clientData];
trc: Hist.TRCVec ← TRCViewer.Get[state.trcViewer];
FOR i: NAT IN [0..Hist.MaxPixel] DO
trc[i].out ← 255 - trc[i].out;
ENDLOOP;
TRCViewer.Set[state.trcViewer, trc];
};
Register: PROC ~ {
Commander.Register[key:"BuildTRC", proc:StartNewInstance];
};
Register[];
END.