ImagerHalftoneImpl.mesa
Michael Plass, July 25, 1983 4:05 pm
DIRECTORY Environment, ImagerBasic, ImagerBrick, ImagerMasks, ImagerMasksPrivate, Inline, Real, Scaled, ImagerTransform, ImagerHalftone, RealFns;
ImagerHalftoneImpl: CEDAR PROGRAM
IMPORTS ImagerBrick, ImagerTransform, ImagerMasks, ImagerMasksPrivate, Inline, Real, Scaled, RealFns
EXPORTS ImagerHalftone
~ BEGIN OPEN ImagerHalftone;
MaskRep: TYPE ~ ImagerMasks.MaskRep;
Hi: PROC [a: CARDINAL] RETURNS [CARDINAL] ~
INLINE {RETURN[Inline.BITSHIFT[a, 1-Environment.bitsPerWord]]};
Shift: PROC [a: CARDINAL, amt: INTEGER] RETURNS [CARDINAL] ~
INLINE {RETURN[Inline.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: Environment.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 which 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
] ~ UNCHECKED {
p: LONG POINTER TO SixteenWords ← sourcePtr;
q: LONG POINTER TO SixteenWords ← brickPtr;
GetN: UNSAFE PROC [n: [0..16)] RETURNS [CARDINAL] ~ UNCHECKED INLINE {
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 [w];
}; -- GetFirst
Get16: UNSAFE PROC RETURNS [CARDINAL] ~ UNCHECKED INLINE {
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 [((((((((((((((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 dst.bit # 0 THEN {
z: INTEGERMAX[firstBits-INTEGER[count], 0];
m: CARDINAL ← Shift[1, firstBits] - Shift[1, z];
d^ ← Inline.BITOR[Inline.BITAND[d^, Inline.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^ ← Inline.BITOR[Inline.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;
};
Halftone: PUBLIC PROC [dest: Mask, mask: Mask, source: PixelArray, transformation: Transformation, deviceBrick: DeviceBrick] ~ {
WITH dest.refRep SELECT FROM
b: REF MaskRep.bitmap => TRUSTED {
sMask: Mask ← mask.InlineShift[-dest.sMin, -dest.fMin];
sMin: NATMAX[sMask.sMin, 0];
sMax: NATMIN[dest.sSize, b.lines, sMask.sMin + sMask.sSize];
fMin: NATMAX[sMask.fMin, 0];
fMax: NATMIN[dest.fSize, b.rast*Environment.bitsPerWord, sMask.fMin + sMask.fSize];
nextPixel: ImagerBasic.Pair ← ImagerTransform.InverseTransformVec[[0, 1], transformation];
nextLine: ImagerBasic.Pair ← ImagerTransform.InverseTransformVec[[1, 0], transformation];
start: ImagerBasic.Pair ← ImagerTransform.InverseTransform[[0.5+sMin+dest.sMin, 0.5+fMin+dest.fMin], transformation];
xStart: Scaled.Value ← ScaledFromReal[start.x];
yStart: Scaled.Value ← ScaledFromReal[start.y];
xDeltaPixel: Scaled.Value ← ScaledFromReal[nextPixel.x];
yDeltaPixel: Scaled.Value ← ScaledFromReal[nextPixel.y];
xDeltaLine: Scaled.Value ← ScaledFromReal[nextLine.x];
yDeltaLine: Scaled.Value ← ScaledFromReal[nextLine.y];
lineBits: NAT ← fMax - fMin;
buffer: PixelBuffer ← NEW[ImagerBasic.PixelBufferRep[lineBits]];
linePointer: LONG POINTER ← b.pointer + Inline.LongMult[sMin, b.rast];
sPeriod: CARDINAL ← deviceBrick.sPeriod;
fPeriod: CARDINAL ← deviceBrick.fPeriod;
sDivPeriod, sModPeriod: CARDINAL;
fBrick: NAT;
sMinBrick: INT ← sMin-(INT[deviceBrick.sMin]-(dest.sMin MOD sPeriod));
fMinBrick: INT ← fMin-(INT[deviceBrick.fMin]-(dest.fMin MOD fPeriod));
WHILE sMinBrick < 0 DO sMinBrick ← sMinBrick + sPeriod ENDLOOP;
WHILE fMinBrick < 0 DO fMinBrick ← fMinBrick + fPeriod ENDLOOP;
[quotient: sDivPeriod, remainder: sModPeriod] ← Inline.LongDivMod[sMinBrick, sPeriod];
fBrick ← Inline.LongDivMod[Inline.LongMult[sDivPeriod, deviceBrick.phase] + fMinBrick, fPeriod].remainder;
IF sMask.refRep = NIL THEN {
bitAddress: Environment.BitAddress ← [word: linePointer + fMin/16, bit: fMin MOD 16];
FOR s: CARDINAL IN [sMin..sMax) DO
brickRow: PixelBuffer ← deviceBrick[sModPeriod];
brickPtr: LONG POINTER ← @(brickRow[fBrick]);
brickRem: INTEGER ← brickRow.maxLength - 15 - fBrick;
source.get[source, buffer, lineBits, 0, xStart, yStart, xDeltaPixel, yDeltaPixel];
DoLine[dst: bitAddress, count: lineBits, sourcePtr: @(buffer[0]), brickPtr: brickPtr, brickRem: brickRem, brickPeriod: fPeriod];
bitAddress.word ← bitAddress.word + b.rast;
xStart ← xStart.PLUS[xDeltaLine];
yStart ← yStart.PLUS[yDeltaLine];
sModPeriod ← sModPeriod + 1;
IF sModPeriod = sPeriod THEN {
sModPeriod ← 0;
sDivPeriod ← sDivPeriod + 1;
fBrick ← fBrick + deviceBrick.phase;
WHILE fBrick >= fPeriod DO fBrick ← fBrick - fPeriod ENDLOOP;
};
ENDLOOP;
}
ELSE {
sMaskReader: ImagerMasksPrivate.Reader;
ImagerMasksPrivate.SetReader[@sMaskReader, sMask];
ImagerMasksPrivate.SkipTo[@sMaskReader, sMin];
FOR s: NAT IN [sMin..sMax) DO
brickRow: PixelBuffer ← deviceBrick[sModPeriod];
brickPtr: LONG POINTER ← @(brickRow[fBrick]);
brickRem: INTEGER ← brickRow.maxLength - 15 - fBrick;
source.get[source, buffer, lineBits, 0, xStart, yStart, xDeltaPixel, yDeltaPixel];
WHILE sMaskReader.s = s DO
fStart: NAT ← sMaskReader.fMin-fMin;
DoLine[dst: [word: linePointer + sMaskReader.fMin/16, bit: sMaskReader.fMin MOD 16], count: sMaskReader.fMax-sMaskReader.fMin, sourcePtr: @(buffer[fStart]), brickPtr: brickPtr+fStart, brickRem: brickRem-fStart, brickPeriod: fPeriod];
ImagerMasksPrivate.Advance[@sMaskReader];
ENDLOOP;
linePointer ← linePointer + b.rast;
xStart ← xStart.PLUS[xDeltaLine];
yStart ← yStart.PLUS[yDeltaLine];
sModPeriod ← sModPeriod + 1;
IF sModPeriod = sPeriod THEN {
sModPeriod ← 0;
sDivPeriod ← sDivPeriod + 1;
fBrick ← fBrick + deviceBrick.phase;
WHILE fBrick >= fPeriod DO fBrick ← fBrick - fPeriod ENDLOOP;
};
ENDLOOP;
};
};
ENDCASE => ERROR;
};
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 Environment.bitsPerWord # 16 THEN ERROR;
END.