FattenPixelsImpl.mesa
Copyright (C) 1984, Xerox Corporation. All rights reserved.
Michael Plass, October 17, 1985 2:26:52 pm PDT
DIRECTORY
ImagerPixelMap, ImagerPixelSeq, FattenPixels, Process
;
FattenPixelsImpl: CEDAR MONITOR
IMPORTS ImagerPixelMap, ImagerPixelSeq, Process
EXPORTS FattenPixels
~ BEGIN
PixelMap: TYPE ~ ImagerPixelMap.PixelMap;
DeviceRectangle: TYPE ~ ImagerPixelMap.DeviceRectangle;
PixelSeq: TYPE ~ ImagerPixelSeq.PixelSeq;
scratchPM: REF ImagerPixelMap.PixelMapRep ← NIL;
killerProcessActive: BOOLEANFALSE;
scratchCondition: CONDITION;
killerDelay: Process.Milliseconds ← 30000;
GetScratch: ENTRY PROC RETURNS [scratch: REF ImagerPixelMap.PixelMapRep] ~ {
scratch ← scratchPM;
scratchPM ← NIL;
};
ReleaseScratch: ENTRY PROC [scratch: REF ImagerPixelMap.PixelMapRep] ~ {
scratchPM ← scratch;
IF NOT killerProcessActive THEN {
TRUSTED{Process.Detach[FORK Killer]};
killerProcessActive ← TRUE;
};
};
Killer: ENTRY PROC ~ {
TRUSTED{Process.InitializeCondition[@scratchCondition, Process.MsecToTicks[killerDelay]]};
WAIT scratchCondition;
UNTIL scratchPM # NIL DO WAIT scratchCondition ENDLOOP;
scratchPM ← NIL;
killerProcessActive ← FALSE;
};
FattenSquare: PUBLIC PROC [bitmap: PixelMap, brushSize: NAT] ~ {
start: INTEGER ← 0;
end: INTEGER ← 1;
targetStart: INTEGER ← -(brushSize/2);
targetEnd: INTEGER ← targetStart+brushSize;
WHILE start > targetStart DO
maxdelta: NAT ← end-start;
newStart: INTEGERMAX[start-maxdelta, targetStart];
bitmap.Transfer[bitmap.ShiftMap[start-newStart, 0], [or, null]];
start ← newStart;
ENDLOOP;
WHILE end < targetEnd DO
maxdelta: NAT ← end-start;
newEnd: INTEGERMIN[end+maxdelta, targetEnd];
bitmap.Transfer[bitmap.ShiftMap[end-newEnd, 0], [or, null]];
end ← newEnd;
ENDLOOP;
start ← 0; end ← 1;
WHILE start > targetStart DO
maxdelta: NAT ← end-start;
newStart: INTEGERMAX[start-maxdelta, targetStart];
bitmap.Transfer[bitmap.ShiftMap[0, start-newStart], [or, null]];
start ← newStart;
ENDLOOP;
WHILE end < targetEnd DO
maxdelta: NAT ← end-start;
newEnd: INTEGERMIN[end+maxdelta, targetEnd];
bitmap.Transfer[bitmap.ShiftMap[0, end-newEnd], [or, null]];
end ← newEnd;
ENDLOOP;
};
FattenDiamond: PUBLIC PROC [bitmap: PixelMap, brushSize: NAT] ~ {
alternate: PixelMap ← GetScratch[].Reshape[0, bitmap.Window];
WHILE brushSize > 2 DO
alternate.Clear;
alternate.Transfer[bitmap.ShiftMap[-1, 0], [or, null]];
alternate.Transfer[bitmap.ShiftMap[1, 0], [or, null]];
alternate.Transfer[bitmap.ShiftMap[0, 1], [or, null]];
alternate.Transfer[bitmap.ShiftMap[0, -1], [or, null]];
bitmap.Transfer[alternate, [or, null]];
brushSize ← brushSize - 2;
ENDLOOP;
ReleaseScratch[alternate.refRep];
IF brushSize = 2 THEN FattenSquare[bitmap, 2];
};
FattenRound: PUBLIC PROC [bitmap: PixelMap, brushSize: NAT] ~ {
square: NAT ← brushSize/2;
diamond: NAT ← brushSize-square;
FattenDiamond[bitmap, diamond];
FattenSquare[bitmap, square];
};
ImposeMinimum: PUBLIC PROC [bitmap: PixelMap, brushSize: NAT] ~ {
alternate: PixelMap ← bitmap.Copy[scratch: GetScratch[]];
ImposeMinimumS[alternate, brushSize];
ImposeMinimumF[bitmap, brushSize];
bitmap.Transfer[alternate, [or, null]];
ReleaseScratch[alternate.refRep];
};
ImposeMinimumS: PUBLIC PROC [bitmap: PixelMap, brushSize: NAT] ~ {
bb: DeviceRectangle ~ bitmap.Window;
pixelSeq: PixelSeq ← ImagerPixelSeq.ObtainScratch[bb.sSize+4];
FOR f: INTEGER IN [bb.fMin..bb.fMin+bb.fSize) DO
pixelSeq.LoadS[s: bb.sMin-2, f: f, size: bb.sSize+4, source: bitmap];
ImposeMinimumSeq[pixelSeq, bb.sSize+4, brushSize];
pixelSeq.StoreS[s: bb.sMin-2, f: f, size: bb.sSize+4, dest: bitmap];
ENDLOOP;
ImagerPixelSeq.ReleaseScratch[pixelSeq];
};
ImposeMinimumF: PUBLIC PROC [bitmap: PixelMap, brushSize: NAT] ~ {
bb: DeviceRectangle ~ bitmap.Window;
pixelSeq: PixelSeq ← ImagerPixelSeq.ObtainScratch[bb.fSize+4];
FOR s: INTEGER IN [bb.sMin..bb.sMin+bb.sSize) DO
pixelSeq.LoadF[s: s, f: bb.fMin-2, size: bb.fSize+4, source: bitmap];
ImposeMinimumSeq[pixelSeq, bb.fSize+4, brushSize];
pixelSeq.StoreF[s: s, f: bb.fMin-2, size: bb.fSize+4, dest: bitmap];
ENDLOOP;
ImagerPixelSeq.ReleaseScratch[pixelSeq];
};
ImposeMinimumSeq: PROC [pixelSeq: PixelSeq, pixelSeqSize: NAT, brushSize: NAT] ~ {
runMin, runMax: CARDINAL ← 0;
i: NAT ← 2;
Put a border around the edges to keep the loops simpler.
pixelSeq[0] ← pixelSeq[pixelSeqSize-1] ← 1;
pixelSeq[1] ← pixelSeq[pixelSeqSize-2] ← 0;
WHILE i < pixelSeqSize-2 DO
WHILE pixelSeq[i] = 0 DO i ← i + 1 ENDLOOP;
runMin ← i;
IF i >= pixelSeqSize-2 THEN EXIT;
WHILE pixelSeq[i] # 0 DO i ← i + 1 ENDLOOP;
runMax ← i;
WHILE runMax-runMin < brushSize DO
IF pixelSeq[runMax] = 0 AND pixelSeq[runMax+1] = 0 THEN {
pixelSeq[runMax] ← 1;
runMax ← runMax + 1;
}
ELSE EXIT;
IF runMax-runMin = brushSize THEN EXIT;
IF pixelSeq[runMin-1] = 0 AND pixelSeq[runMin-2] = 0 THEN {
pixelSeq[runMin-1] ← 1;
runMin ← runMin - 1;
}
ELSE EXIT;
ENDLOOP;
i ← runMax;
ENDLOOP;
};
AddBorder: PUBLIC PROC [pixelMap: PixelMap, borderSize: NAT, borderValue: CARDINAL] RETURNS [bordered: PixelMap] ~ {
w: DeviceRectangle ← pixelMap.Window;
w.sMin ← w.sMin - borderSize;
w.fMin ← w.fMin - borderSize;
w.sSize ← w.sSize + 2*borderSize;
w.fSize ← w.fSize + 2*borderSize;
bordered ← ImagerPixelMap.Create[pixelMap.refRep.lgBitsPerPixel, w];
bordered.Fill[w, borderValue];
bordered.Transfer[pixelMap];
};
END.