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;
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: INTEGER ← MIN[size, pixelSeq.maxSize];
mapBB: DeviceRectangle ← source.BoundedWindow;
fMin: INTEGER ← MAX[fOriginRow, mapBB.fMin];
fMax: INTEGER ← MIN[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: INTEGER ← MIN[size, pixelSeq.maxSize];
mapBB: DeviceRectangle ← source.BoundedWindow;
sMin: INTEGER ← MAX[seqOrigin, mapBB.sMin];
sMax: INTEGER ← MIN[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: INTEGER ← MIN[size, pixelSeq.maxSize];
mapBB: DeviceRectangle ← dest.BoundedWindow;
fMin: INTEGER ← MAX[fOriginRow, mapBB.fMin];
fMax: INTEGER ← MIN[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: INTEGER ← MIN[size, pixelSeq.maxSize];
mapBB: DeviceRectangle ← dest.BoundedWindow;
sMin: INTEGER ← MAX[seqOrigin, mapBB.sMin];
sMax: INTEGER ← MIN[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:
BOOLEAN ←
FALSE, 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:
BOOLEAN ←
FALSE, 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.