ImagerPixelRowImpl.mesa
Copyright © 1984, 1985 by Xerox Corporation. All rights reserved.
Michael Plass, August 6, 1984 9:07:49 am PDT
Doug Wyatt, May 3, 1985 5:25:52 pm PDT
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: 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];
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: INTEGERMAX[pixelRow.fOrigin, mapBB.fMin];
fMax: INTEGERMIN[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<xMax DO x1 ← x1+1 ENDLOOP;
WHILE y1<yMax DO y1 ← y1+1 ENDLOOP;
RETURN [[x0, y0, x1-x0, y1-y0]]
};
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 ← TransformIntRectangle[transformation, [sr.sMin, sr.fMin, sr.sSize, sr.fSize]];
destRect: DeviceRectangle ← dest.BoundedWindow;
dr: DeviceRectangle ← IF tile THEN destRect ELSE ImagerPixelMap.Intersect[destRect, [db.x, db.y, db.w, db.h]];
pixelRow: PixelRow ← CreatePixelRow[dr.sMin, dr.fMin, dr.fSize];
deltaPixel: VEC ~ transformation.InverseTransformVec[[0, 1]];
sDelta: Scaled.Value ~ Scaled.FromReal[deltaPixel.x];
fDelta: Scaled.Value ~ Scaled.FromReal[deltaPixel.y];
deltaLine: VEC ~ transformation.InverseTransformVec[[1, 0]];
sDeltaLine: Scaled.Value ~ Scaled.FromReal[deltaLine.x];
fDeltaLine: Scaled.Value ~ Scaled.FromReal[deltaLine.y];
sourceOrigin: VEC ~ transformation.InverseTransform[[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..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 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.