ImagerHalftoneImpl.mesa
Copyright (C) 1984, 1985, Xerox Corporation. All rights reserved.
Michael Plass, January 7, 1985 3:36:43 pm PST
Edited by Doug Wyatt, November 22, 1983 1:10 pm
DIRECTORY
Basics,
ImagerBasic,
ImagerBrick,
ImagerHalftone,
ImagerTransform,
PrincOps,
Real,
RealFns,
Scaled;
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: CARDINAL ← IF 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: INTEGER ← MAX[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: INTEGER ← MAX[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: NAT ← MAX[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];
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: INTEGER ← MIN[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
Div:
PROC [num:
INTEGER, denom:
CARDINAL]
RETURNS [
INTEGER] ~ {
This divide returns the greatest integer <= the real quotient.
IF num >= 0 THEN RETURN [LOOPHOLE[LOOPHOLE[num, CARDINAL]/denom]]
ELSE RETURN [-1-LOOPHOLE[LOOPHOLE[-1-num, CARDINAL]/denom, INTEGER]]
};
PosMod:
PROC [num: Basics.LongNumber, denom:
CARDINAL]
RETURNS [
CARDINAL] ~ {
Returns a result in the range [0..denom)
IF num.highbits >= denom THEN num.highbits ← num.highbits MOD denom;
RETURN [Basics.LongDivMod[num.lc, denom].remainder]
};
Mod:
PROC [num:
INT, denom:
CARDINAL]
RETURNS [
CARDINAL] ~ {
Returns a result in the range [0..denom)
IF num >= 0 THEN RETURN [PosMod[[li[num]], denom]]
ELSE RETURN [denom-1-PosMod[[li[-1-num]], denom]]
};
Mul:
PROC [a:
INTEGER, b:
CARDINAL]
RETURNS [
INT] ~ {
IF a > 0 THEN RETURN [Basics.LongMult[a, b]]
ELSE RETURN [-INT[Basics.LongMult[-a, b]]]
};
sNperiods: INTEGER ← Div[dest.sMin+dest.sOrigin-deviceBrick.sMin, sPeriod];
sMinBrick:
INTEGER ← deviceBrick.sMin + Mul[sNperiods, sPeriod];
dest.sMin+dest.sOrigin-sPeriod < sMinBrick <= dest.sMin+dest.sOrigin
sModPeriod ← dest.sMin+dest.sOrigin-sMinBrick;
IF sModPeriod NOT IN [0..sPeriod) THEN ERROR;
fBrick ← Mod[dest.fMin+dest.fOrigin-deviceBrick.fMin-Mul[sNperiods, deviceBrick.phase], fPeriod]
};
runs[Run];
FreePixelBuffer[buffer];
};
MakeSquareBrick:
PUBLIC
PROC [size:
NAT, p, q:
INTEGER, pModulation, qModulation:
REAL, maxPixelValue:
CARDINAL]
RETURNS [DeviceBrick] ~ {
max: REAL ← ABS[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.