DIRECTORY
AIS,
Ascii,
Commander USING [CommandProc, Register],
CommandTool USING [FileWithSearchRules],
FS USING [StreamOpen],
IO,
Process USING [CheckForAbort, GetPriority, Priority, priorityBackground, SetPriority],
Real USING [RoundI],
Rope USING [Equal, Concat, ROPE];
~
BEGIN
OPEN Ascii;
ROPE: TYPE ~ Rope.ROPE;
STREAM: TYPE ~ IO.STREAM;
FilterSpec: TYPE ~ REF FilterSpecRep;
FilterSpecRep:
TYPE ~
RECORD [
x, y: CARDINAL,
seq: SEQUENCE cnt: CARDINAL OF ZEROREAL
];
ZEROREAL: TYPE ~ REAL← 0.0;
ApplyFilterSpec:
PROC [inFile, outFile:
ROPE, filter: FilterSpec] =
BEGIN
inF: AIS.FRef = AIS.OpenFile[inFile];
inR: AIS.Raster = AIS.ReadRaster[inF];
outR: AIS.Raster = NEW [AIS.RasterPart ← inR^];
outF: AIS.FRef = AIS.CreateFile[outFile, outR];
inW: AIS.WRef = AIS.OpenWindow[inF];
outW: AIS.WRef;
firstScan, lastScan, firstPixel, lastPixel: CARDINAL;
[firstScan, lastScan, firstPixel, lastPixel] ← AIS.GetWindowParams[inW];
outW ← AIS.OpenWindow[outF, firstScan, lastScan, firstPixel, lastPixel];
AIS.WriteComment[outF, AIS.ReadComment[inF]];
FOR line:
CARDINAL
IN [firstScan .. lastScan]
DO
FOR pixel:
CARDINAL
IN [firstPixel .. lastPixel]
DO
ENABLE UNWIND => {AIS.CloseWindow[inW]; AIS.CloseWindow[outW]; AIS.CloseFile[inF]; AIS.CloseFile[outF]};
np: CARDINAL;
x: INT = filter.x/2;
y: INT = filter.y/2;
sum: REAL ← 0.0;
FOR i:
INT
IN [-y .. y]
DO
IF i+line NOT IN [firstScan .. lastScan] THEN LOOP;
FOR j:
INT
IN [-x .. x]
DO
fi: CARDINAL ← (i+y)*filter.x + (j+x);
IF j+pixel NOT IN [firstPixel .. lastPixel] THEN LOOP;
sum← sum + AIS.ReadSample[inW, i+line, j+pixel] * filter.seq[fi];
Process.CheckForAbort[];
ENDLOOP;
ENDLOOP;
np← MIN[MAX[Real.RoundI[sum], 0], 255];
AIS.WriteSample[outW, np, line, pixel];
ENDLOOP;
ENDLOOP;
AIS.CloseWindow[inW];
AIS.CloseWindow[outW];
AIS.CloseFile[inF];
AIS.CloseFile[outF];
END;
ParseFilterSpec:
PROC [filterName:
ROPE, fileName:
ROPE]
RETURNS [filter: FilterSpec] =
BEGIN
name: ROPE = Rope.Concat[filterName, ":"];
s: STREAM = FS.StreamOpen[fileName];
token: ROPE; x, y: CARDINAL;
BEGIN
ENABLE
UNWIND =>
IF s #
NIL
THEN
IO.Close[s];
DO
IF IO.EndOf[s] THEN EXIT;
token← IO.GetTokenRope[s, Break ! IO.EndOfStream => EXIT].token;
IF NOT Rope.Equal[token, name, FALSE] THEN LOOP;
x← IO.GetCard[s ! IO.EndOfStream => ERROR];
token← IO.GetTokenRope[s, Break ! IO.EndOfStream => ERROR].token;
IF NOT Rope.Equal[token, "by", FALSE] THEN ERROR;
y← IO.GetCard[s ! IO.EndOfStream => ERROR];
IF y MOD 2 # 1 THEN ERROR;
IF x MOD 2 # 1 THEN ERROR;
filter← NEW [FilterSpecRep[x*y]];
filter.x← x; filter.y← y;
FOR i:
CARDINAL
IN [0 .. y)
DO
FOR j:
CARDINAL
IN [0 .. x)
DO
filter.seq[i*x+j] ← IO.GetReal[s ! IO.EndOfStream => ERROR];
ENDLOOP;
ENDLOOP;
ENDLOOP;
END; -- of enable
IO.Close[s];
END;
Break:
IO.BreakProc =
{
RETURN [
SELECT char
FROM
CR, SP, TAB, ',, '{, '} => sepr,
ENDCASE => other]};
GetToken:
PROC [stream:
IO.
STREAM]
RETURNS [rope:
ROPE ←
NIL] = {
Break:
PROC [char:
CHAR]
RETURNS [
IO.CharClass] ~ {
IF char = '← OR char = '; THEN RETURN [break];
IF char = ' OR char = ' OR char = ', OR char = '\n THEN RETURN [sepr];
RETURN [other];
};
rope ← stream.GetTokenRope[Break ! IO.EndOfStream => CONTINUE].token;
};
ConvolutionFilterCommand: Commander.CommandProc ~ {
stream: IO.STREAM ← IO.RIS[cmd.commandLine];
outputName: ROPE ← GetToken[stream];
gets: ROPE ← GetToken[stream];
inputName: ROPE ← GetToken[stream];
oldPriority: Process.Priority ← Process.GetPriority[];
filter: ROPE ← GetToken[stream];
filterSpec: FilterSpec;
IF
NOT gets.Equal["←"]
THEN {
cmd.out.PutRope["Specify output ← input <filterspec>, please.\n"];
RETURN;
};
filterSpec ← ParseFilterSpec[filter, CommandTool.FileWithSearchRules["Filter", "txt", cmd]];
Process.SetPriority[Process.priorityBackground];
ApplyFilterSpec[inputName, outputName, filterSpec ! UNWIND => Process.SetPriority[oldPriority]];
Process.SetPriority[oldPriority];
cmd.out.PutRope["Done.\n"];
};
Commander.Register["ConvolutionFilter", ConvolutionFilterCommand, "Apply convolution filter to (output ← input filter"];