ImagerHalftoneImpl.mesa
Copyright © 1984 Xerox Corporation. All rights reserved.
Michael Plass, February 8, 1984 2:56:08 pm PST
Doug Wyatt, July 20, 1984 2:39:49 pm PDT
DIRECTORY
Basics USING [BITAND, BITNOT, BITOR, BITSHIFT, bitsPerWord, BITXOR, LongMult],
ImagerBasic USING [Pair, PixelBufferRep],
ImagerBrick USING [BuildBrick, GetElement],
ImagerHalftone USING [Brick, DeviceBrick, DeviceBrickRep, PixelArray, PixelBuffer, PixelMap, Transformation],
ImagerTransform USING [InverseTransform, InverseTransformVec, Invert],
PrincOps USING [BitAddress],
Real USING [RoundI, RoundLI],
RealFns USING [CosDeg],
Scaled USING [Value];
ImagerHalftoneImpl: CEDAR MONITOR
IMPORTS Basics, ImagerBrick, ImagerTransform, Real, RealFns
EXPORTS ImagerHalftone
~ BEGIN OPEN ImagerHalftone;
Hi: PROC [a: CARDINAL] RETURNS [CARDINAL] ~
INLINE {RETURN[Basics.BITSHIFT[a, 1-Basics.bitsPerWord]]};
Shift: PROC [a: CARDINAL, amt: INTEGER] RETURNS [CARDINAL] ~
INLINE {RETURN[Basics.BITSHIFT[a, amt]]};
ScaledFromReal: PROC [real: REAL] RETURNS [Scaled.Value] ~ TRUSTED {
Because of an apparent bug in Real.FScale.
i: INT ← Real.RoundLI[real * 65536.0];
RETURN[LOOPHOLE[i]]
};
SixteenWords: TYPE ~ MACHINE DEPENDENT RECORD [
w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15: CARDINAL
];
DoLine: UNSAFE PROC [
dst: PrincOps.BitAddress,
count: CARDINAL,
sourcePtr: LONG POINTER,
brickPtr: LONG POINTER,
pointer into the threshold brick row. Each word is the negative of the minimum pixel value that should be displayed as white.
brickRem: INTEGER,
number of words to the end of the brick row; the row must extend at least 15 words past the end.
brickPeriod: NAT,
invertOutput: BOOLEAN,
transparent: BOOLEAN
] ~ UNCHECKED {
p: LONG POINTER TO SixteenWords ← sourcePtr;
q: LONG POINTER TO SixteenWords ← brickPtr;
allInvert: CARDINALIF invertOutput THEN LAST[CARDINAL] ELSE 0;
GetN: UNSAFE PROC [n: [0..16)] RETURNS [CARDINAL] ~ UNCHECKED {
w: CARDINAL ← 0;
WHILE brickRem <= 0 DO brickRem ← brickRem + brickPeriod; q ← q - brickPeriod ENDLOOP;
THROUGH [0..n) DO
w ← w*2 + Hi[p^.w0+q^.w0];
p ← p + 1;
q ← q + 1;
ENDLOOP;
brickRem ← brickRem - n;
RETURN [Basics.BITXOR[w, Basics.BITSHIFT[allInvert, n-16]]];
}; -- GetFirst
Get16: UNSAFE PROC RETURNS [CARDINAL] ~ UNCHECKED {
s, h: SixteenWords;
WHILE brickRem <= 0 DO brickRem ← brickRem + brickPeriod; q ← q - brickPeriod ENDLOOP;
s ← p^; p ← p + SIZE[SixteenWords];
h ← q^; q ← q + SIZE[SixteenWords];
brickRem ← brickRem - 16;
RETURN [Basics.BITXOR[allInvert, ((((((((((((((Hi[h.w0+s.w0]*2+Hi[h.w1+s.w1])*2+Hi[h.w2+s.w2])*2+Hi[h.w3+s.w3])*2+Hi[h.w4+s.w4])*2+Hi[h.w5+s.w5])*2+Hi[h.w6+s.w6])*2+Hi[h.w7+s.w7])*2+Hi[h.w8+s.w8])*2+Hi[h.w9+s.w9])*2+Hi[h.w10+s.w10])*2+Hi[h.w11+s.w11])*2+Hi[h.w12+s.w12])*2+Hi[h.w13+s.w13])*2+Hi[h.w14+s.w14])*2+Hi[h.w15+s.w15]]]
}; -- Get16
d: LONG POINTER TO CARDINAL ← dst.word;
firstBits: INTEGER ← 16-dst.bit;
IF transparent THEN {
IF dst.bit # 0 THEN {
z: INTEGERMAX[firstBits-INTEGER[count], 0];
d^ ← Basics.BITOR[d^, Shift[GetN[firstBits-z], z]];
d ← d + 1;
count ← count - (firstBits-z);
};
WHILE count >= 16 DO
d^ ← Basics.BITOR[d^, Get16[]];
d ← d + 1;
count ← count - 16;
ENDLOOP;
IF count > 0 THEN {
d^ ← Basics.BITOR[d^, Shift[GetN[count], 16-count]];
};
}
ELSE {
IF dst.bit # 0 THEN {
z: INTEGERMAX[firstBits-INTEGER[count], 0];
m: CARDINAL ← Shift[1, firstBits] - Shift[1, z];
d^ ← Basics.BITOR[Basics.BITAND[d^, Basics.BITNOT[m]], Shift[GetN[firstBits-z], z]];
d ← d + 1;
count ← count - (firstBits-z);
};
WHILE count >= 16 DO
d^ ← Get16[];
d ← d + 1;
count ← count - 16;
ENDLOOP;
IF count > 0 THEN {
d^ ← Basics.BITOR[Basics.BITAND[d^, Shift[1, 16-count]-1], Shift[GetN[count], 16-count]];
};
};
}; -- DoLine
Mod: PROC [p, q: INT] RETURNS [rem: INT] ~ {
IF q<0 THEN ERROR;
rem ← p MOD q;
WHILE rem < 0 DO rem ← rem + q ENDLOOP;
};
MakeDeviceBrick: PUBLIC PROC [brick: Brick, maxPixelValue: CARDINAL] RETURNS [d: DeviceBrick] ~ {
phase: NAT ← Mod[brick.phase, brick.fSize];
fMax: NATMAX[brick.fSize, 16] + phase + 15;
d ← NEW[DeviceBrickRep[brick.sSize]];
d.fMin ← 0;
d.sMin ← 0;
d.phase ← phase;
d.fPeriod ← brick.fSize;
FOR s: NAT IN [0..d.sPeriod) DO
r: PixelBuffer ← NEW[ImagerBasic.PixelBufferRep[fMax]];
d[s] ← r;
FOR f: NAT IN [0..fMax) DO
r[f] ← LAST[CARDINAL] - Real.RoundI[brick.GetElement[f, s] * (maxPixelValue-1)];
ENDLOOP;
ENDLOOP;
};
cachedPixelBuffer: PixelBuffer ← NIL;
AllocPixelBuffer: ENTRY PROC [lineBits: NAT] RETURNS [pixelBuffer: PixelBuffer] ~ INLINE {
IF cachedPixelBuffer = NIL OR cachedPixelBuffer.maxLength < lineBits THEN
pixelBuffer ← NEW[ImagerBasic.PixelBufferRep[lineBits]]
ELSE {
pixelBuffer ← cachedPixelBuffer;
cachedPixelBuffer ← NIL;
};
};
FreePixelBuffer: ENTRY PROC [pixelBuffer: PixelBuffer] ~ INLINE {
cachedPixelBuffer ← pixelBuffer;
};
ReduceModulo: PROC [p: ImagerBasic.Pair, xPixels, yPixels: REAL] RETURNS [ImagerBasic.Pair] ~ {
WHILE p.x < 0 DO p.x ← p.x + xPixels ENDLOOP;
WHILE p.x >= xPixels DO p.x ← p.x - xPixels ENDLOOP;
WHILE p.y < 0 DO p.y ← p.y + yPixels ENDLOOP;
WHILE p.y >= xPixels DO p.y ← p.y - yPixels ENDLOOP;
RETURN [p]
};
Halftone: PUBLIC PROC [dest: PixelMap, runs: PROC[run: PROC[sMin, fMin: INTEGER, fSize: NAT]], source: PixelArray, transformation: Transformation, deviceBrick: DeviceBrick, invertOutput: BOOLEAN, transparent: BOOLEAN] ~ TRUSTED {
raster: CARDINAL ~ dest.refRep.rast;
sMinBuf: NAT ~ MAX[dest.sMin, 0];
sMaxBuf: NAT ~ MIN[dest.sSize, dest.refRep.lines];
fMinBuf: NAT ~ MAX[dest.fMin, 0];
fMaxBuf: NAT ~ MIN[dest.fSize, raster*Basics.bitsPerWord];
inverseTransform: Transformation ~ ImagerTransform.Invert[transformation];
nextPixel: ImagerBasic.Pair ~ ImagerTransform.InverseTransformVec[[0, 1], transformation];
xDeltaPixel: Scaled.Value ~ ScaledFromReal[nextPixel.x];
yDeltaPixel: Scaled.Value ~ ScaledFromReal[nextPixel.y];
lineBits: NAT ~ fMaxBuf - fMinBuf;
buffer: PixelBuffer ~ AllocPixelBuffer[lineBits];
linePointer: LONG POINTER ← dest.refRep.pointer + Basics.LongMult[sMinBuf, raster];
s: NAT ← sMinBuf;
sPeriod: CARDINAL ~ deviceBrick.sPeriod;
fPeriod: CARDINAL ~ deviceBrick.fPeriod;
sModPeriod: CARDINAL;
fBrick: NAT;
Run: SAFE PROC [sMin, fMin: INTEGER, fSize: NAT] ~ TRUSTED {
sMin ← sMin - dest.sOrigin;
fMin ← fMin - dest.fOrigin;
IF sMin IN [sMinBuf..sMaxBuf) THEN {
fMax: INTEGERMIN[fMin+fSize, fMaxBuf];
fMin ← MAX[fMin, fMinBuf];
IF fMin < fMax THEN {
UNTIL s = sMin DO
s ← s + 1;
linePointer ← linePointer + raster;
sModPeriod ← sModPeriod + 1;
IF sModPeriod = sPeriod THEN {
sModPeriod ← 0;
fBrick ← fBrick + deviceBrick.phase;
WHILE fBrick >= fPeriod DO fBrick ← fBrick - fPeriod ENDLOOP;
};
ENDLOOP;
TRUSTED {
start: ImagerBasic.Pair ~ ReduceModulo[ImagerTransform.InverseTransform[[0.5+s+dest.sOrigin, 0.5+fMin+dest.fOrigin], transformation], source.xPixels, source.yPixels];
xStart: Scaled.Value ~ ScaledFromReal[start.x];
yStart: Scaled.Value ~ ScaledFromReal[start.y];
brickRow: PixelBuffer ← deviceBrick[sModPeriod];
brickPtr: LONG POINTER ← @(brickRow[fBrick]);
brickRem: INTEGER ← brickRow.maxLength - 15 - fBrick;
fStart: NAT ← fMin-fMinBuf;
fMinCardinal: CARDINAL ← fMin;
source.get[source, buffer, fMax-fMin, 0, xStart, yStart, xDeltaPixel, yDeltaPixel];
DoLine[dst: [word: linePointer + fMinCardinal/16, bit: fMinCardinal MOD 16], count: fMax-fMin, sourcePtr: @(buffer[0]), brickPtr: brickPtr+fStart, brickRem: brickRem-fStart, brickPeriod: fPeriod, invertOutput: invertOutput, transparent: transparent];
};
};
};
};
IF dest.refRep.lgBitsPerPixel # 0 THEN ERROR;
CHECKED {
These are in device, not buffer, coordinates
sMinBrick: INT ← deviceBrick.sMin;
fMinBrick: INT ← deviceBrick.fMin;
WHILE sMinBrick < dest.sMin+dest.sOrigin DO
sMinBrick ← sMinBrick + sPeriod;
fMinBrick ← fMinBrick + deviceBrick.phase;
ENDLOOP;
WHILE sMinBrick > dest.sMin+dest.sOrigin DO
sMinBrick ← sMinBrick - sPeriod;
fMinBrick ← fMinBrick - deviceBrick.phase;
ENDLOOP;
WHILE fMinBrick < dest.fMin+dest.fOrigin DO
fMinBrick ← fMinBrick + fPeriod;
ENDLOOP;
WHILE fMinBrick > dest.fMin+dest.fOrigin DO
fMinBrick ← fMinBrick - fPeriod;
ENDLOOP;
sModPeriod ← dest.sMin+dest.sOrigin-sMinBrick;
fBrick ← dest.fMin+dest.fOrigin-fMinBrick;
};
runs[Run];
FreePixelBuffer[buffer];
};
MakeSquareBrick: PUBLIC PROC [size: NAT, p, q: INTEGER, pModulation, qModulation: REAL, maxPixelValue: CARDINAL] RETURNS [DeviceBrick] ~ {
max: REALABS[pModulation]+ABS[qModulation];
min: REAL ← -max;
Screen: PROC [x, y: REAL] RETURNS [fvalue: REAL] ~ {
x0: REAL ← (x+1)/2.0;
y0: REAL ← (y+1)/2.0;
u: REAL ← p * x0 + q * y0;
v: REAL ← -q * x0 + p * y0;
fvalue ← (pModulation*RealFns.CosDeg[u*360] + qModulation*RealFns.CosDeg[v*360] - min)/(max-min);
};
RETURN [MakeDeviceBrick[ImagerBrick.BuildBrick[size, 0, Screen], maxPixelValue]]
};
DotScreen: PUBLIC PROC [x, y: REAL] RETURNS [fvalue: REAL] ~ {
tx: REAL ← (x-1)*(x-1)*(x+1)*(x+1);
ty: REAL ← (y-1)*(y-1)*(y+1)*(y+1);
fvalue ← (tx+ty)/2;
};
LineScreen: PUBLIC PROC [x, y:REAL] RETURNS [fvalue: REAL] ~ {
fvalue ← (x-1)*(x-1)*(x+1)*(x+1);
};
IF Basics.bitsPerWord # 16 THEN ERROR;
END.