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]; 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 Michael Plass, February 8, 1984 2:56:08 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 Ê Ï˜J™J™.J™/J˜šÏk ˜ Jšœ˜Jšœ ˜ Jšœ ˜ Jšœ˜Jšœ˜Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜—J˜Jšœ ˜!Jšœ4˜;Jšœ˜Jšœœœ˜J˜š Ïnœœœœœ˜+Jšœœœ˜:J˜—š žœœœœœœ˜Jšœœ˜#Jšœœ˜#Jšœ˜Jšœ˜J˜—š ž œœœœœ œ˜>Jšœ!˜!Jšœ˜—J˜šœœœ˜&J˜—Jšœ˜—…— ,“