ImagerPixelRowImpl.mesa
Michael Plass, June 18, 1984 11:59:21 am PDT
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: INTEGERMAX[dest.fOrigin, source.fOrigin];
fMax: INTEGERMIN[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: INTEGERMAX[dest.fOrigin, source.fOrigin];
fMax: INTEGERMIN[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: INTEGERMAX[pixelRow.fOrigin, mapBB.fMin];
fMax: INTEGERMIN[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: INTEGERMAX[pixelRow.fOrigin, mapBB.fMin];
fMax: INTEGERMIN[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: BOOLEANFALSE, 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: BOOLEANFALSE, 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.