ImagerHalftoneImpl.mesa
Michael Plass, October 4, 1983 10:01 am
DIRECTORY Environment, ImagerBasic, ImagerBrick, ImagerMasks, ImagerMasksPrivate, Inline, Real, Scaled, ImagerTransform, ImagerHalftone, RealFns, ImagerPixelMaps;
ImagerHalftoneImpl:
CEDAR PROGRAM
IMPORTS ImagerBrick, ImagerTransform, ImagerMasks, ImagerMasksPrivate, Inline, Real, Scaled, RealFns
EXPORTS ImagerHalftone
~ BEGIN OPEN ImagerHalftone;
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 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
] ~ UNCHECKED {
p: LONG POINTER TO SixteenWords ← sourcePtr;
q: LONG POINTER TO SixteenWords ← brickPtr;
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 [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: INTEGER ← MAX[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: 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;
};
Halftone:
PUBLIC
PROC [dest: PixelMap, mask: Mask, source: PixelArray, transformation: Transformation, deviceBrick: DeviceBrick] ~
TRUSTED {
raster: CARDINAL ← dest.refRep.rast;
sMask: Mask ← mask.InlineShift[-(dest.sMin+dest.sOrigin), -(dest.fMin+dest.fOrigin)];
sMin: NAT ← MAX[sMask.sMin, 0];
sMax: NAT ← MIN[dest.sSize, dest.refRep.lines, sMask.sMin + sMask.sSize];
fMin: NAT ← MAX[sMask.fMin, 0];
fMax: NAT ← MIN[dest.fSize, raster*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+dest.fOrigin, 0.5+fMin+dest.fMin+dest.fOrigin], 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 ← dest.refRep.pointer + Inline.LongMult[sMin, raster];
sPeriod: CARDINAL ← deviceBrick.sPeriod;
fPeriod: CARDINAL ← deviceBrick.fPeriod;
sDivPeriod, sModPeriod: CARDINAL;
fBrick: NAT;
sMinBrick: INT ← sMin-(INT[deviceBrick.sMin]-((dest.sMin+dest.sOrigin) MOD sPeriod));
fMinBrick: INT ← fMin-(INT[deviceBrick.fMin]-((dest.fMin+dest.fOrigin) MOD fPeriod));
WHILE sMinBrick < 0 DO sMinBrick ← sMinBrick + sPeriod ENDLOOP;
WHILE fMinBrick < 0 DO fMinBrick ← fMinBrick + fPeriod ENDLOOP;
IF dest.refRep.lgBitsPerPixel # 0 THEN ERROR;
[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 + raster;
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 + raster;
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;
};
};
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 Environment.bitsPerWord # 16 THEN ERROR;
END.