<> <> DIRECTORY Basics, ImagerBasic, ImagerPixelMaps, PrincOpsUtils, Real, ImagerTransform, Scaled, ImagerPixelRow; ImagerPixelRowImpl: CEDAR PROGRAM IMPORTS Basics, ImagerPixelMaps, PrincOpsUtils, Real, ImagerTransform, Scaled EXPORTS ImagerPixelRow ~ BEGIN OPEN ImagerPixelRow; DeviceRectangle: TYPE ~ ImagerPixelMaps.DeviceRectangle; IntRectangle: TYPE ~ ImagerBasic.IntRectangle; Pair: TYPE ~ ImagerBasic.Pair; PixelRowElementSize: NAT ~ SIZE[PixelRowRep[1]]-SIZE[PixelRowRep[0]]; CreatePixelRow: PUBLIC PROC [sMin, fMin: INTEGER, fSize: NAT] RETURNS [new: PixelRow] ~ { new _ NEW[PixelRowRep[fSize]]; new.sOrigin _ sMin; new.fOrigin _ fMin; }; ClearPixelRow: PUBLIC PROC [pixelRow: PixelRow] ~ TRUSTED { IF pixelRow.fSize > 0 THEN PrincOpsUtils.LongZero[@(pixelRow[0]), pixelRow.fSize*PixelRowElementSize]; }; CopyPixelRow: PUBLIC PROC [pixelRow: PixelRow, scratch: PixelRow _ NIL] RETURNS [new: PixelRow] ~ { IF scratch = NIL OR scratch.fSize # pixelRow.fSize THEN new _ NEW[PixelRowRep[pixelRow.fSize]] ELSE new _ scratch; new.sOrigin _ pixelRow.sOrigin; new.fOrigin _ pixelRow.fOrigin; IF new.fSize > 0 THEN TRUSTED { PrincOpsUtils.LongCopy[from: @(pixelRow[0]), nwords: new.fSize*PixelRowElementSize, to: @(new[0])]; }; }; AddByColumn: PUBLIC PROC [dest, source: PixelRow] ~ { fMin: INTEGER _ MAX[dest.fOrigin, source.fOrigin]; fMax: INTEGER _ MIN[dest.fOrigin+dest.fSize, source.fOrigin+source.fSize]; IF fMin < fMax THEN TRUSTED { destArr: LONG POINTER TO ARRAY [0..0) OF Pixel _ LOOPHOLE[@(dest[fMin-dest.fOrigin])]; sourceArr: LONG POINTER TO ARRAY [0..0) OF Pixel _ LOOPHOLE[@(source[fMin-source.fOrigin])]; FOR j: INTEGER IN [0..fMax-fMin) DO destArr[j] _ destArr[j] + sourceArr[j]; ENDLOOP; }; }; SubtractByColumn: PUBLIC PROC [dest, source: PixelRow] ~ { fMin: INTEGER _ MAX[dest.fOrigin, source.fOrigin]; fMax: INTEGER _ MIN[dest.fOrigin+dest.fSize, source.fOrigin+source.fSize]; IF fMin < fMax THEN TRUSTED { destArr: LONG POINTER TO ARRAY [0..0) OF Pixel _ LOOPHOLE[@(dest[fMin-dest.fOrigin])]; sourceArr: LONG POINTER TO ARRAY [0..0) OF Pixel _ LOOPHOLE[@(source[fMin-source.fOrigin])]; FOR j: INTEGER IN [0..fMax-fMin) DO destArr[j] _ destArr[j] - sourceArr[j]; ENDLOOP; }; }; LoadPixelRow: PUBLIC PROC [pixelRow: PixelRow, source: PixelMap] ~ TRUSTED { fOriginMap: INTEGER _ source.fOrigin; fOriginRow: INTEGER _ pixelRow.fOrigin; mapBB: DeviceRectangle _ source.BoundedWindow; fMin: INTEGER _ MAX[pixelRow.fOrigin, mapBB.fMin]; fMax: INTEGER _ MIN[pixelRow.fOrigin+pixelRow.fSize, mapBB.fMin+mapBB.fSize]; ClearPixelRow[pixelRow]; IF fMin < fMax AND pixelRow.sOrigin IN [source.sOrigin+source.sMin..source.sOrigin+source.sMin+source.sSize) THEN { SELECT source.refRep.lgBitsPerPixel FROM 0 => { linePtr: LONG POINTER TO PACKED ARRAY [0..0) OF [0..2) _ source.refRep.pointer + Basics.LongMult[(pixelRow.sOrigin - source.sOrigin), source.refRep.rast]; FOR f: INTEGER IN [fMin..fMax) DO pixelRow[f-fOriginRow] _ linePtr[f-fOriginMap]; ENDLOOP; }; 1 => { linePtr: LONG POINTER TO PACKED ARRAY [0..0) OF [0..4) _ source.refRep.pointer + Basics.LongMult[(pixelRow.sOrigin - source.sOrigin), source.refRep.rast]; FOR f: INTEGER IN [fMin..fMax) DO pixelRow[f-fOriginRow] _ linePtr[f-fOriginMap]; ENDLOOP; }; 2 => { linePtr: LONG POINTER TO PACKED ARRAY [0..0) OF [0..16) _ source.refRep.pointer + Basics.LongMult[(pixelRow.sOrigin - source.sOrigin), source.refRep.rast]; FOR f: INTEGER IN [fMin..fMax) DO pixelRow[f-fOriginRow] _ linePtr[f-fOriginMap]; ENDLOOP; }; 3 => { linePtr: LONG POINTER TO PACKED ARRAY [0..0) OF [0..256) _ source.refRep.pointer + Basics.LongMult[(pixelRow.sOrigin - source.sOrigin), source.refRep.rast]; FOR f: INTEGER IN [fMin..fMax) DO pixelRow[f-fOriginRow] _ linePtr[f-fOriginMap]; ENDLOOP; }; 4 => { linePtr: LONG POINTER TO PACKED ARRAY [0..0) OF CARDINAL _ source.refRep.pointer + Basics.LongMult[(pixelRow.sOrigin - source.sOrigin), source.refRep.rast]; FOR f: INTEGER IN [fMin..fMax) DO pixelRow[f-fOriginRow] _ linePtr[f-fOriginMap]; ENDLOOP; }; ENDCASE => ERROR; }; }; StorePixelRow: PUBLIC PROC [pixelRow: PixelRow, dest: PixelMap] ~ TRUSTED { fOriginMap: INTEGER _ dest.fOrigin; fOriginRow: INTEGER _ pixelRow.fOrigin; mapBB: DeviceRectangle _ dest.BoundedWindow; fMin: INTEGER _ MAX[pixelRow.fOrigin, mapBB.fMin]; fMax: INTEGER _ MIN[pixelRow.fOrigin+pixelRow.fSize, mapBB.fMin+mapBB.fSize]; IF fMin < fMax AND pixelRow.sOrigin IN [dest.sOrigin+dest.sMin..dest.sOrigin+dest.sMin+dest.sSize) THEN { SELECT dest.refRep.lgBitsPerPixel FROM 0 => { linePtr: LONG POINTER TO PACKED ARRAY [0..0) OF [0..2) _ dest.refRep.pointer + Basics.LongMult[(pixelRow.sOrigin - dest.sOrigin), dest.refRep.rast]; FOR f: INTEGER IN [fMin..fMax) DO linePtr[f-fOriginMap] _ MIN[pixelRow[f-fOriginRow], 1]; ENDLOOP; }; 1 => { linePtr: LONG POINTER TO PACKED ARRAY [0..0) OF [0..4) _ dest.refRep.pointer + Basics.LongMult[(pixelRow.sOrigin - dest.sOrigin), dest.refRep.rast]; FOR f: INTEGER IN [fMin..fMax) DO linePtr[f-fOriginMap] _ MIN[pixelRow[f-fOriginRow], 3]; ENDLOOP; }; 2 => { linePtr: LONG POINTER TO PACKED ARRAY [0..0) OF [0..16) _ dest.refRep.pointer + Basics.LongMult[(pixelRow.sOrigin - dest.sOrigin), dest.refRep.rast]; FOR f: INTEGER IN [fMin..fMax) DO linePtr[f-fOriginMap] _ MIN[pixelRow[f-fOriginRow], 15]; ENDLOOP; }; 3 => { linePtr: LONG POINTER TO PACKED ARRAY [0..0) OF [0..256) _ dest.refRep.pointer + Basics.LongMult[(pixelRow.sOrigin - dest.sOrigin), dest.refRep.rast]; FOR f: INTEGER IN [fMin..fMax) DO linePtr[f-fOriginMap] _ MIN[pixelRow[f-fOriginRow], 255]; ENDLOOP; }; 4 => { linePtr: LONG POINTER TO PACKED ARRAY [0..0) OF CARDINAL _ dest.refRep.pointer + Basics.LongMult[(pixelRow.sOrigin - dest.sOrigin), dest.refRep.rast]; FOR f: INTEGER IN [fMin..fMax) DO linePtr[f-fOriginMap] _ pixelRow[f-fOriginRow]; ENDLOOP; }; ENDCASE => ERROR; }; }; 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 _ ImagerTransform.TransformIntRectangle[[sr.sMin, sr.fMin, sr.sSize, sr.fSize], transformation]; destRect: DeviceRectangle _ dest.BoundedWindow; dr: DeviceRectangle _ IF tile THEN destRect ELSE ImagerPixelMaps.Intersect[destRect, [db.x, db.y, db.w, db.h]]; pixelRow: PixelRow _ CreatePixelRow[dr.sMin, dr.fMin, dr.fSize]; deltaPixel: Pair ~ ImagerTransform.InverseTransformVec[[0, 1], transformation]; sDelta: Scaled.Value ~ Scaled.FromReal[deltaPixel.x]; fDelta: Scaled.Value ~ Scaled.FromReal[deltaPixel.y]; deltaLine: Pair ~ ImagerTransform.InverseTransformVec[[1, 0], transformation]; sDeltaLine: Scaled.Value ~ Scaled.FromReal[deltaLine.x]; fDeltaLine: Scaled.Value ~ Scaled.FromReal[deltaLine.y]; sourceOrigin: Pair ~ ImagerTransform.InverseTransform[[dr.sMin+0.5, dr.fMin+0.5], transformation]; 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..pixelRow.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 { pixelRow[j] _ Basics.BITSHIFT[source.GetPixel[s.Floor, f.Floor]*multiplier, lgScale]; }; s _ s.PLUS[sDelta]; f _ f.PLUS[fDelta]; ENDLOOP; }; THROUGH [0..dr.sSize) DO LoadPixelRow[pixelRow, dest]; GetSamples[]; StorePixelRow[pixelRow, dest]; pixelRow.sOrigin _ pixelRow.sOrigin + 1; sSource _ sSource.PLUS[sDeltaLine]; fSource _ fSource.PLUS[fDeltaLine]; ENDLOOP; }; UnderSample: PUBLIC PROC [pixelMap: PixelMap, transformation: Transformation, tile: BOOLEAN _ FALSE, background: CARDINAL _ 0, scratch: REF ImagerPixelMaps.PixelMapRep _ NIL] RETURNS [PixelMap] ~ { sr: DeviceRectangle _ pixelMap.Window; db: IntRectangle _ ImagerTransform.TransformIntRectangle[[sr.sMin, sr.fMin, sr.sSize, sr.fSize], transformation]; dr: DeviceRectangle _ [db.x, db.y, db.w, db.h]; new: PixelMap _ ImagerPixelMaps.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 ERROR -- box too big 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..32) OF PixelRow; nPixels: CARDINAL _ sSizeBox*fSizeBox; sOrigin: INTEGER _ sStart-sSizeBox; fOrigin: INTEGER ~ fStart-fSizeBox; result: PixelRow _ CreatePixelRow[sOrigin, fStart, pixelMap.fSize]; MoveToNextRow: PROC ~ { t: PixelRow _ sum[0]; FOR i: NAT IN [0..sSizeBox) DO sum[i] _ sum[i+1]; ENDLOOP; sum[sSizeBox] _ t; sOrigin _ sOrigin + 1; t.sOrigin _ sOrigin + sSizeBox; LoadPixelRow[t, pixelMap]; FOR i: NAT IN [1..t.fSize) DO t[i] _ t[i] + t[i-1] ENDLOOP; AddByColumn[t, sum[sSizeBox-1]]; }; FOR i: NAT IN [0..sSizeBox] DO sum[i] _ CreatePixelRow[sOrigin+i, fOrigin, pixelMap.fSize+2*fSizeBox]; ClearPixelRow[sum[i]]; ENDLOOP; FOR s: INTEGER IN [sStart..sEnd) DO WHILE sum[sHalf+1].sOrigin # s DO MoveToNextRow[] ENDLOOP; result.sOrigin _ s; 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; StorePixelRow[result, pixelMap]; ENDLOOP; }; }; ChangeBitsPerPixel: PUBLIC PROC [pixelMap: PixelMap, newLgBitsPerPixel: [0..4], scratch: REF ImagerPixelMaps.PixelMapRep _ NIL] RETURNS [PixelMap] ~ { bounds: DeviceRectangle _ pixelMap.Window; new: PixelMap _ ImagerPixelMaps.Reshape[scratch, newLgBitsPerPixel, bounds]; pixelRow: PixelRow _ CreatePixelRow[0, bounds.fMin, bounds.fSize]; FOR s: INTEGER IN [bounds.sMin..bounds.sMin+bounds.sSize) DO pixelRow.sOrigin _ s; LoadPixelRow[pixelRow, pixelMap]; StorePixelRow[pixelRow, new]; ENDLOOP; RETURN [new] }; Renormalize: PUBLIC PROC [pixelMap: PixelMap, oldmin, oldmax, newmin, newmax: REAL] ~ { bounds: DeviceRectangle _ pixelMap.Window; pixelRow: PixelRow _ CreatePixelRow[0, bounds.fMin, bounds.fSize]; m: REAL _ (newmax-newmin)/(oldmax-oldmin); FOR s: INTEGER IN [bounds.sMin..bounds.sMin+bounds.sSize) DO pixelRow.sOrigin _ s; LoadPixelRow[pixelRow, pixelMap]; FOR j: NAT IN [0..bounds.fSize) DO pix: REAL _ pixelRow[j]; out: REAL _ (pix-oldmin)*m+newmin; pixelRow[j] _ MAX[MIN[Real.RoundLI[out], CARDINAL.LAST], 0]; ENDLOOP; StorePixelRow[pixelRow, pixelMap]; ENDLOOP; }; END.