<> <> <> <> DIRECTORY Basics USING [BITSHIFT, bitsPerWord, LongMult], ImagerManhattan USING [BoundingBox, CountRuns, CreateFromBox, CreateFromRuns, Destroy, MapRuns, Polygon], ImagerMask USING [DevicePath, DeviceRectangle, Function, ManhattanPolygon, Mask, PixelMap, Tile, Transformation], ImagerPixelArray USING [PixelArray, PixelArrayRep], ImagerPixelMap USING [Clear, Clip, Fill, Intersect, PixelMap, PixelMapRep, Reshape, ShiftMap, Transfer, TransferTile, Trim], ImagerScanConverter USING [BoundingBox, ConvertToPixels, ConvertToRuns, NumberOfRuns], ImagerTransformation USING [IntRectangle, TransformIntRectangle], Real USING []; ImagerMaskImpl: CEDAR PROGRAM IMPORTS Basics, ImagerManhattan, ImagerPixelMap, ImagerTransformation, ImagerScanConverter EXPORTS ImagerMask ~ BEGIN OPEN ImagerMask; PixelArray: TYPE ~ ImagerPixelArray.PixelArray; PixelArrayRep: TYPE ~ ImagerPixelArray.PixelArrayRep; bitsPerWord: NAT ~ Basics.bitsPerWord; FromRectangle: PUBLIC PROC[box: DeviceRectangle] RETURNS[Mask] ~ { IF box.sSize = 0 OR box.fSize = 0 THEN RETURN [NIL] ELSE RETURN [ImagerManhattan.CreateFromBox[box]] }; FromBitmap: PUBLIC PROC [pixelMap: PixelMap] RETURNS [Mask] ~ { IF pixelMap.refRep.lgBitsPerPixel # 0 THEN ERROR; IF pixelMap.sSize = 0 OR pixelMap.fSize = 0 THEN RETURN [NIL] ELSE RETURN [NEW[PixelMap _ ImagerPixelMap.Trim[pixelMap]]]; }; FromPixelArray: PUBLIC PROC[pixelArray: PixelArray, compositeTransformation: Transformation] RETURNS [Mask] ~ { IF compositeTransformation = pixelArray.m THEN RETURN [pixelArray] ELSE { copy: PixelArray _ NEW[PixelArrayRep _ pixelArray^]; copy.m _ compositeTransformation; RETURN [copy] }; }; BBList: PROC [mask: Mask] RETURNS [LIST OF DeviceRectangle] ~ { RETURN [LIST[BoundingBox[mask]]] }; BoundingBox: PUBLIC PROC [mask: Mask] RETURNS [DeviceRectangle] ~ { WITH mask SELECT FROM polygon: ManhattanPolygon => RETURN [ImagerManhattan.BoundingBox[polygon]]; bitmap: REF PixelMap => { s: INT ~ INT[bitmap.sOrigin]+INT[bitmap.sMin]; f: INT ~ INT[bitmap.fOrigin]+INT[bitmap.fMin]; RETURN[[sMin: s, fMin: f, sSize: bitmap.sSize, fSize: bitmap.fSize]]; }; devicePath: DevicePath => RETURN [ImagerScanConverter.BoundingBox[devicePath]]; pixelArray: PixelArray => { bb: ImagerTransformation.IntRectangle _ pixelArray.m.TransformIntRectangle[ [x: 0, y: 0, w: pixelArray.sSize, h: pixelArray.fSize]]; RETURN [[bb.x, bb.y, bb.w, bb.h]]; }; ENDCASE => RETURN [[0, 0, 0, 0]]; }; CountRuns: PUBLIC PROC [mask: Mask] RETURNS [numberOfRuns: INT] ~ { WITH mask SELECT FROM polygon: ManhattanPolygon => RETURN [ImagerManhattan.CountRuns[polygon]]; devicePath: DevicePath => RETURN [ImagerScanConverter.NumberOfRuns[devicePath]]; ENDCASE => { count: INT _ 0; run: PROC[sMin, fMin: INTEGER, fSize: NAT] ~ { count _ count+1 }; t1: ManhattanPolygon _ ImagerManhattan.CreateFromBox[BoundingBox[mask]]; GenerateRuns[mask, t1, run, 0, 0]; ImagerManhattan.Destroy[t1]; RETURN[count]; }; }; GenerateRuns: PUBLIC PROC [mask, clipper: Mask, runProc: PROC [sMin, fMin: INTEGER, fSize: NAT], sTranslate, fTranslate: INTEGER] ~ { clipPoly: ManhattanPolygon _ WITH clipper SELECT FROM polygon: ManhattanPolygon => polygon, ENDCASE => ToManhattanPolygon[clipper, BBList[clipper], 0, 0]; remainder: ManhattanPolygon _ clipPoly; TranslateAndClipRunProc: PROC [sMin, fMin: INTEGER, fSize: NAT] ~ { sMin _ sMin + sTranslate; fMin _ fMin + fTranslate; WHILE remainder # NIL AND remainder.first.sMin + remainder.first.sSize <= sMin DO remainder _ remainder.rest; ENDLOOP; FOR l: LIST OF DeviceRectangle _ remainder, l.rest UNTIL l = NIL OR l.first.sMin > sMin DO fMinRun: INTEGER ~ MAX[l.first.fMin, fMin]; fMaxRun: INTEGER ~ MIN[l.first.fMin+l.first.fSize, fMin+fSize]; IF fMaxRun > fMinRun THEN runProc [sMin, fMinRun, fMaxRun-fMinRun]; ENDLOOP; }; WITH mask SELECT FROM polygon: ManhattanPolygon => ImagerManhattan.MapRuns[polygon, TranslateAndClipRunProc]; bitmap: REF PixelMap => { IF clipPoly # NIL AND clipPoly.rest = NIL THEN { BitmapGenerateRuns[bitmap^.ShiftMap[sTranslate, fTranslate].Clip[clipPoly.first], runProc]; } ELSE BitmapGenerateRuns[bitmap^, TranslateAndClipRunProc]; }; devicePath: DevicePath => { IF clipPoly # NIL AND clipPoly.rest = NIL AND sTranslate = 0 AND fTranslate = 0 THEN { devicePath.ConvertToRuns[runProc, clipPoly.first]; } ELSE { devicePath.ConvertToRuns[TranslateAndClipRunProc, ImagerManhattan.BoundingBox[clipPoly]]; }; }; < {>> <> <> <> <<};>> <> <> <<};>> <> <> <> <> <> <<};>> <> <> <> <<};>> ENDCASE => {IF mask # NIL THEN ERROR}; IF clipPoly # clipper THEN ImagerManhattan.Destroy[clipPoly]; }; BitmapGenerateRuns: PROC [bitmap: PixelMap, runProc: PROC [sMin, fMin: INTEGER, fSize: NAT]] ~ TRUSTED { refRep: REF ImagerPixelMap.PixelMapRep _ bitmap.refRep; rast: NAT _ refRep.rast; s: INTEGER _ bitmap.sOrigin + MAX[bitmap.sMin, 0]; sMax: INTEGER _ MIN[bitmap.sOrigin + bitmap.sMin + bitmap.sSize, bitmap.sOrigin + refRep.lines]; linePtr: LONG POINTER TO CARDINAL _ refRep.pointer + Basics.LongMult[s-bitmap.sOrigin, rast]; fFirst: NAT _ MAX[bitmap.fMin, 0]; fEnd: NAT _ MAX[MIN[bitmap.fMin+bitmap.fSize, rast*bitsPerWord], 0]; fFirstWord: CARDINAL _ fFirst / bitsPerWord; fFirstBit: CARDINAL _ fFirst MOD bitsPerWord; IF refRep.lgBitsPerPixel # 0 THEN ERROR; WHILE s < sMax DO wordPtr: LONG POINTER TO CARDINAL _ linePtr+fFirstWord; wordsWorth: CARDINAL _ Basics.BITSHIFT[wordPtr^, fFirstBit]; goodBitCount: INTEGER _ bitsPerWord-fFirstBit; f: CARDINAL _ fFirst; someRuns: BOOLEAN _ FALSE; WHILE f < fEnd DO fStart: CARDINAL; WHILE f < fEnd DO IF goodBitCount = bitsPerWord AND wordsWorth = 0 THEN f _ f + bitsPerWord ELSE { f _ f + goodBitCount; WHILE goodBitCount > 0 AND wordsWorth <= LAST[NAT] DO goodBitCount _ goodBitCount-1; wordsWorth _ wordsWorth*2; ENDLOOP; f _ f - goodBitCount; IF goodBitCount > 0 THEN EXIT; goodBitCount _ bitsPerWord; }; wordPtr _ wordPtr + 1; wordsWorth _ wordPtr^; ENDLOOP; fStart _ f; WHILE f < fEnd DO IF goodBitCount = bitsPerWord AND wordsWorth = LAST[CARDINAL] THEN f _ f + bitsPerWord ELSE { f _ f + goodBitCount; WHILE goodBitCount > 0 AND wordsWorth > LAST[NAT] DO goodBitCount _ goodBitCount-1; wordsWorth _ wordsWorth*2; ENDLOOP; f _ f - goodBitCount; IF goodBitCount > 0 THEN EXIT; goodBitCount _ bitsPerWord; }; wordPtr _ wordPtr + 1; wordsWorth _ wordPtr^; ENDLOOP; f _ MIN[f, fEnd]; IF f > fStart THEN runProc[s, fStart+bitmap.fOrigin, f-fStart]; ENDLOOP; s _ s + 1; linePtr _ linePtr + rast; ENDLOOP; }; <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> < runStart THEN {runProc[sMin, fMin + runStart, fRel - runStart]};>> <> <> <> <> <<};>> <> <<};>> <<>> ApplyTile: PUBLIC PROC [mask, clipper: Mask, dest: PixelMap, tile: Tile, function: Function _ [null, null], sTranslate, fTranslate: INTEGER] ~ { RunProc: PROC [sMin, fMin: INTEGER, fSize: NAT] ~ { dest.Clip[[sMin, fMin, 1, fSize]].TransferTile[tile, function]; }; GenerateRuns[mask, clipper, RunProc, sTranslate, fTranslate]; }; ApplyConstant: PUBLIC PROC [mask, clipper: Mask, dest: PixelMap, value: CARDINAL, function: Function _ [null, null], sTranslate, fTranslate: INTEGER] ~ { RunProc: PROC [sMin, fMin: INTEGER, fSize: NAT] ~ { dest.Fill[[sMin, fMin, 1, fSize], value, function]; }; clipPoly: ManhattanPolygon _ WITH clipper SELECT FROM polygon: ManhattanPolygon => polygon, ENDCASE => ToManhattanPolygon[clipper, BBList[clipper], 0, 0]; WITH mask SELECT FROM polygon: ManhattanPolygon => { IF clipPoly # NIL AND clipPoly.rest = NIL THEN { clippedDest: PixelMap _ dest.Clip[clipPoly.first]; FOR l: LIST OF DeviceRectangle _ polygon, l.rest UNTIL l=NIL DO ImagerPixelMap.Fill[clippedDest, [l.first.sMin+sTranslate, l.first.fMin+fTranslate, l.first.sSize, l.first.fSize], value, function]; ENDLOOP; } ELSE GenerateRuns[mask, clipPoly, RunProc, sTranslate, fTranslate]; }; devicePath: DevicePath => { IF clipPoly # NIL AND clipPoly.rest = NIL AND sTranslate = 0 AND fTranslate = 0 THEN { devicePath.ConvertToPixels[pixelMap: dest.Clip[clipPoly.first], value: value, function: function]; } ELSE GenerateRuns[mask, clipPoly, RunProc, sTranslate, fTranslate]; }; bitmap: REF PixelMap => { IF clipPoly # NIL AND clipPoly.rest = NIL THEN { SELECT TRUE FROM dest.refRep.lgBitsPerPixel = 0 AND function = [null, null] => { pixelMap: PixelMap _ bitmap^; pixelMap.sOrigin _ pixelMap.sOrigin + sTranslate; pixelMap.fOrigin _ pixelMap.fOrigin + fTranslate; IF value MOD 2 = 1 THEN function _ [or, null] ELSE function _ [and, complement]; dest.Clip[clipPoly.first].Transfer[pixelMap, function]; }; bitmap.refRep.lgBitsPerPixel = 0 AND function = [xor, null] => { pixelMap: PixelMap _ bitmap^; IF value MOD 2 = 0 THEN RETURN; pixelMap.sOrigin _ pixelMap.sOrigin + sTranslate; pixelMap.fOrigin _ pixelMap.fOrigin + fTranslate; dest.Clip[clipPoly.first].Transfer[pixelMap, function]; }; ENDCASE => GenerateRuns[mask, clipPoly, RunProc, sTranslate, fTranslate]; } ELSE GenerateRuns[mask, clipPoly, RunProc, sTranslate, fTranslate]; }; ENDCASE => { GenerateRuns[mask, clipPoly, RunProc, sTranslate, fTranslate]; }; IF clipPoly # clipper THEN ImagerManhattan.Destroy[clipPoly]; }; ToPixelMap: PUBLIC PROC [mask, clipper: Mask, sTranslate, fTranslate: INTEGER, scratch: REF ImagerPixelMap.PixelMapRep] RETURNS [pixelMap: PixelMap] ~ { bb: DeviceRectangle _ BoundingBox[mask]; bb.sMin _ bb.sMin + sTranslate; bb.fMin _ bb.fMin + fTranslate; bb _ ImagerPixelMap.Intersect[bb, BoundingBox[clipper]]; pixelMap _ ImagerPixelMap.Reshape[scratch, 0, bb]; ImagerPixelMap.Clear[pixelMap]; ApplyConstant[mask, clipper, pixelMap, 1, [null, null], sTranslate, sTranslate]; }; ToManhattanPolygon: PUBLIC PROC [mask, clipper: Mask, sTranslate, fTranslate: INTEGER] RETURNS [manhattanPolygon: ManhattanPolygon] ~ { Runs: PROC [ run: PROC [sMin, fMin: INTEGER, fSize: NAT], repeat: PROC [timesToRepeatScanline: NAT] ] ~ { GenerateRuns[mask, clipper, run, sTranslate, fTranslate]; }; manhattanPolygon _ ImagerManhattan.CreateFromRuns[Runs]; }; <> <> <> <> <> <> <> <