ImagerPixelSeqImpl.mesa
Copyright (C) 1984, Xerox Corporation. All rights reserved.
Michael Plass, October 18, 1985 12:07:55 pm PDT
DIRECTORY Basics, Vector2, ImagerPixelMap, PrincOps, PrincOpsUtils, Real, ImagerTransformation, Scaled, ImagerPixelSeq, GreenBay;
ImagerPixelSeqImpl: CEDAR MONITOR
IMPORTS Basics, ImagerPixelMap, PrincOpsUtils, Real, ImagerTransformation, Scaled, GreenBay
EXPORTS ImagerPixelSeq
~ BEGIN OPEN ImagerPixelSeq;
DeviceRectangle: TYPE ~ ImagerPixelMap.DeviceRectangle;
IntRectangle: TYPE ~ RECORD [x, y, w, h: INT];
TransformIntRectangle: PROC [in: IntRectangle, m: ImagerTransformation.Transformation] RETURNS [IntRectangle] ~ {
r: ImagerTransformation.Rectangle ~ ImagerTransformation.TransformRectangle[m: m, r: [in.x, in.y, in.w, in.h]];
RETURN [[Real.Round[r.x], Real.Round[r.y], Real.Round[r.w], Real.Round[r.h]]]
};
Pair: TYPE ~ Vector2.VEC;
bitsPerWord: NAT ~ Basics.bitsPerWord;
pixelSeqElementSize: NAT ~ SIZE[PixelSeqRep[1]]-SIZE[PixelSeqRep[0]];
Create: PUBLIC PROC [maxSize: NAT] RETURNS [new: PixelSeq] ~ {
new ← NEW[PixelSeqRep[maxSize]];
};
nScratchSlots: NAT ~ 2;
nScratchAvail: NAT ← 0;
scratch: ARRAY [0..nScratchSlots) OF PixelSeq;
rover: NAT ← 0;
ObtainScratch: PUBLIC ENTRY PROC [maxSize: NAT] RETURNS [new: PixelSeq] ~ {
ENABLE UNWIND => NULL;
FOR i: NAT DECREASING IN [0..nScratchAvail) DO
IF scratch[i].maxSize >= maxSize THEN {
new ← scratch[i];
IF i # nScratchAvail-1 THEN scratch[i] ← scratch[nScratchAvail-1];
nScratchAvail ← nScratchAvail - 1;
scratch[nScratchAvail] ← NIL;
EXIT;
};
ENDLOOP;
IF new = NIL THEN new ← NEW[PixelSeqRep[maxSize]];
};
ReleaseScratch: PUBLIC ENTRY PROC [pixelSeq: PixelSeq] ~ {
IF nScratchAvail < nScratchSlots THEN {
scratch[nScratchAvail] ← pixelSeq;
nScratchAvail ← nScratchAvail + 1;
}
ELSE {
scratch[rover] ← pixelSeq;
rover ← (rover + 1) MOD nScratchSlots;
};
};
Clear: PUBLIC PROC [pixelSeq: PixelSeq, size: NAT] ~ TRUSTED {
size ← MIN[size, pixelSeq.maxSize];
IF size > 0 THEN PrincOpsUtils.LongZero[@(pixelSeq[0]), size*pixelSeqElementSize];
};
Copy: PUBLIC PROC [pixelSeq: PixelSeq, size: NAT, scratch: PixelSeq ← NIL] RETURNS [new: PixelSeq] ~ {
size ← MIN[size, pixelSeq.maxSize];
new ← IF scratch = NIL OR scratch.maxSize < size THEN NEW[PixelSeqRep[size]] ELSE scratch;
IF size > 0 THEN TRUSTED {
PrincOpsUtils.LongCopy[from: @(pixelSeq[0]), nwords: size*pixelSeqElementSize, to: @(new[0])];
};
};
Add: PUBLIC PROC [dest, source: PixelSeq, size: NAT] ~ {
fMin: INTEGER ← 0;
fMax: INTEGER ← size;
IF fMin < fMax THEN TRUSTED {
destArr: LONG POINTER TO RECORD[SEQUENCE COMPUTED CARDINAL OF Pixel] ← LOOPHOLE[@(dest[fMin])];
sourceArr: LONG POINTER TO RECORD[SEQUENCE COMPUTED CARDINAL OF Pixel] ← LOOPHOLE[@(source[fMin])];
lengthMinusOne: NAT ← fMax-fMin-1;
dest[fMax-1] ← destArr[lengthMinusOne] + source[fMax-1];
Do last element the hard way to get bounds checking.
FOR j: NAT IN [0..lengthMinusOne) DO
destArr[j] ← destArr[j] + sourceArr[j];
ENDLOOP;
};
};
Subtract: PUBLIC PROC [dest, source: PixelSeq, size: NAT] ~ {
fMin: INTEGER ← 0;
fMax: INTEGER ← size;
IF fMin < fMax THEN TRUSTED {
destArr: LONG POINTER TO RECORD[SEQUENCE COMPUTED CARDINAL OF Pixel] ← LOOPHOLE[@(dest[fMin])];
sourceArr: LONG POINTER TO RECORD[SEQUENCE COMPUTED CARDINAL OF Pixel] ← LOOPHOLE[@(source[fMin])];
lengthMinusOne: NAT ← fMax-fMin-1;
dest[fMax-1] ← destArr[lengthMinusOne] - source[fMax-1];
Do last element the hard way to get bounds checking.
FOR j: NAT IN [0..lengthMinusOne) DO
destArr[j] ← destArr[j] - sourceArr[j];
ENDLOOP;
};
};
Apply: PUBLIC PROC [dest, source: PixelSeq, size: NAT, table: PixelSeq] ~ {
IF size > 0 THEN TRUSTED {
destArr: LONG POINTER TO RECORD[SEQUENCE COMPUTED CARDINAL OF Pixel] ← LOOPHOLE[@(dest[0])];
sourceArr: LONG POINTER TO RECORD[SEQUENCE COMPUTED CARDINAL OF Pixel] ← LOOPHOLE[@(source[0])];
lengthMinusOne: NAT ← size-1;
dest[lengthMinusOne] ← table[source[lengthMinusOne]];
Do last element the hard way to get bounds checking.
FOR j: NAT IN [0..lengthMinusOne) DO
destArr[j] ← table[sourceArr[j]];
ENDLOOP;
};
};
ApplyAndAdd: PUBLIC PROC [dest, source: PixelSeq, size: NAT, table: PixelSeq] ~ {
IF size > 0 THEN TRUSTED {
destArr: LONG POINTER TO RECORD[SEQUENCE COMPUTED CARDINAL OF Pixel] ← LOOPHOLE[@(dest[0])];
sourceArr: LONG POINTER TO RECORD[SEQUENCE COMPUTED CARDINAL OF Pixel] ← LOOPHOLE[@(source[0])];
lengthMinusOne: NAT ← size-1;
dest[lengthMinusOne] ← destArr[lengthMinusOne] + table[source[lengthMinusOne]];
Do last element the hard way to get bounds checking.
FOR j: NAT IN [0..lengthMinusOne) DO
destArr[j] ← destArr[j] + table[sourceArr[j]];
ENDLOOP;
};
};
LoadF: PUBLIC PROC [pixelSeq: PixelSeq, s, f: INTEGER, size: NAT, source: PixelMap] ~ TRUSTED {
fOriginMap: INTEGER ← source.fOrigin;
fOriginRow: INTEGER ← f;
fSizeRow: INTEGERMIN[size, pixelSeq.maxSize];
mapBB: DeviceRectangle ← source.BoundedWindow;
fMin: INTEGERMAX[fOriginRow, mapBB.fMin];
fMax: INTEGERMIN[fOriginRow+fSizeRow, mapBB.fMin+mapBB.fSize];
IF fMin >= fMax OR s NOT IN [mapBB.sMin..mapBB.sMin+mapBB.sSize)
THEN {Clear[pixelSeq, size]; RETURN};
IF fMin-fOriginRow > 0 THEN PrincOpsUtils.LongZero[@(pixelSeq[0]), (fMin-fOriginRow)*pixelSeqElementSize];
IF fMax-fOriginRow < fSizeRow THEN PrincOpsUtils.LongZero[@(pixelSeq[fMax-fOriginRow]), (fSizeRow-fMax+fOriginRow)*pixelSeqElementSize];
GreenBay.UnPack[
wordPointer: @(pixelSeq[fMin-fOriginRow]),
bitsPerElement: Basics.BITSHIFT[1, source.refRep.lgBitsPerPixel],
base: source.refRep.pointer + Basics.LongMult[(s - source.sOrigin), source.refRep.rast],
start: fMin-fOriginMap,
count: fMax-fMin
];
};
LoadS: PUBLIC PROC [pixelSeq: PixelSeq, s, f: INTEGER, size: NAT, source: PixelMap] ~ TRUSTED {
sOriginMap: INTEGER ← source.sOrigin;
seqOrigin: INTEGER ← s;
seqSize: INTEGERMIN[size, pixelSeq.maxSize];
mapBB: DeviceRectangle ← source.BoundedWindow;
sMin: INTEGERMAX[seqOrigin, mapBB.sMin];
sMax: INTEGERMIN[seqOrigin+seqSize, mapBB.sMin+mapBB.sSize];
bbTableSpace: PrincOps.BBTableSpace;
bb: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace];
bitsPerElement: CARDINAL ~ Basics.BITSHIFT[1, source.refRep.lgBitsPerPixel];
bit: CARDINAL ~ Basics.BITSHIFT[NAT[f-source.fOrigin], source.refRep.lgBitsPerPixel];
Clear[pixelSeq, size];
IF sMin >= sMax OR f NOT IN [mapBB.fMin..mapBB.fMin+mapBB.fSize) THEN RETURN;
bb^ ← [
dst: [word: @(pixelSeq[sMin-seqOrigin]), bit: bitsPerWord-bitsPerElement],
dstBpl: bitsPerWord,
src: [word: source.refRep.pointer + Basics.LongMult[(sMin - source.sOrigin), source.refRep.rast] + bit/bitsPerWord, bit: bit MOD bitsPerWord],
srcDesc: [srcBpl[source.refRep.rast*bitsPerWord]],
width: bitsPerElement,
height: sMax-sMin,
flags: []
];
PrincOpsUtils.BITBLT[bb];
};
StoreF: PUBLIC PROC [pixelSeq: PixelSeq, s, f: INTEGER, size: NAT, dest: PixelMap] ~ TRUSTED {
fOriginMap: INTEGER ← dest.fOrigin;
fOriginRow: INTEGER ← f;
fSizeRow: INTEGERMIN[size, pixelSeq.maxSize];
mapBB: DeviceRectangle ← dest.BoundedWindow;
fMin: INTEGERMAX[fOriginRow, mapBB.fMin];
fMax: INTEGERMIN[fOriginRow+fSizeRow, mapBB.fMin+mapBB.fSize];
IF fMin >= fMax OR s NOT IN [mapBB.sMin..mapBB.sMin+mapBB.sSize) THEN RETURN;
GreenBay.Pack[
wordPointer: @(pixelSeq[fMin-fOriginRow]),
bitsPerElement: Basics.BITSHIFT[1, dest.refRep.lgBitsPerPixel],
base: dest.refRep.pointer + Basics.LongMult[(s - dest.sOrigin), dest.refRep.rast],
start: fMin-fOriginMap,
count: fMax-fMin
];
};
StoreS: PUBLIC PROC [pixelSeq: PixelSeq, s, f: INTEGER, size: NAT, dest: PixelMap] ~ TRUSTED {
sOriginMap: INTEGER ← dest.sOrigin;
seqOrigin: INTEGER ← s;
seqSize: INTEGERMIN[size, pixelSeq.maxSize];
mapBB: DeviceRectangle ← dest.BoundedWindow;
sMin: INTEGERMAX[seqOrigin, mapBB.sMin];
sMax: INTEGERMIN[seqOrigin+seqSize, mapBB.sMin+mapBB.sSize];
bbTableSpace: PrincOps.BBTableSpace;
bb: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace];
bitsPerElement: CARDINAL ~ Basics.BITSHIFT[1, dest.refRep.lgBitsPerPixel];
bit: CARDINAL ~ Basics.BITSHIFT[NAT[f-dest.fOrigin], dest.refRep.lgBitsPerPixel];
IF sMin >= sMax OR f NOT IN [mapBB.fMin..mapBB.fMin+mapBB.fSize) THEN RETURN;
bb^ ← [
dst: [word: dest.refRep.pointer + Basics.LongMult[(sMin - dest.sOrigin), dest.refRep.rast] + bit/bitsPerWord, bit: bit MOD bitsPerWord],
dstBpl: dest.refRep.rast*bitsPerWord,
src: [word: @(pixelSeq[sMin-seqOrigin]), bit: bitsPerWord-bitsPerElement],
srcDesc: [srcBpl[bitsPerWord]],
width: bitsPerElement,
height: sMax-sMin,
flags: []
];
PrincOpsUtils.BITBLT[bb];
};
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[[sr.sMin, sr.fMin, sr.sSize, sr.fSize], transformation];
destRect: DeviceRectangle ← dest.BoundedWindow;
dr: DeviceRectangle ← IF tile THEN destRect ELSE ImagerPixelMap.Intersect[destRect, [db.x, db.y, db.w, db.h]];
pixelSeq: PixelSeq ← ObtainScratch[dr.fSize];
deltaPixel: Pair ~ ImagerTransformation.InverseTransformVec[transformation, [0, 1]];
sDelta: Scaled.Value ~ Scaled.FromReal[deltaPixel.x];
fDelta: Scaled.Value ~ Scaled.FromReal[deltaPixel.y];
deltaLine: Pair ~ ImagerTransformation.InverseTransformVec[transformation, [1, 0]];
sDeltaLine: Scaled.Value ~ Scaled.FromReal[deltaLine.x];
fDeltaLine: Scaled.Value ~ Scaled.FromReal[deltaLine.y];
sourceOrigin: Pair ~ ImagerTransformation.InverseTransform[transformation, [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..dr.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 {
pixelSeq[j] ← Basics.BITSHIFT[source.GetPixel[s.Floor, f.Floor]*multiplier, lgScale];
};
s ← s.PLUS[sDelta];
f ← f.PLUS[fDelta];
ENDLOOP;
};
FOR s: INTEGER IN [dr.sMin..dr.sMin+dr.sSize) DO
LoadF[pixelSeq, s, dr.fMin, dr.fSize, dest];
GetSamples[];
StoreF[pixelSeq, s, dr.fMin, dr.fSize, dest];
sSource ← sSource.PLUS[sDeltaLine];
fSource ← fSource.PLUS[fDeltaLine];
ENDLOOP;
ReleaseScratch[pixelSeq];
};
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[[sr.sMin, sr.fMin, sr.sSize, sr.fSize], transformation];
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 {
BoxFilter[pixelMap, sSizeBox, 1];
BoxFilter[pixelMap, 1, fSizeBox];
}
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..256) OF PixelSeq;
nPixels: CARDINAL ← sSizeBox*fSizeBox;
sOrigin: INTEGER ← sStart-2*sSizeBox+sHalf;
fOrigin: INTEGER ~ fStart-fSizeBox;
result: PixelSeq ← ObtainScratch[pixelMap.fSize];
paddedSize: NAT ← pixelMap.fSize+2*fSizeBox;
MoveToNextRow: PROC ~ {
t: PixelSeq ← sum[0];
p: Pixel;
FOR i: NAT IN [0..sSizeBox) DO
sum[i] ← sum[i+1];
ENDLOOP;
sum[sSizeBox] ← t;
sOrigin ← sOrigin + 1;
LoadF[
pixelSeq: t,
s: MAX[MIN[sOrigin + sSizeBox, sEnd-1], sStart],
f: fOrigin,
size: paddedSize,
source: pixelMap
];
p ← t[fSizeBox];
FOR i: NAT IN [0..fSizeBox) DO
t[i] ← p;
ENDLOOP;
p ← t[paddedSize-fSizeBox-1];
FOR i: NAT IN [paddedSize-fSizeBox..paddedSize) DO
t[i] ← p;
ENDLOOP;
FOR i: NAT IN [1..paddedSize) DO t[i] ← t[i] + t[i-1] ENDLOOP;
Add[t, sum[sSizeBox-1], paddedSize];
};
FOR i: NAT IN [0..sSizeBox] DO
sum[i] ← Create[paddedSize];
ENDLOOP;
FOR s: INTEGER IN [sStart..sEnd) DO
WHILE sOrigin+sHalf+1 # s DO MoveToNextRow[] ENDLOOP;
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;
StoreF[result, s, fStart, pixelMap.fSize, pixelMap];
ENDLOOP;
ReleaseScratch[result];
};
};
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];
pixelSeq: PixelSeq ← ObtainScratch[bounds.fSize];
FOR s: INTEGER IN [bounds.sMin..bounds.sMin+bounds.sSize) DO
LoadF[pixelSeq, s, bounds.fMin, bounds.fSize, pixelMap];
StoreF[pixelSeq, s, bounds.fMin, bounds.fSize, new];
ENDLOOP;
ReleaseScratch[pixelSeq];
RETURN [new]
};
Renormalize: PUBLIC PROC [pixelMap: PixelMap, oldmin, oldmax, newmin, newmax: REAL] ~ {
bounds: DeviceRectangle ← pixelMap.Window;
pixelSeq: PixelSeq ← ObtainScratch[bounds.fSize];
m: REAL ← (newmax-newmin)/(oldmax-oldmin);
FOR s: INTEGER IN [bounds.sMin..bounds.sMin+bounds.sSize) DO
LoadF[pixelSeq, s, bounds.fMin, bounds.fSize, pixelMap];
FOR j: NAT IN [0..bounds.fSize) DO
pix: REAL ← pixelSeq[j];
out: REAL ← (pix-oldmin)*m+newmin;
pixelSeq[j] ← MAX[MIN[Real.RoundLI[out], CARDINAL.LAST], 0];
ENDLOOP;
StoreF[pixelSeq, s, bounds.fMin, bounds.fSize, pixelMap];
ENDLOOP;
ReleaseScratch[pixelSeq];
};
END.