<> <> <> <> 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.