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 { 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, brickRem: INTEGER, 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 { Div: PROC [num: INTEGER, denom: CARDINAL] RETURNS [INTEGER] ~ { 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] ~ { 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] ~ { 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]; 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. Î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 Because of an apparent bug in Real.FScale. pointer into the threshold brick row. Each word is the negative of the minimum pixel value that should be displayed as white. number of words to the end of the brick row; the row must extend at least 15 words past the end. These are in device, not buffer, coordinates This divide returns the greatest integer <= the real quotient. Returns a result in the range [0..denom) Returns a result in the range [0..denom) dest.sMin+dest.sOrigin-sPeriod < sMinBrick <= dest.sMin+dest.sOrigin Ê £˜J™J™BJ™-J™/J˜šÏk ˜ Jšœ˜Jšœ ˜ Jšœ ˜ Jšœ˜Jšœ˜Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜—J˜Jšœ ˜!Jšœ4˜;Jšœ˜Jšœœœ˜J˜š Ïnœœœœœ˜+Jšœœœ˜:J˜—š žœœœœœœ˜Jš œ œœœœœ ˜AJš œœœ œ œ˜DJšœ˜—š žœœ!œœœ˜MJšœ(™(Jšœœœ˜DJšœ-˜3Jšœ˜—š žœœœ œœœ˜Jšœœ˜#Jšœœ˜#Jšœ˜Jšœ˜J˜—š ž œœœœœ œ˜>Jšœ!˜!Jšœ˜—J˜šœœœ˜&J˜—Jšœ˜—…—!Š/û