<> <> <> <> DIRECTORY Basics USING [BITSHIFT, bitsPerWord, LongMult], ImagerPixelMap USING [BoundedWindow, DeviceRectangle, Fill, GetPixel, Intersect, PixelMap, PixelMapRep, Reshape, Window], ImagerPixelRow USING [Pixel, PixelRow, PixelRowRep], ImagerTransformation USING [InverseTransform, InverseTransformVec, Rectangle, Transformation, TransformRectangle], PrincOpsUtils USING [LongCopy, LongZero], Real USING [Round], Scaled USING [Floor, FromInt, FromReal, MINUS, PLUS, Value], Vector2 USING [VEC]; ImagerPixelRowImpl: CEDAR PROGRAM IMPORTS Basics, ImagerPixelMap, PrincOpsUtils, Real, ImagerTransformation, Scaled EXPORTS ImagerPixelRow ~ BEGIN OPEN ImagerPixelRow; VEC: TYPE ~ Vector2.VEC; DeviceRectangle: TYPE ~ ImagerPixelMap.DeviceRectangle; Transformation: TYPE ~ ImagerTransformation.Transformation; PixelMap: TYPE ~ ImagerPixelMap.PixelMap; 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; new.fSize _ fSize; }; 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.maxSize < pixelRow.fSize THEN new _ NEW[PixelRowRep[pixelRow.fSize]] ELSE new _ scratch; new.sOrigin _ pixelRow.sOrigin; new.fOrigin _ pixelRow.fOrigin; new.fSize _ pixelRow.fSize; 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]; IF fMin >= fMax THEN {ClearPixelRow[pixelRow]; RETURN}; IF fMin > 0 THEN PrincOpsUtils.LongZero[@(pixelRow[0]), fMin*PixelRowElementSize]; IF fMax < pixelRow.fSize THEN PrincOpsUtils.LongZero[@(pixelRow[fMax]), (pixelRow.fSize-fMax)*PixelRowElementSize]; IF pixelRow.sOrigin IN [mapBB.sMin..mapBB.sMin+mapBB.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 => IF Basics.bitsPerWord = 16 THEN { from: LONG POINTER _ source.refRep.pointer + Basics.LongMult[(pixelRow.sOrigin - source.sOrigin), source.refRep.rast] + (fMin-fOriginMap); PrincOpsUtils.LongCopy[from: from, nwords: (fMax-fMin)*PixelRowElementSize, to: @(pixelRow[fMin-fOriginRow])]; } ELSE { 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 [mapBB.sMin..mapBB.sMin+mapBB.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 => IF Basics.bitsPerWord = 16 THEN { to: LONG POINTER _ dest.refRep.pointer + Basics.LongMult[(pixelRow.sOrigin - dest.sOrigin), dest.refRep.rast] + (fMin-fOriginMap); PrincOpsUtils.LongCopy[from: @(pixelRow[fMin-fOriginRow]), nwords: (fMax-fMin)*PixelRowElementSize, to: to]; } ELSE { 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; }; }; Rectangle: TYPE ~ ImagerTransformation.Rectangle; IntRectangle: TYPE ~ RECORD [x, y, w, h: INTEGER]; TransformIntRectangle: PROC [m: Transformation, rect: Rectangle] RETURNS [IntRectangle] ~ { new: Rectangle ~ m.TransformRectangle[rect]; xMax: REAL _ new.x+new.w; yMax: REAL _ new.y+new.h; x0: INT _ Real.Round[new.x]; y0: INT _ Real.Round[new.y]; x1: INT _ Real.Round[xMax]; y1: INT _ Real.Round[yMax]; WHILE x0>new.x DO x0 _ x0-1 ENDLOOP; WHILE y0>new.y DO y0 _ y0-1 ENDLOOP; WHILE x1= 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 ImagerPixelMap.PixelMapRep _ NIL] RETURNS [PixelMap] ~ { sr: DeviceRectangle _ pixelMap.Window; db: IntRectangle _ TransformIntRectangle[transformation, [sr.sMin, sr.fMin, sr.sSize, sr.fSize]]; 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 ERROR BoxTooBig 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-2*sSizeBox+sHalf; fOrigin: INTEGER ~ fStart-fSizeBox; result: PixelRow _ CreatePixelRow[sStart, fStart, pixelMap.fSize]; MoveToNextRow: PROC ~ { t: PixelRow _ sum[0]; p: Pixel; FOR i: NAT IN [0..sSizeBox) DO sum[i] _ sum[i+1]; ENDLOOP; sum[sSizeBox] _ t; sOrigin _ sOrigin + 1; t.sOrigin _ MAX[MIN[sOrigin + sSizeBox, sEnd-1], sStart]; LoadPixelRow[t, pixelMap]; p _ t[fSizeBox]; FOR i: NAT IN [0..fSizeBox) DO t[i] _ p; ENDLOOP; p _ t[t.fSize-fSizeBox-1]; FOR i: NAT IN [t.fSize-fSizeBox..t.fSize) DO t[i] _ p; ENDLOOP; t.sOrigin _ sOrigin + sSizeBox; 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 ImagerPixelMap.PixelMapRep _ NIL] RETURNS [PixelMap] ~ { bounds: DeviceRectangle _ pixelMap.Window; new: PixelMap _ ImagerPixelMap.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.Round[out], CARDINAL.LAST], 0]; ENDLOOP; StorePixelRow[pixelRow, pixelMap]; ENDLOOP; }; END.