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 { 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]; 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: 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 { 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: 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 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 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 Ê ˜™Jšœ Ïmœ.™9J™.J™(—J˜šÏk ˜ Jš œžœžœžœžœžœžœ ˜NJšœ žœ˜)Jšœ žœ˜+JšœžœY˜mJšœžœ1˜FJšœ žœ˜Jšœžœ˜Jšœžœ ˜Jšœžœ ˜J˜—Jšœž ˜!Jšžœ4˜;Jšžœ˜Jšœžœžœ˜J˜š Ïnœžœžœžœžœ˜+Jšžœžœžœ˜:J˜—š Ÿœžœžœžœžœžœ˜Jšœžœ˜#Jšœžœ˜#Jšœ˜Jšœ˜J˜—š Ÿ œžœžœžœžœ žœ˜>Jšœ!˜!Jšœ˜—J˜šžœžœžœ˜&J˜—Jšžœ˜—…—!n.j