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.