<> <> <> <<>> DIRECTORY Basics, Vector2, ImagerPixelMap, PrincOps, PrincOpsUtils, Real, ImagerTransformation, Scaled, ImagerPixelSeq, GreenBay; ImagerPixelSeqImpl: CEDAR MONITOR IMPORTS Basics, ImagerPixelMap, PrincOpsUtils, Real, ImagerTransformation, Scaled, GreenBay EXPORTS ImagerPixelSeq ~ BEGIN OPEN ImagerPixelSeq; DeviceRectangle: TYPE ~ ImagerPixelMap.DeviceRectangle; IntRectangle: TYPE ~ RECORD [x, y, w, h: INT]; TransformIntRectangle: PROC [in: IntRectangle, m: ImagerTransformation.Transformation] RETURNS [IntRectangle] ~ { r: ImagerTransformation.Rectangle ~ ImagerTransformation.TransformRectangle[m: m, r: [in.x, in.y, in.w, in.h]]; RETURN [[Real.Round[r.x], Real.Round[r.y], Real.Round[r.w], Real.Round[r.h]]] }; Pair: TYPE ~ Vector2.VEC; bitsPerWord: NAT ~ Basics.bitsPerWord; pixelSeqElementSize: NAT ~ SIZE[PixelSeqRep[1]]-SIZE[PixelSeqRep[0]]; Create: PUBLIC PROC [maxSize: NAT] RETURNS [new: PixelSeq] ~ { new _ NEW[PixelSeqRep[maxSize]]; }; nScratchSlots: NAT ~ 2; nScratchAvail: NAT _ 0; scratch: ARRAY [0..nScratchSlots) OF PixelSeq; rover: NAT _ 0; ObtainScratch: PUBLIC ENTRY PROC [maxSize: NAT] RETURNS [new: PixelSeq] ~ { ENABLE UNWIND => NULL; FOR i: NAT DECREASING IN [0..nScratchAvail) DO IF scratch[i].maxSize >= maxSize THEN { new _ scratch[i]; IF i # nScratchAvail-1 THEN scratch[i] _ scratch[nScratchAvail-1]; nScratchAvail _ nScratchAvail - 1; scratch[nScratchAvail] _ NIL; EXIT; }; ENDLOOP; IF new = NIL THEN new _ NEW[PixelSeqRep[maxSize]]; }; ReleaseScratch: PUBLIC ENTRY PROC [pixelSeq: PixelSeq] ~ { IF nScratchAvail < nScratchSlots THEN { scratch[nScratchAvail] _ pixelSeq; nScratchAvail _ nScratchAvail + 1; } ELSE { scratch[rover] _ pixelSeq; rover _ (rover + 1) MOD nScratchSlots; }; }; Clear: PUBLIC PROC [pixelSeq: PixelSeq, size: NAT] ~ TRUSTED { size _ MIN[size, pixelSeq.maxSize]; IF size > 0 THEN PrincOpsUtils.LongZero[@(pixelSeq[0]), size*pixelSeqElementSize]; }; Copy: PUBLIC PROC [pixelSeq: PixelSeq, size: NAT, scratch: PixelSeq _ NIL] RETURNS [new: PixelSeq] ~ { size _ MIN[size, pixelSeq.maxSize]; new _ IF scratch = NIL OR scratch.maxSize < size THEN NEW[PixelSeqRep[size]] ELSE scratch; IF size > 0 THEN TRUSTED { PrincOpsUtils.LongCopy[from: @(pixelSeq[0]), nwords: size*pixelSeqElementSize, to: @(new[0])]; }; }; Add: PUBLIC PROC [dest, source: PixelSeq, size: NAT] ~ { fMin: INTEGER _ 0; fMax: INTEGER _ size; IF fMin < fMax THEN TRUSTED { destArr: LONG POINTER TO RECORD[SEQUENCE COMPUTED CARDINAL OF Pixel] _ LOOPHOLE[@(dest[fMin])]; sourceArr: LONG POINTER TO RECORD[SEQUENCE COMPUTED CARDINAL OF Pixel] _ LOOPHOLE[@(source[fMin])]; lengthMinusOne: NAT _ fMax-fMin-1; dest[fMax-1] _ destArr[lengthMinusOne] + source[fMax-1]; <> FOR j: NAT IN [0..lengthMinusOne) DO destArr[j] _ destArr[j] + sourceArr[j]; ENDLOOP; }; }; Subtract: PUBLIC PROC [dest, source: PixelSeq, size: NAT] ~ { fMin: INTEGER _ 0; fMax: INTEGER _ size; IF fMin < fMax THEN TRUSTED { destArr: LONG POINTER TO RECORD[SEQUENCE COMPUTED CARDINAL OF Pixel] _ LOOPHOLE[@(dest[fMin])]; sourceArr: LONG POINTER TO RECORD[SEQUENCE COMPUTED CARDINAL OF Pixel] _ LOOPHOLE[@(source[fMin])]; lengthMinusOne: NAT _ fMax-fMin-1; dest[fMax-1] _ destArr[lengthMinusOne] - source[fMax-1]; <> FOR j: NAT IN [0..lengthMinusOne) DO destArr[j] _ destArr[j] - sourceArr[j]; ENDLOOP; }; }; Apply: PUBLIC PROC [dest, source: PixelSeq, size: NAT, table: PixelSeq] ~ { IF size > 0 THEN TRUSTED { destArr: LONG POINTER TO RECORD[SEQUENCE COMPUTED CARDINAL OF Pixel] _ LOOPHOLE[@(dest[0])]; sourceArr: LONG POINTER TO RECORD[SEQUENCE COMPUTED CARDINAL OF Pixel] _ LOOPHOLE[@(source[0])]; lengthMinusOne: NAT _ size-1; dest[lengthMinusOne] _ table[source[lengthMinusOne]]; <> FOR j: NAT IN [0..lengthMinusOne) DO destArr[j] _ table[sourceArr[j]]; ENDLOOP; }; }; ApplyAndAdd: PUBLIC PROC [dest, source: PixelSeq, size: NAT, table: PixelSeq] ~ { IF size > 0 THEN TRUSTED { destArr: LONG POINTER TO RECORD[SEQUENCE COMPUTED CARDINAL OF Pixel] _ LOOPHOLE[@(dest[0])]; sourceArr: LONG POINTER TO RECORD[SEQUENCE COMPUTED CARDINAL OF Pixel] _ LOOPHOLE[@(source[0])]; lengthMinusOne: NAT _ size-1; dest[lengthMinusOne] _ destArr[lengthMinusOne] + table[source[lengthMinusOne]]; <> FOR j: NAT IN [0..lengthMinusOne) DO destArr[j] _ destArr[j] + table[sourceArr[j]]; ENDLOOP; }; }; LoadF: PUBLIC PROC [pixelSeq: PixelSeq, s, f: INTEGER, size: NAT, source: PixelMap] ~ TRUSTED { fOriginMap: INTEGER _ source.fOrigin; fOriginRow: INTEGER _ f; fSizeRow: INTEGER _ MIN[size, pixelSeq.maxSize]; mapBB: DeviceRectangle _ source.BoundedWindow; fMin: INTEGER _ MAX[fOriginRow, mapBB.fMin]; fMax: INTEGER _ MIN[fOriginRow+fSizeRow, mapBB.fMin+mapBB.fSize]; IF fMin >= fMax OR s NOT IN [mapBB.sMin..mapBB.sMin+mapBB.sSize) THEN {Clear[pixelSeq, size]; RETURN}; IF fMin-fOriginRow > 0 THEN PrincOpsUtils.LongZero[@(pixelSeq[0]), (fMin-fOriginRow)*pixelSeqElementSize]; IF fMax-fOriginRow < fSizeRow THEN PrincOpsUtils.LongZero[@(pixelSeq[fMax-fOriginRow]), (fSizeRow-fMax+fOriginRow)*pixelSeqElementSize]; GreenBay.UnPack[ wordPointer: @(pixelSeq[fMin-fOriginRow]), bitsPerElement: Basics.BITSHIFT[1, source.refRep.lgBitsPerPixel], base: source.refRep.pointer + Basics.LongMult[(s - source.sOrigin), source.refRep.rast], start: fMin-fOriginMap, count: fMax-fMin ]; }; LoadS: PUBLIC PROC [pixelSeq: PixelSeq, s, f: INTEGER, size: NAT, source: PixelMap] ~ TRUSTED { sOriginMap: INTEGER _ source.sOrigin; seqOrigin: INTEGER _ s; seqSize: INTEGER _ MIN[size, pixelSeq.maxSize]; mapBB: DeviceRectangle _ source.BoundedWindow; sMin: INTEGER _ MAX[seqOrigin, mapBB.sMin]; sMax: INTEGER _ MIN[seqOrigin+seqSize, mapBB.sMin+mapBB.sSize]; bbTableSpace: PrincOps.BBTableSpace; bb: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace]; bitsPerElement: CARDINAL ~ Basics.BITSHIFT[1, source.refRep.lgBitsPerPixel]; bit: CARDINAL ~ Basics.BITSHIFT[NAT[f-source.fOrigin], source.refRep.lgBitsPerPixel]; Clear[pixelSeq, size]; IF sMin >= sMax OR f NOT IN [mapBB.fMin..mapBB.fMin+mapBB.fSize) THEN RETURN; bb^ _ [ dst: [word: @(pixelSeq[sMin-seqOrigin]), bit: bitsPerWord-bitsPerElement], dstBpl: bitsPerWord, src: [word: source.refRep.pointer + Basics.LongMult[(sMin - source.sOrigin), source.refRep.rast] + bit/bitsPerWord, bit: bit MOD bitsPerWord], srcDesc: [srcBpl[source.refRep.rast*bitsPerWord]], width: bitsPerElement, height: sMax-sMin, flags: [] ]; PrincOpsUtils.BITBLT[bb]; }; StoreF: PUBLIC PROC [pixelSeq: PixelSeq, s, f: INTEGER, size: NAT, dest: PixelMap] ~ TRUSTED { fOriginMap: INTEGER _ dest.fOrigin; fOriginRow: INTEGER _ f; fSizeRow: INTEGER _ MIN[size, pixelSeq.maxSize]; mapBB: DeviceRectangle _ dest.BoundedWindow; fMin: INTEGER _ MAX[fOriginRow, mapBB.fMin]; fMax: INTEGER _ MIN[fOriginRow+fSizeRow, mapBB.fMin+mapBB.fSize]; IF fMin >= fMax OR s NOT IN [mapBB.sMin..mapBB.sMin+mapBB.sSize) THEN RETURN; GreenBay.Pack[ wordPointer: @(pixelSeq[fMin-fOriginRow]), bitsPerElement: Basics.BITSHIFT[1, dest.refRep.lgBitsPerPixel], base: dest.refRep.pointer + Basics.LongMult[(s - dest.sOrigin), dest.refRep.rast], start: fMin-fOriginMap, count: fMax-fMin ]; }; StoreS: PUBLIC PROC [pixelSeq: PixelSeq, s, f: INTEGER, size: NAT, dest: PixelMap] ~ TRUSTED { sOriginMap: INTEGER _ dest.sOrigin; seqOrigin: INTEGER _ s; seqSize: INTEGER _ MIN[size, pixelSeq.maxSize]; mapBB: DeviceRectangle _ dest.BoundedWindow; sMin: INTEGER _ MAX[seqOrigin, mapBB.sMin]; sMax: INTEGER _ MIN[seqOrigin+seqSize, mapBB.sMin+mapBB.sSize]; bbTableSpace: PrincOps.BBTableSpace; bb: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace]; bitsPerElement: CARDINAL ~ Basics.BITSHIFT[1, dest.refRep.lgBitsPerPixel]; bit: CARDINAL ~ Basics.BITSHIFT[NAT[f-dest.fOrigin], dest.refRep.lgBitsPerPixel]; IF sMin >= sMax OR f NOT IN [mapBB.fMin..mapBB.fMin+mapBB.fSize) THEN RETURN; bb^ _ [ dst: [word: dest.refRep.pointer + Basics.LongMult[(sMin - dest.sOrigin), dest.refRep.rast] + bit/bitsPerWord, bit: bit MOD bitsPerWord], dstBpl: dest.refRep.rast*bitsPerWord, src: [word: @(pixelSeq[sMin-seqOrigin]), bit: bitsPerWord-bitsPerElement], srcDesc: [srcBpl[bitsPerWord]], width: bitsPerElement, height: sMax-sMin, flags: [] ]; PrincOpsUtils.BITBLT[bb]; }; TransferSamples: PUBLIC PROC [dest, source: PixelMap, transformation: Transformation, tile: BOOLEAN _ FALSE, multiplier: CARDINAL _ 1, lgScale: INTEGER _ 0] ~ { sr: DeviceRectangle _ source.Window; sb: DeviceRectangle _ source.BoundedWindow; db: IntRectangle _ TransformIntRectangle[[sr.sMin, sr.fMin, sr.sSize, sr.fSize], transformation]; destRect: DeviceRectangle _ dest.BoundedWindow; dr: DeviceRectangle _ IF tile THEN destRect ELSE ImagerPixelMap.Intersect[destRect, [db.x, db.y, db.w, db.h]]; pixelSeq: PixelSeq _ ObtainScratch[dr.fSize]; deltaPixel: Pair ~ ImagerTransformation.InverseTransformVec[transformation, [0, 1]]; sDelta: Scaled.Value ~ Scaled.FromReal[deltaPixel.x]; fDelta: Scaled.Value ~ Scaled.FromReal[deltaPixel.y]; deltaLine: Pair ~ ImagerTransformation.InverseTransformVec[transformation, [1, 0]]; sDeltaLine: Scaled.Value ~ Scaled.FromReal[deltaLine.x]; fDeltaLine: Scaled.Value ~ Scaled.FromReal[deltaLine.y]; sourceOrigin: Pair ~ ImagerTransformation.InverseTransform[transformation, [dr.sMin+0.5, dr.fMin+0.5]]; sSource: Scaled.Value _ Scaled.FromReal[sourceOrigin.x]; fSource: Scaled.Value _ Scaled.FromReal[sourceOrigin.y]; GetSamples: PROC ~ { sMax: INTEGER _ sb.sMin+sb.sSize; fMax: INTEGER _ sb.fMin+sb.fSize; s: Scaled.Value _ sSource; f: Scaled.Value _ fSource; FOR j: NAT IN [0..dr.fSize) DO IF tile THEN { WHILE s.Floor < sr.sMin DO s _ s.PLUS[Scaled.FromInt[sr.sSize]] ENDLOOP; WHILE s.Floor >= sr.sMin+sr.sSize DO s _ s.MINUS[Scaled.FromInt[sr.sSize]] ENDLOOP; WHILE f.Floor < sr.fMin DO f _ f.PLUS[Scaled.FromInt[sr.fSize]] ENDLOOP; WHILE f.Floor >= sr.fMin+sr.fSize DO f _ f.MINUS[Scaled.FromInt[sr.fSize]] ENDLOOP; }; IF s.Floor IN [sb.sMin..sMax) AND f.Floor IN [sb.fMin..fMax) THEN { pixelSeq[j] _ Basics.BITSHIFT[source.GetPixel[s.Floor, f.Floor]*multiplier, lgScale]; }; s _ s.PLUS[sDelta]; f _ f.PLUS[fDelta]; ENDLOOP; }; FOR s: INTEGER IN [dr.sMin..dr.sMin+dr.sSize) DO LoadF[pixelSeq, s, dr.fMin, dr.fSize, dest]; GetSamples[]; StoreF[pixelSeq, s, dr.fMin, dr.fSize, dest]; sSource _ sSource.PLUS[sDeltaLine]; fSource _ fSource.PLUS[fDeltaLine]; ENDLOOP; ReleaseScratch[pixelSeq]; }; UnderSample: PUBLIC PROC [pixelMap: PixelMap, transformation: Transformation, tile: BOOLEAN _ FALSE, background: CARDINAL _ 0, scratch: REF ImagerPixelMap.PixelMapRep _ NIL] RETURNS [PixelMap] ~ { sr: DeviceRectangle _ pixelMap.Window; db: IntRectangle _ TransformIntRectangle[[sr.sMin, sr.fMin, sr.sSize, sr.fSize], transformation]; dr: DeviceRectangle _ [db.x, db.y, db.w, db.h]; new: PixelMap _ ImagerPixelMap.Reshape[scratch, pixelMap.refRep.lgBitsPerPixel, dr]; new.Fill[dr, background]; TransferSamples[new, pixelMap, transformation, tile]; RETURN [new] }; BoxTooBig: PUBLIC ERROR ~ CODE; BoxFilter: PUBLIC PROC [pixelMap: PixelMap, sSizeBox, fSizeBox: NAT] ~ { IF LONG[sSizeBox]*fSizeBox*255 > CARDINAL.LAST THEN { BoxFilter[pixelMap, sSizeBox, 1]; BoxFilter[pixelMap, 1, fSizeBox]; } ELSE { sHalf: NAT ~ sSizeBox/2; fHalf: NAT ~ (fSizeBox+1)/2; sStart: INTEGER ~ pixelMap.sOrigin+pixelMap.sMin; sEnd: INTEGER ~ sStart + pixelMap.sSize; fStart: INTEGER ~ pixelMap.fOrigin+pixelMap.fMin; fEnd: INTEGER ~ fStart+pixelMap.fSize; sum: ARRAY [0..256) OF PixelSeq; nPixels: CARDINAL _ sSizeBox*fSizeBox; sOrigin: INTEGER _ sStart-2*sSizeBox+sHalf; fOrigin: INTEGER ~ fStart-fSizeBox; result: PixelSeq _ ObtainScratch[pixelMap.fSize]; paddedSize: NAT _ pixelMap.fSize+2*fSizeBox; MoveToNextRow: PROC ~ { t: PixelSeq _ sum[0]; p: Pixel; FOR i: NAT IN [0..sSizeBox) DO sum[i] _ sum[i+1]; ENDLOOP; sum[sSizeBox] _ t; sOrigin _ sOrigin + 1; LoadF[ pixelSeq: t, s: MAX[MIN[sOrigin + sSizeBox, sEnd-1], sStart], f: fOrigin, size: paddedSize, source: pixelMap ]; p _ t[fSizeBox]; FOR i: NAT IN [0..fSizeBox) DO t[i] _ p; ENDLOOP; p _ t[paddedSize-fSizeBox-1]; FOR i: NAT IN [paddedSize-fSizeBox..paddedSize) DO t[i] _ p; ENDLOOP; FOR i: NAT IN [1..paddedSize) DO t[i] _ t[i] + t[i-1] ENDLOOP; Add[t, sum[sSizeBox-1], paddedSize]; }; FOR i: NAT IN [0..sSizeBox] DO sum[i] _ Create[paddedSize]; ENDLOOP; FOR s: INTEGER IN [sStart..sEnd) DO WHILE sOrigin+sHalf+1 # s DO MoveToNextRow[] ENDLOOP; FOR f: INTEGER IN [fStart..fEnd) DO boxSum: Pixel _ sum[sSizeBox][f-fHalf+fSizeBox-fOrigin] - sum[sSizeBox][f-fHalf-fOrigin] - sum[0][f-fHalf+fSizeBox-fOrigin] + sum[0][f-fHalf-fOrigin]; result[f-fStart] _ boxSum/nPixels; ENDLOOP; StoreF[result, s, fStart, pixelMap.fSize, pixelMap]; ENDLOOP; ReleaseScratch[result]; }; }; ChangeBitsPerPixel: PUBLIC PROC [pixelMap: PixelMap, newLgBitsPerPixel: [0..4], scratch: REF ImagerPixelMap.PixelMapRep _ NIL] RETURNS [PixelMap] ~ { bounds: DeviceRectangle _ pixelMap.Window; new: PixelMap _ ImagerPixelMap.Reshape[scratch, newLgBitsPerPixel, bounds]; pixelSeq: PixelSeq _ ObtainScratch[bounds.fSize]; FOR s: INTEGER IN [bounds.sMin..bounds.sMin+bounds.sSize) DO LoadF[pixelSeq, s, bounds.fMin, bounds.fSize, pixelMap]; StoreF[pixelSeq, s, bounds.fMin, bounds.fSize, new]; ENDLOOP; ReleaseScratch[pixelSeq]; RETURN [new] }; Renormalize: PUBLIC PROC [pixelMap: PixelMap, oldmin, oldmax, newmin, newmax: REAL] ~ { bounds: DeviceRectangle _ pixelMap.Window; pixelSeq: PixelSeq _ ObtainScratch[bounds.fSize]; m: REAL _ (newmax-newmin)/(oldmax-oldmin); FOR s: INTEGER IN [bounds.sMin..bounds.sMin+bounds.sSize) DO LoadF[pixelSeq, s, bounds.fMin, bounds.fSize, pixelMap]; FOR j: NAT IN [0..bounds.fSize) DO pix: REAL _ pixelSeq[j]; out: REAL _ (pix-oldmin)*m+newmin; pixelSeq[j] _ MAX[MIN[Real.RoundLI[out], CARDINAL.LAST], 0]; ENDLOOP; StoreF[pixelSeq, s, bounds.fMin, bounds.fSize, pixelMap]; ENDLOOP; ReleaseScratch[pixelSeq]; }; END.