<> <> DIRECTORY Basics, ImagerBasic, ImagerManhattan, ImagerPixelMaps, ImagerScanConverter, ImagerTransform, Scaled, ImagerMasks ; ImagerMasksImpl: CEDAR PROGRAM IMPORTS Basics, ImagerManhattan, ImagerPixelMaps, ImagerTransform, ImagerScanConverter, Scaled EXPORTS ImagerMasks ~ BEGIN OPEN ImagerMasks; 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]] }; FromManhattanPolygon: PUBLIC PROC [polygon: ImagerManhattan.Polygon] RETURNS [Mask] ~ { RETURN [polygon] }; 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 _ ImagerPixelMaps.Trim[pixelMap]]]; }; FromDevicePath: PUBLIC PROC [devicePath: DevicePath] RETURNS [Mask] ~ { RETURN [devicePath]; }; FromPixelArray: PUBLIC PROC [pixelArray: PixelArray, compositeTransformation: Transformation] RETURNS [Mask] ~ { IF compositeTransformation = pixelArray.m THEN RETURN [pixelArray] ELSE { copy: PixelArray _ NEW[ImagerBasic.PixelArrayRep _ pixelArray^]; copy.m _ compositeTransformation; RETURN [copy] }; }; BBList: PUBLIC 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 => RETURN [[bitmap.sOrigin+bitmap.sMin, bitmap.fOrigin+bitmap.fMin, bitmap.sSize, bitmap.fSize]]; devicePath: DevicePath => RETURN [ImagerScanConverter.BoundingBox[devicePath]]; pixelArray: PixelArray => { bb: ImagerBasic.IntRectangle _ ImagerTransform.TransformIntRectangle[ [0, 0, pixelArray.xPixels, pixelArray.yPixels], pixelArray.m ]; 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 => { RunProc: PROC [sMin, fMin: INTEGER, fSize: NAT] ~ {numberOfRuns _ numberOfRuns+1}; t1: ManhattanPolygon _ ImagerManhattan.CreateFromBox[BoundingBox[mask]]; numberOfRuns _ 0; GenerateRuns[mask, t1, RunProc, 0, 0]; ImagerManhattan.Destroy[t1]; }; }; 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]]; }; }; pixelArray: PixelArray => { m: ImagerTransform.TransformationRec _ ImagerTransform.Contents[pixelArray.m]; X: PROC [x, y: REAL] RETURNS [REAL] ~ { RETURN [m.a * x + m.b * y + m.c + sTranslate] }; Y: PROC [x, y: REAL] RETURNS [REAL] ~ { RETURN [m.d * x + m.e * y + m.f + fTranslate] }; PathMap: ImagerScanConverter.PathProc ~ { move[X[0, 0], Y[0, 0]]; line[X[0, pixelArray.yPixels], Y[0, pixelArray.yPixels]]; line[X[pixelArray.xPixels, pixelArray.yPixels], Y[pixelArray.xPixels, pixelArray.yPixels]]; line[X[pixelArray.xPixels, 0], Y[pixelArray.xPixels, 0]]; }; devicePath: DevicePath _ ImagerScanConverter.CreatePath[PathMap, BoundingBox[clipPoly]]; clipPoly _ ToManhattanPolygon[devicePath, clipPoly, 0, 0]; PixelArrayGenerateRuns[pixelArray, runProc, 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 ImagerPixelMaps.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; }; PixelArrayGenerateRuns: PROC [pixelArray: PixelArray, runProc: PROC [sMin, fMin: INTEGER, fSize: NAT], area: Mask] ~ { buffer: ImagerBasic.PixelBuffer _ NEW[ImagerBasic.PixelBufferRep[BoundingBox[area].fSize+1]]; inverseM: Transformation ~ ImagerTransform.Invert[pixelArray.m]; nextPixel: ImagerBasic.Pair _ ImagerTransform.TransformVec[[0, 1], inverseM]; xDeltaPixel: Scaled.Value _ Scaled.FromReal[nextPixel.x]; yDeltaPixel: Scaled.Value _ Scaled.FromReal[nextPixel.y]; DoRun: PROC [sMin, fMin: INTEGER, fSize: CARDINAL] ~ { start: ImagerBasic.Pair _ ImagerTransform.Transform[[0.5+sMin, 0.5+fMin], inverseM]; xStart: Scaled.Value _ Scaled.FromReal[start.x]; yStart: Scaled.Value _ Scaled.FromReal[start.y]; runStart: NAT _ 0; fRel: NAT _ 0; pixelArray.get[pixelArray, buffer, fSize, 0, xStart, yStart, xDeltaPixel, yDeltaPixel]; WHILE fRel < fSize DO buffer[fSize] _ 0; WHILE buffer[fRel] # 0 DO fRel _ fRel + 1 ENDLOOP; IF fRel > runStart THEN {runProc[sMin, fMin + runStart, fRel - runStart]}; buffer[fSize] _ 1; WHILE buffer[fRel] = 0 DO fRel _ fRel + 1 ENDLOOP; runStart _ fRel; ENDLOOP; }; GenerateRuns[area, area, DoRun, 0, 0]; }; 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 ImagerPixelMaps.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 ImagerPixelMaps.PixelMapRep] RETURNS [pixelMap: PixelMap] ~ { bb: DeviceRectangle _ BoundingBox[mask]; bb.sMin _ bb.sMin + sTranslate; bb.fMin _ bb.fMin + fTranslate; bb _ ImagerPixelMaps.Intersect[bb, BoundingBox[clipper]]; pixelMap _ ImagerPixelMaps.Reshape[scratch, 0, bb]; ImagerPixelMaps.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]; }; PixelArrayFromPixelMap: PUBLIC PROC [pixelMap: PixelMap] RETURNS [pixelArray: PixelArray] ~ { pixelArray _ NEW[ImagerBasic.PixelArrayRep]; pixelArray.xPixels _ pixelMap.sSize; pixelArray.yPixels _ pixelMap.fSize; pixelArray.samplesPerPixel _ 1; pixelArray.m _ ImagerTransform.Rotate[0]; pixelArray.data _ NEW[ImagerPixelMaps.PixelMap _ pixelMap]; SELECT pixelMap.refRep.lgBitsPerPixel FROM 0 => { pixelArray.maxSampleValue _ 1; pixelArray.get _ GetOne; }; 1 => { pixelArray.maxSampleValue _ 3; pixelArray.get _ GetTwo; }; 2 => { pixelArray.maxSampleValue _ 15; pixelArray.get _ GetFour; }; 3 => { pixelArray.maxSampleValue _ 255; pixelArray.get _ GetEight; }; 4 => { pixelArray.maxSampleValue _ LAST[CARDINAL]; pixelArray.get _ GetSixteen; }; ENDCASE => ERROR; }; GetOne: PROC [self: ImagerBasic.PixelArray, buffer: ImagerBasic.PixelBuffer, nSamples: NAT, layer: INT, xStart, yStart: Scaled.Value, xDelta, yDelta: Scaled.Value] ~ { pixelArrayRef: REF ImagerPixelMaps.PixelMap ~ NARROW[self.data]; pixelArray: ImagerPixelMaps.PixelMap ~ pixelArrayRef^; IF layer#0 THEN ERROR; FOR i: NAT IN [0..nSamples) DO WHILE yStart.Floor < 0 DO yStart _ yStart.PLUS[Scaled.FromInt[pixelArray.fSize]]; ENDLOOP; WHILE yStart.Floor >= pixelArray.fSize DO yStart _ yStart.MINUS[Scaled.FromInt[pixelArray.fSize]]; ENDLOOP; WHILE xStart.Floor < 0 DO xStart _ xStart.PLUS[Scaled.FromInt[pixelArray.sSize]]; ENDLOOP; WHILE xStart.Floor >= pixelArray.sSize DO xStart _ xStart.MINUS[Scaled.FromInt[pixelArray.sSize]]; ENDLOOP; buffer[i] _ pixelArray.GetBit[xStart.Floor, yStart.Floor]; xStart _ xStart.PLUS[xDelta]; yStart _ yStart.PLUS[yDelta]; ENDLOOP; }; GetTwo: PROC [self: ImagerBasic.PixelArray, buffer: ImagerBasic.PixelBuffer, nSamples: NAT, layer: INT, xStart, yStart: Scaled.Value, xDelta, yDelta: Scaled.Value] ~ { pixelArrayRef: REF ImagerPixelMaps.PixelMap ~ NARROW[self.data]; pixelArray: ImagerPixelMaps.PixelMap ~ pixelArrayRef^; IF layer#0 THEN ERROR; FOR i: NAT IN [0..nSamples) DO WHILE yStart.Floor < 0 DO yStart _ yStart.PLUS[Scaled.FromInt[pixelArray.fSize]]; ENDLOOP; WHILE yStart.Floor >= pixelArray.fSize DO yStart _ yStart.MINUS[Scaled.FromInt[pixelArray.fSize]]; ENDLOOP; WHILE xStart.Floor < 0 DO xStart _ xStart.PLUS[Scaled.FromInt[pixelArray.sSize]]; ENDLOOP; WHILE xStart.Floor >= pixelArray.sSize DO xStart _ xStart.MINUS[Scaled.FromInt[pixelArray.sSize]]; ENDLOOP; buffer[i] _ pixelArray.Get2Bits[xStart.Floor, yStart.Floor]; xStart _ xStart.PLUS[xDelta]; yStart _ yStart.PLUS[yDelta]; ENDLOOP; }; GetFour: PROC [self: ImagerBasic.PixelArray, buffer: ImagerBasic.PixelBuffer, nSamples: NAT, layer: INT, xStart, yStart: Scaled.Value, xDelta, yDelta: Scaled.Value] ~ { pixelArrayRef: REF ImagerPixelMaps.PixelMap ~ NARROW[self.data]; pixelArray: ImagerPixelMaps.PixelMap ~ pixelArrayRef^; IF layer#0 THEN ERROR; FOR i: NAT IN [0..nSamples) DO WHILE yStart.Floor < 0 DO yStart _ yStart.PLUS[Scaled.FromInt[pixelArray.fSize]]; ENDLOOP; WHILE yStart.Floor >= pixelArray.fSize DO yStart _ yStart.MINUS[Scaled.FromInt[pixelArray.fSize]]; ENDLOOP; WHILE xStart.Floor < 0 DO xStart _ xStart.PLUS[Scaled.FromInt[pixelArray.sSize]]; ENDLOOP; WHILE xStart.Floor >= pixelArray.sSize DO xStart _ xStart.MINUS[Scaled.FromInt[pixelArray.sSize]]; ENDLOOP; buffer[i] _ pixelArray.Get4Bits[xStart.Floor, yStart.Floor]; xStart _ xStart.PLUS[xDelta]; yStart _ yStart.PLUS[yDelta]; ENDLOOP; }; GetEight: PROC [self: ImagerBasic.PixelArray, buffer: ImagerBasic.PixelBuffer, nSamples: NAT, layer: INT, xStart, yStart: Scaled.Value, xDelta, yDelta: Scaled.Value] ~ { pixelArrayRef: REF ImagerPixelMaps.PixelMap ~ NARROW[self.data]; pixelArray: ImagerPixelMaps.PixelMap ~ pixelArrayRef^; IF layer#0 THEN ERROR; FOR i: NAT IN [0..nSamples) DO WHILE yStart.Floor < 0 DO yStart _ yStart.PLUS[Scaled.FromInt[pixelArray.fSize]]; ENDLOOP; WHILE yStart.Floor >= pixelArray.fSize DO yStart _ yStart.MINUS[Scaled.FromInt[pixelArray.fSize]]; ENDLOOP; WHILE xStart.Floor < 0 DO xStart _ xStart.PLUS[Scaled.FromInt[pixelArray.sSize]]; ENDLOOP; WHILE xStart.Floor >= pixelArray.sSize DO xStart _ xStart.MINUS[Scaled.FromInt[pixelArray.sSize]]; ENDLOOP; buffer[i] _ pixelArray.Get8Bits[xStart.Floor, yStart.Floor]; xStart _ xStart.PLUS[xDelta]; yStart _ yStart.PLUS[yDelta]; ENDLOOP; }; GetSixteen: PROC [self: ImagerBasic.PixelArray, buffer: ImagerBasic.PixelBuffer, nSamples: NAT, layer: INT, xStart, yStart: Scaled.Value, xDelta, yDelta: Scaled.Value] ~ { pixelArrayRef: REF ImagerPixelMaps.PixelMap ~ NARROW[self.data]; pixelArray: ImagerPixelMaps.PixelMap ~ pixelArrayRef^; IF layer#0 THEN ERROR; FOR i: NAT IN [0..nSamples) DO WHILE yStart.Floor < 0 DO yStart _ yStart.PLUS[Scaled.FromInt[pixelArray.fSize]]; ENDLOOP; WHILE yStart.Floor >= pixelArray.fSize DO yStart _ yStart.MINUS[Scaled.FromInt[pixelArray.fSize]]; ENDLOOP; WHILE xStart.Floor < 0 DO xStart _ xStart.PLUS[Scaled.FromInt[pixelArray.sSize]]; ENDLOOP; WHILE xStart.Floor >= pixelArray.sSize DO xStart _ xStart.MINUS[Scaled.FromInt[pixelArray.sSize]]; ENDLOOP; buffer[i] _ pixelArray.Get16Bits[xStart.Floor, yStart.Floor]; xStart _ xStart.PLUS[xDelta]; yStart _ yStart.PLUS[yDelta]; ENDLOOP; }; END. <> <> <> <> <> <> <> <> <<];>> <> <> <> <> <<];>> <> <> <> <> <<];>> <> <> <> <> <<];>> <sMinClip AND fMaxClip>fMinClip THEN {>> <> <> <> <> <> <> <> <> <> <> < fMaxClip THEN ERROR;>> <> <> <> <> <> <> <> <> <> <<};>> <> <> <> <> <> <> <> <> <<];>> <> <> <> <> <> <<};>> <<};>> <<>> <<>> <> <> < {>> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<};>> <> <> <> <> <> <> <> <> <<];>> <> <> <> <<};>> <<}>> <> <<};>> < ERROR;>> <<};>> <<>>