ImagerMasksImpl.mesa
Michael Plass, January 16, 1984 2:14 pm
DIRECTORY
Basics,
ImagerBasic,
ImagerManhattan,
ImagerPixelMaps,
ImagerScanConverter,
ImagerTransform,
Scaled,
ImagerMasks
;
ImagerMasksImpl: CEDAR PROGRAM
IMPORTS Basics, ImagerManhattan, ImagerPixelMaps, ImagerTransform, ImagerScanConverter, Scaled
EXPORTS ImagerMasks ~ BEGIN OPEN ImagerMasks;
bitsPerWord: NAT ~ Basics.bitsPerWord;
FromRectangle: PUBLIC PROC [box: DeviceRectangle] RETURNS [Mask] ~ {
IF box.sSize = 0 OR box.fSize = 0 THEN RETURN [NIL]
ELSE RETURN [ImagerManhattan.CreateFromBox[box]]
};
FromManhattanPolygon: PUBLIC PROC [polygon: ImagerManhattan.Polygon] RETURNS [Mask] ~ {
RETURN [polygon]
};
FromBitmap: PUBLIC PROC [pixelMap: PixelMap] RETURNS [Mask] ~ {
IF pixelMap.refRep.lgBitsPerPixel # 0 THEN ERROR;
IF pixelMap.sSize = 0 OR pixelMap.fSize = 0 THEN RETURN [NIL]
ELSE RETURN [NEW[PixelMap ← ImagerPixelMaps.Trim[pixelMap]]];
};
FromDevicePath: PUBLIC PROC [devicePath: DevicePath] RETURNS [Mask] ~ {
RETURN [devicePath];
};
FromPixelArray: PUBLIC PROC [pixelArray: PixelArray, compositeTransformation: Transformation] RETURNS [Mask] ~ {
IF compositeTransformation = pixelArray.m THEN RETURN [pixelArray]
ELSE {
copy: PixelArray ← NEW[ImagerBasic.PixelArrayRep ← pixelArray^];
copy.m ← compositeTransformation;
RETURN [copy]
};
};
BBList: PUBLIC PROC [mask: Mask] RETURNS [LIST OF DeviceRectangle] ~ {
RETURN [LIST[BoundingBox[mask]]]
};
BoundingBox: PUBLIC PROC [mask: Mask] RETURNS [DeviceRectangle] ~ {
WITH mask SELECT FROM
polygon: ManhattanPolygon => RETURN [ImagerManhattan.BoundingBox[polygon]];
bitmap: REF PixelMap => RETURN [[bitmap.sOrigin+bitmap.sMin, bitmap.fOrigin+bitmap.fMin, bitmap.sSize, bitmap.fSize]];
devicePath: DevicePath => RETURN [ImagerScanConverter.BoundingBox[devicePath]];
pixelArray: PixelArray => {
bb: ImagerBasic.IntRectangle ← ImagerTransform.TransformIntRectangle[
[0, 0, pixelArray.xPixels, pixelArray.yPixels],
pixelArray.m
];
RETURN [[bb.x, bb.y, bb.w, bb.h]];
};
ENDCASE => RETURN [[0, 0, 0, 0]];
};
CountRuns: PUBLIC PROC [mask: Mask] RETURNS [numberOfRuns: INT] ~ {
WITH mask SELECT FROM
polygon: ManhattanPolygon => RETURN [ImagerManhattan.CountRuns[polygon]];
devicePath: DevicePath => RETURN [ImagerScanConverter.NumberOfRuns[devicePath]];
ENDCASE => {
RunProc: PROC [sMin, fMin: INTEGER, fSize: NAT] ~
{numberOfRuns ← numberOfRuns+1};
t1: ManhattanPolygon ← ImagerManhattan.CreateFromBox[BoundingBox[mask]];
numberOfRuns ← 0;
GenerateRuns[mask, t1, RunProc, 0, 0];
ImagerManhattan.Destroy[t1];
};
};
GenerateRuns: PUBLIC PROC [mask, clipper: Mask, runProc: PROC [sMin, fMin: INTEGER, fSize: NAT], sTranslate, fTranslate: INTEGER] ~ {
clipPoly: ManhattanPolygon ← WITH clipper SELECT FROM
polygon: ManhattanPolygon => polygon,
ENDCASE => ToManhattanPolygon[clipper, BBList[clipper], 0, 0];
remainder: ManhattanPolygon ← clipPoly;
TranslateAndClipRunProc: PROC [sMin, fMin: INTEGER, fSize: NAT] ~ {
sMin ← sMin + sTranslate;
fMin ← fMin + fTranslate;
WHILE remainder # NIL AND remainder.first.sMin + remainder.first.sSize <= sMin DO
remainder ← remainder.rest;
ENDLOOP;
FOR l: LIST OF DeviceRectangle ← remainder, l.rest UNTIL l = NIL OR l.first.sMin > sMin DO
fMinRun: INTEGER ~ MAX[l.first.fMin, fMin];
fMaxRun: INTEGER ~ MIN[l.first.fMin+l.first.fSize, fMin+fSize];
IF fMaxRun > fMinRun THEN runProc [sMin, fMinRun, fMaxRun-fMinRun];
ENDLOOP;
};
WITH mask SELECT FROM
polygon: ManhattanPolygon => ImagerManhattan.MapRuns[polygon, TranslateAndClipRunProc];
bitmap: REF PixelMap => {
IF clipPoly # NIL AND clipPoly.rest = NIL THEN {
BitmapGenerateRuns[bitmap^.ShiftMap[sTranslate, fTranslate].Clip[clipPoly.first], runProc];
}
ELSE BitmapGenerateRuns[bitmap^, TranslateAndClipRunProc];
};
devicePath: DevicePath => {
IF clipPoly # NIL AND clipPoly.rest = NIL AND sTranslate = 0 AND fTranslate = 0 THEN {
devicePath.ConvertToRuns[runProc, clipPoly.first];
}
ELSE {
devicePath.ConvertToRuns[TranslateAndClipRunProc, ImagerManhattan.BoundingBox[clipPoly]];
};
};
pixelArray: PixelArray => {
m: ImagerTransform.TransformationRec ← ImagerTransform.Contents[pixelArray.m];
X: PROC [x, y: REAL] RETURNS [REAL] ~ {
RETURN [m.a * x + m.b * y + m.c + sTranslate]
};
Y: PROC [x, y: REAL] RETURNS [REAL] ~ {
RETURN [m.d * x + m.e * y + m.f + fTranslate]
};
PathMap: ImagerScanConverter.PathProc ~ {
move[X[0, 0], Y[0, 0]];
line[X[0, pixelArray.yPixels], Y[0, pixelArray.yPixels]];
line[X[pixelArray.xPixels, pixelArray.yPixels], Y[pixelArray.xPixels, pixelArray.yPixels]];
line[X[pixelArray.xPixels, 0], Y[pixelArray.xPixels, 0]];
};
devicePath: DevicePath ← ImagerScanConverter.CreatePath[PathMap, BoundingBox[clipPoly]];
clipPoly ← ToManhattanPolygon[devicePath, clipPoly, 0, 0];
PixelArrayGenerateRuns[pixelArray, runProc, clipPoly];
};
ENDCASE => {IF mask # NIL THEN ERROR};
IF clipPoly # clipper THEN ImagerManhattan.Destroy[clipPoly];
};
BitmapGenerateRuns: PROC [bitmap: PixelMap, runProc: PROC [sMin, fMin: INTEGER, fSize: NAT]] ~ TRUSTED {
refRep: REF ImagerPixelMaps.PixelMapRep ← bitmap.refRep;
rast: NAT ← refRep.rast;
s: INTEGER ← bitmap.sOrigin + MAX[bitmap.sMin, 0];
sMax: INTEGERMIN[bitmap.sOrigin + bitmap.sMin + bitmap.sSize, bitmap.sOrigin + refRep.lines];
linePtr: LONG POINTER TO CARDINAL ← refRep.pointer + Basics.LongMult[s-bitmap.sOrigin, rast];
fFirst: NATMAX[bitmap.fMin, 0];
fEnd: NATMAX[MIN[bitmap.fMin+bitmap.fSize, rast*bitsPerWord], 0];
fFirstWord: CARDINAL ← fFirst / bitsPerWord;
fFirstBit: CARDINAL ← fFirst MOD bitsPerWord;
IF refRep.lgBitsPerPixel # 0 THEN ERROR;
WHILE s < sMax DO
wordPtr: LONG POINTER TO CARDINAL ← linePtr+fFirstWord;
wordsWorth: CARDINAL ← Basics.BITSHIFT[wordPtr^, fFirstBit];
goodBitCount: INTEGER ← bitsPerWord-fFirstBit;
f: CARDINAL ← fFirst;
someRuns: BOOLEANFALSE;
WHILE f < fEnd DO
fStart: CARDINAL;
WHILE f < fEnd DO
IF goodBitCount = bitsPerWord AND wordsWorth = 0 THEN f ← f + bitsPerWord
ELSE {
f ← f + goodBitCount;
WHILE goodBitCount > 0 AND wordsWorth <= LAST[NAT] DO
goodBitCount ← goodBitCount-1;
wordsWorth ← wordsWorth*2;
ENDLOOP;
f ← f - goodBitCount;
IF goodBitCount > 0 THEN EXIT;
goodBitCount ← bitsPerWord;
};
wordPtr ← wordPtr + 1;
wordsWorth ← wordPtr^;
ENDLOOP;
fStart ← f;
WHILE f < fEnd DO
IF goodBitCount = bitsPerWord AND wordsWorth = LAST[CARDINAL] THEN f ← f + bitsPerWord
ELSE {
f ← f + goodBitCount;
WHILE goodBitCount > 0 AND wordsWorth > LAST[NAT] DO
goodBitCount ← goodBitCount-1;
wordsWorth ← wordsWorth*2;
ENDLOOP;
f ← f - goodBitCount;
IF goodBitCount > 0 THEN EXIT;
goodBitCount ← bitsPerWord;
};
wordPtr ← wordPtr + 1;
wordsWorth ← wordPtr^;
ENDLOOP;
f ← MIN[f, fEnd];
IF f > fStart THEN runProc[s, fStart+bitmap.fOrigin, f-fStart];
ENDLOOP;
s ← s + 1;
linePtr ← linePtr + rast;
ENDLOOP;
};
PixelArrayGenerateRuns: PROC [pixelArray: PixelArray, runProc: PROC [sMin, fMin: INTEGER, fSize: NAT], area: Mask] ~ {
buffer: ImagerBasic.PixelBuffer ← NEW[ImagerBasic.PixelBufferRep[BoundingBox[area].fSize+1]];
inverseM: Transformation ~ ImagerTransform.Invert[pixelArray.m];
nextPixel: ImagerBasic.Pair ← ImagerTransform.TransformVec[[0, 1], inverseM];
xDeltaPixel: Scaled.Value ← Scaled.FromReal[nextPixel.x];
yDeltaPixel: Scaled.Value ← Scaled.FromReal[nextPixel.y];
DoRun: PROC [sMin, fMin: INTEGER, fSize: CARDINAL] ~ {
start: ImagerBasic.Pair ← ImagerTransform.Transform[[0.5+sMin, 0.5+fMin], inverseM];
xStart: Scaled.Value ← Scaled.FromReal[start.x];
yStart: Scaled.Value ← Scaled.FromReal[start.y];
runStart: NAT ← 0;
fRel: NAT ← 0;
pixelArray.get[pixelArray, buffer, fSize, 0, xStart, yStart, xDeltaPixel, yDeltaPixel];
WHILE fRel < fSize DO
buffer[fSize] ← 0;
WHILE buffer[fRel] # 0 DO fRel ← fRel + 1 ENDLOOP;
IF fRel > runStart THEN {runProc[sMin, fMin + runStart, fRel - runStart]};
buffer[fSize] ← 1;
WHILE buffer[fRel] = 0 DO fRel ← fRel + 1 ENDLOOP;
runStart ← fRel;
ENDLOOP;
};
GenerateRuns[area, area, DoRun, 0, 0];
};
ApplyTile: PUBLIC PROC [mask, clipper: Mask, dest: PixelMap, tile: Tile, function: Function ← [null, null], sTranslate, fTranslate: INTEGER] ~ {
RunProc: PROC [sMin, fMin: INTEGER, fSize: NAT] ~ {
dest.Clip[[sMin, fMin, 1, fSize]].TransferTile[tile, function];
};
GenerateRuns[mask, clipper, RunProc, sTranslate, fTranslate];
};
ApplyConstant: PUBLIC PROC [mask, clipper: Mask, dest: PixelMap, value: CARDINAL, function: Function ← [null, null], sTranslate, fTranslate: INTEGER] ~ {
RunProc: PROC [sMin, fMin: INTEGER, fSize: NAT] ~ {
dest.Fill[[sMin, fMin, 1, fSize], value, function];
};
clipPoly: ManhattanPolygon ← WITH clipper SELECT FROM
polygon: ManhattanPolygon => polygon,
ENDCASE => ToManhattanPolygon[clipper, BBList[clipper], 0, 0];
WITH mask SELECT FROM
polygon: ManhattanPolygon => {
IF clipPoly # NIL AND clipPoly.rest = NIL THEN {
clippedDest: PixelMap ← dest.Clip[clipPoly.first];
FOR l: LIST OF DeviceRectangle ← polygon, l.rest UNTIL l=NIL DO
ImagerPixelMaps.Fill[clippedDest, [l.first.sMin+sTranslate, l.first.fMin+fTranslate, l.first.sSize, l.first.fSize], value, function];
ENDLOOP;
}
ELSE GenerateRuns[mask, clipPoly, RunProc, sTranslate, fTranslate];
};
devicePath: DevicePath => {
IF clipPoly # NIL AND clipPoly.rest = NIL AND sTranslate = 0 AND fTranslate = 0 THEN {
devicePath.ConvertToPixels[pixelMap: dest.Clip[clipPoly.first], value: value, function: function];
}
ELSE GenerateRuns[mask, clipPoly, RunProc, sTranslate, fTranslate];
};
bitmap: REF PixelMap => {
IF clipPoly # NIL AND clipPoly.rest = NIL THEN {
SELECT TRUE FROM
dest.refRep.lgBitsPerPixel = 0 AND function = [null, null] => {
pixelMap: PixelMap ← bitmap^;
pixelMap.sOrigin ← pixelMap.sOrigin + sTranslate;
pixelMap.fOrigin ← pixelMap.fOrigin + fTranslate;
IF value MOD 2 = 1 THEN function ← [or, null]
ELSE function ← [and, complement];
dest.Clip[clipPoly.first].Transfer[pixelMap, function];
};
bitmap.refRep.lgBitsPerPixel = 0 AND function = [xor, null] => {
pixelMap: PixelMap ← bitmap^;
IF value MOD 2 = 0 THEN RETURN;
pixelMap.sOrigin ← pixelMap.sOrigin + sTranslate;
pixelMap.fOrigin ← pixelMap.fOrigin + fTranslate;
dest.Clip[clipPoly.first].Transfer[pixelMap, function];
};
ENDCASE => GenerateRuns[mask, clipPoly, RunProc, sTranslate, fTranslate];
}
ELSE GenerateRuns[mask, clipPoly, RunProc, sTranslate, fTranslate];
};
ENDCASE => {
GenerateRuns[mask, clipPoly, RunProc, sTranslate, fTranslate];
};
IF clipPoly # clipper THEN ImagerManhattan.Destroy[clipPoly];
};
ToPixelMap: PUBLIC PROC [mask, clipper: Mask, sTranslate, fTranslate: INTEGER, scratch: REF ImagerPixelMaps.PixelMapRep]
RETURNS [pixelMap: PixelMap] ~ {
bb: DeviceRectangle ← BoundingBox[mask];
bb.sMin ← bb.sMin + sTranslate;
bb.fMin ← bb.fMin + fTranslate;
bb ← ImagerPixelMaps.Intersect[bb, BoundingBox[clipper]];
pixelMap ← ImagerPixelMaps.Reshape[scratch, 0, bb];
ImagerPixelMaps.Clear[pixelMap];
ApplyConstant[mask, clipper, pixelMap, 1, [null, null], sTranslate, sTranslate];
};
ToManhattanPolygon: PUBLIC PROC [mask, clipper: Mask, sTranslate, fTranslate: INTEGER] RETURNS [manhattanPolygon: ManhattanPolygon] ~ {
Runs: PROC [
run: PROC [sMin, fMin: INTEGER, fSize: NAT],
repeat: PROC [timesToRepeatScanline: NAT]
] ~ {
GenerateRuns[mask, clipper, run, sTranslate, fTranslate];
};
manhattanPolygon ← ImagerManhattan.CreateFromRuns[Runs];
};
PixelArrayFromPixelMap: PUBLIC PROC [pixelMap: PixelMap] RETURNS [pixelArray: PixelArray] ~ {
pixelArray ← NEW[ImagerBasic.PixelArrayRep];
pixelArray.xPixels ← pixelMap.sSize;
pixelArray.yPixels ← pixelMap.fSize;
pixelArray.samplesPerPixel ← 1;
pixelArray.m ← ImagerTransform.Rotate[0];
pixelArray.data ← NEW[ImagerPixelMaps.PixelMap ← pixelMap];
SELECT pixelMap.refRep.lgBitsPerPixel FROM
0 => {
pixelArray.maxSampleValue ← 1;
pixelArray.get ← GetOne;
};
1 => {
pixelArray.maxSampleValue ← 3;
pixelArray.get ← GetTwo;
};
2 => {
pixelArray.maxSampleValue ← 15;
pixelArray.get ← GetFour;
};
3 => {
pixelArray.maxSampleValue ← 255;
pixelArray.get ← GetEight;
};
4 => {
pixelArray.maxSampleValue ← LAST[CARDINAL];
pixelArray.get ← GetSixteen;
};
ENDCASE => ERROR;
};
GetOne: PROC [self: ImagerBasic.PixelArray, buffer: ImagerBasic.PixelBuffer, nSamples: NAT, layer: INT, xStart, yStart: Scaled.Value, xDelta, yDelta: Scaled.Value] ~ {
pixelArrayRef: REF ImagerPixelMaps.PixelMap ~ NARROW[self.data];
pixelArray: ImagerPixelMaps.PixelMap ~ pixelArrayRef^;
IF layer#0 THEN ERROR;
FOR i: NAT IN [0..nSamples) DO
WHILE yStart.Floor < 0 DO
yStart ← yStart.PLUS[Scaled.FromInt[pixelArray.fSize]];
ENDLOOP;
WHILE yStart.Floor >= pixelArray.fSize DO
yStart ← yStart.MINUS[Scaled.FromInt[pixelArray.fSize]];
ENDLOOP;
WHILE xStart.Floor < 0 DO
xStart ← xStart.PLUS[Scaled.FromInt[pixelArray.sSize]];
ENDLOOP;
WHILE xStart.Floor >= pixelArray.sSize DO
xStart ← xStart.MINUS[Scaled.FromInt[pixelArray.sSize]];
ENDLOOP;
buffer[i] ← pixelArray.GetBit[xStart.Floor, yStart.Floor];
xStart ← xStart.PLUS[xDelta];
yStart ← yStart.PLUS[yDelta];
ENDLOOP;
};
GetTwo: PROC [self: ImagerBasic.PixelArray, buffer: ImagerBasic.PixelBuffer, nSamples: NAT, layer: INT, xStart, yStart: Scaled.Value, xDelta, yDelta: Scaled.Value] ~ {
pixelArrayRef: REF ImagerPixelMaps.PixelMap ~ NARROW[self.data];
pixelArray: ImagerPixelMaps.PixelMap ~ pixelArrayRef^;
IF layer#0 THEN ERROR;
FOR i: NAT IN [0..nSamples) DO
WHILE yStart.Floor < 0 DO
yStart ← yStart.PLUS[Scaled.FromInt[pixelArray.fSize]];
ENDLOOP;
WHILE yStart.Floor >= pixelArray.fSize DO
yStart ← yStart.MINUS[Scaled.FromInt[pixelArray.fSize]];
ENDLOOP;
WHILE xStart.Floor < 0 DO
xStart ← xStart.PLUS[Scaled.FromInt[pixelArray.sSize]];
ENDLOOP;
WHILE xStart.Floor >= pixelArray.sSize DO
xStart ← xStart.MINUS[Scaled.FromInt[pixelArray.sSize]];
ENDLOOP;
buffer[i] ← pixelArray.Get2Bits[xStart.Floor, yStart.Floor];
xStart ← xStart.PLUS[xDelta];
yStart ← yStart.PLUS[yDelta];
ENDLOOP;
};
GetFour: PROC [self: ImagerBasic.PixelArray, buffer: ImagerBasic.PixelBuffer, nSamples: NAT, layer: INT, xStart, yStart: Scaled.Value, xDelta, yDelta: Scaled.Value] ~ {
pixelArrayRef: REF ImagerPixelMaps.PixelMap ~ NARROW[self.data];
pixelArray: ImagerPixelMaps.PixelMap ~ pixelArrayRef^;
IF layer#0 THEN ERROR;
FOR i: NAT IN [0..nSamples) DO
WHILE yStart.Floor < 0 DO
yStart ← yStart.PLUS[Scaled.FromInt[pixelArray.fSize]];
ENDLOOP;
WHILE yStart.Floor >= pixelArray.fSize DO
yStart ← yStart.MINUS[Scaled.FromInt[pixelArray.fSize]];
ENDLOOP;
WHILE xStart.Floor < 0 DO
xStart ← xStart.PLUS[Scaled.FromInt[pixelArray.sSize]];
ENDLOOP;
WHILE xStart.Floor >= pixelArray.sSize DO
xStart ← xStart.MINUS[Scaled.FromInt[pixelArray.sSize]];
ENDLOOP;
buffer[i] ← pixelArray.Get4Bits[xStart.Floor, yStart.Floor];
xStart ← xStart.PLUS[xDelta];
yStart ← yStart.PLUS[yDelta];
ENDLOOP;
};
GetEight: PROC [self: ImagerBasic.PixelArray, buffer: ImagerBasic.PixelBuffer, nSamples: NAT, layer: INT, xStart, yStart: Scaled.Value, xDelta, yDelta: Scaled.Value] ~ {
pixelArrayRef: REF ImagerPixelMaps.PixelMap ~ NARROW[self.data];
pixelArray: ImagerPixelMaps.PixelMap ~ pixelArrayRef^;
IF layer#0 THEN ERROR;
FOR i: NAT IN [0..nSamples) DO
WHILE yStart.Floor < 0 DO
yStart ← yStart.PLUS[Scaled.FromInt[pixelArray.fSize]];
ENDLOOP;
WHILE yStart.Floor >= pixelArray.fSize DO
yStart ← yStart.MINUS[Scaled.FromInt[pixelArray.fSize]];
ENDLOOP;
WHILE xStart.Floor < 0 DO
xStart ← xStart.PLUS[Scaled.FromInt[pixelArray.sSize]];
ENDLOOP;
WHILE xStart.Floor >= pixelArray.sSize DO
xStart ← xStart.MINUS[Scaled.FromInt[pixelArray.sSize]];
ENDLOOP;
buffer[i] ← pixelArray.Get8Bits[xStart.Floor, yStart.Floor];
xStart ← xStart.PLUS[xDelta];
yStart ← yStart.PLUS[yDelta];
ENDLOOP;
};
GetSixteen: PROC [self: ImagerBasic.PixelArray, buffer: ImagerBasic.PixelBuffer, nSamples: NAT, layer: INT, xStart, yStart: Scaled.Value, xDelta, yDelta: Scaled.Value] ~ {
pixelArrayRef: REF ImagerPixelMaps.PixelMap ~ NARROW[self.data];
pixelArray: ImagerPixelMaps.PixelMap ~ pixelArrayRef^;
IF layer#0 THEN ERROR;
FOR i: NAT IN [0..nSamples) DO
WHILE yStart.Floor < 0 DO
yStart ← yStart.PLUS[Scaled.FromInt[pixelArray.fSize]];
ENDLOOP;
WHILE yStart.Floor >= pixelArray.fSize DO
yStart ← yStart.MINUS[Scaled.FromInt[pixelArray.fSize]];
ENDLOOP;
WHILE xStart.Floor < 0 DO
xStart ← xStart.PLUS[Scaled.FromInt[pixelArray.sSize]];
ENDLOOP;
WHILE xStart.Floor >= pixelArray.sSize DO
xStart ← xStart.MINUS[Scaled.FromInt[pixelArray.sSize]];
ENDLOOP;
buffer[i] ← pixelArray.Get16Bits[xStart.Floor, yStart.Floor];
xStart ← xStart.PLUS[xDelta];
yStart ← yStart.PLUS[yDelta];
ENDLOOP;
};
END.
ApplyConstantUsingRuns: PROC [mask: Mask, dest: PixelMap, value: CARDINAL, function: Function] ~ TRUSTED {
lgBitsPerPixel: INTEGER ~ dest.refRep.lgBitsPerPixel;
lgPixelsPerWord: INTEGER ~ lgBitsPerWord-lgBitsPerPixel;
rast: CARDINAL ~ dest.refRep.rast;
sMinClip: INTEGER ~ MAX[
INT[mask.sOrigin]+mask.sMin,
INT[dest.sOrigin]+dest.sMin,
dest.sOrigin
];
sMaxClip: INTEGER ~ MIN[
INT[mask.sOrigin]+mask.sMin+mask.sSize,
INT[dest.sOrigin]+dest.sMin+dest.sSize,
dest.sOrigin+dest.refRep.lines
];
fMinClip: INTEGER ~ MAX[
INT[mask.fOrigin]+mask.fMin,
INT[dest.fOrigin]+dest.fMin,
dest.fOrigin
];
fMaxClip: INTEGER ~ MIN[
INT[mask.fOrigin]+mask.fMin+mask.fSize,
INT[dest.fOrigin]+dest.fMin+dest.fSize,
INT[dest.fOrigin]+Shift[rast, lgBitsPerWord-lgBitsPerPixel]
];
IF sMaxClip>sMinClip AND fMaxClip>fMinClip THEN {
fMinBufferLimit: INTEGER ~ MAX[dest.fMin, 0];
fMaxBufferLimit: INTEGER ~ MIN[dest.fMin+dest.fSize, Shift[rast, lgBitsPerWord-lgBitsPerPixel]];
replicatedPixel: CARDINAL ← Basics.BITAND[value, Shift[1, Shift[1, lgBitsPerPixel]]-1] * replicator[lgBitsPerPixel];
bbTableSpace: BitBlt.BBTableSpace;
bb: BitBlt.BBptr ← BitBlt.AlignedBBTable[@bbTableSpace];
bitMask: CARDINAL ← Shift[1, lgPixelsPerWord]-1;
s: INTEGER ← sMinClip;
linePtr: LONG POINTER ← dest.refRep.pointer+Basics.LongMult[rast, sMinClip-dest.sOrigin];
RunProc: PROC [sMin, fMin: INTEGER, fSize: NAT] ~ TRUSTED {
fMinBuffer: NAT ← fMin-dest.fOrigin;
IF fMin + fSize > fMaxClip THEN ERROR;
IF NOT (sMin IN [s..sMaxClip)) THEN ERROR;
WHILE s<sMin DO
linePtr ← linePtr + rast;
s ← s + 1;
ENDLOOP;
bb.dst.word ← linePtr + Shift[fMinBuffer, -lgPixelsPerWord];
bb.dst.bit ← Basics.BITAND[fMinBuffer, bitMask];
bb.width ← Shift[fSize, lgBitsPerPixel];
BitBlt.BITBLT[bb];
};
bb^ ← [
dst: [word: NIL, bit: 0],
dstBpl: rast*bitsPerWord,
src: [word: @replicatedPixel, bit: 0],
srcDesc: [gray[[yOffset: 0, widthMinusOne: 0, heightMinusOne: 0]]],
height: 1,
width: 0,
flags: [direction: forward, disjoint: TRUE, disjointItems: TRUE, gray: TRUE, srcFunc: function.srcFunc, dstFunc: function.dstFunc]
];
mask.sSize ← sMaxClip-sMinClip;
mask.fSize ← fMaxClip-fMinClip;
mask.sMin ← sMinClip - mask.sOrigin;
mask.fMin ← fMinClip - mask.fOrigin;
mask.class.generateRuns[mask, RunProc];
};
};
BitmapApplyConstant: PROC [mask: Mask, dest: PixelMap, value: CARDINAL, function: Function] ~ TRUSTED {
WITH mask.data SELECT FROM
refRep: REF ImagerPixelMaps.PixelMapRep => {
IF dest.refRep.lgBitsPerPixel = 0 THEN {
sMin: INTEGER ~ MAX[dest.sOrigin+MAX[dest.sMin, 0], mask.sOrigin+MAX[mask.sMin, 0]];
sMax: INTEGER ~ MIN[dest.sOrigin+MIN[dest.sMin+dest.sSize, dest.refRep.lines], mask.sOrigin+MIN[mask.sMin+mask.sSize, refRep.lines]];
fMin: INTEGER ~ MAX[dest.fOrigin+MAX[dest.fMin, 0], mask.fOrigin+MAX[mask.fMin, 0]];
fMax: INTEGER ~ MIN[dest.fOrigin+MIN[dest.fMin+dest.fSize, dest.refRep.rast * bitsPerWord], mask.fOrigin+MIN[mask.fMin+mask.fSize, refRep.rast * bitsPerWord]];
bbTableSpace: BitBlt.BBTableSpace;
bb: BitBlt.BBptr ~ BitBlt.AlignedBBTable[@bbTableSpace];
fMinDest: NAT ~ fMin - dest.fOrigin;
fMinSource: NAT ~ fMin - mask.fOrigin;
sStartDest: NAT ~ sMin-dest.sOrigin;
sStartSource: NAT ~ sMin-mask.sOrigin;
srcFunc: BitBlt.SrcFunc ← null;
dstFunc: BitBlt.DstFunc ← or;
IF function.srcFunc = complement THEN value ← 1-value;
IF value MOD 2 = 0 THEN {
IF function.dstFunc = xor THEN RETURN;
srcFunc ← complement; dstFunc ← and;
};
IF function.dstFunc = xor THEN dstFunc ← xor;
IF sMin<sMax AND fMin<fMax THEN {
bb^ ← [
dstBpl: dest.refRep.rast*bitsPerWord,
srcDesc: [srcBpl[refRep.rast*bitsPerWord]],
height: sMax-sMin,
width: fMax-fMin,
flags: [direction: forward, disjoint: TRUE, disjointItems: TRUE, gray: FALSE, srcFunc: srcFunc, dstFunc: dstFunc]
];
bb.dst ← [word: dest.refRep.pointer + Basics.LongMult[sStartDest, dest.refRep.rast] + fMinDest/bitsPerWord, bit: fMinDest MOD bitsPerWord];
bb.src ← [word: refRep.pointer + Basics.LongMult[sStartSource, refRep.rast] + fMinSource/bitsPerWord, bit: fMinSource MOD bitsPerWord];
BitBlt.BITBLT[bb];
};
}
ELSE ApplyConstantUsingRuns[mask, dest, value, function];
};
ENDCASE => ERROR;
};