ImagerSampleImpl.mesa
Copyright © 1984, 1985 by Xerox Corporation. All rights reserved.
Michael Plass, November 1, 1985 9:19:12 am PST
Doug Wyatt, May 28, 1985 7:04:18 pm PDT
DIRECTORY
Basics,
ImagerSample,
ImagerTransformation,
PrincOps,
PrincOpsUtils,
Process,
Real;
ImagerSampleImpl: CEDAR MONITOR
IMPORTS Basics, ImagerSample, ImagerTransformation, PrincOpsUtils, Process, Real
EXPORTS ImagerSample
~ BEGIN OPEN ImagerSample;
assertSampleSizeMatchesWordSize: BOOL[TRUE..TRUE] ~ SIZE[Sample]=SIZE[WORD];
bitsPerWord: NAT ~ Basics.bitsPerWord;
lgBitsPerWord: NAT ~ Basics.logBitsPerWord;
NewBuffer: PUBLIC PROC [iSize, jSize: NAT, scratch: SampleBuffer ← NIL]
RETURNS
[SampleBuffer] ~ {
size: NAT ~ Basics.LongMult[iSize, jSize];
new: SampleBuffer ← scratch;
IF new=NIL OR new.size<size THEN new ← NEW[SampleBufferRep[size]];
new.iSize ← iSize; new.jSize ← jSize;
RETURN[new];
};
nScratchSlots: NAT ~ 2;
nScratchAvail: NAT ← 0;
scratch: ARRAY [0..nScratchSlots) OF SampleBuffer ← ALL[NIL];
rover: NAT ← 0;
ObtainScratchBuffer: PUBLIC ENTRY PROC [iSize, jSize: NAT]
RETURNS [buffer: SampleBuffer ← NIL] ~ {
ENABLE UNWIND => NULL;
size: NAT ~ Basics.LongMult[iSize, jSize];
FOR i: NAT DECREASING IN [0..nScratchAvail) DO
IF scratch[i].size >= size THEN {
buffer ← scratch[i];
IF i # nScratchAvail-1 THEN scratch[i] ← scratch[nScratchAvail-1];
nScratchAvail ← nScratchAvail - 1;
scratch[nScratchAvail] ← NIL;
EXIT;
};
ENDLOOP;
buffer ← NewBuffer[iSize: iSize, jSize: jSize, scratch: buffer];
};
ReleaseScratchBuffer: PUBLIC ENTRY PROC [buffer: SampleBuffer] ~ {
IF nScratchAvail < nScratchSlots THEN {
scratch[nScratchAvail] ← buffer;
nScratchAvail ← nScratchAvail + 1;
}
ELSE {
scratch[rover] ← buffer;
rover ← (rover + 1) MOD nScratchSlots;
};
};
DoWithScratchBuffer: PUBLIC PROC [iSize, jSize: NAT, action: PROC [SampleBuffer]] ~ {
buffer: SampleBuffer ~ ObtainScratchBuffer[iSize, jSize];
action[buffer ! UNWIND => ReleaseScratchBuffer[buffer]];
ReleaseScratchBuffer[buffer];
};
GetSample: PUBLIC PROC [buffer: SampleBuffer, i, j: NAT] RETURNS [Sample] ~ {
k: NAT ~ Basics.BoundsCheck[i, buffer.iSize]*buffer.jSize+Basics.BoundsCheck[j, buffer.jSize];
RETURN[buffer[k]];
};
PutSample: PUBLIC PROC [buffer: SampleBuffer, i, j: NAT, sample: Sample] ~ {
k: NAT ~ Basics.BoundsCheck[i, buffer.iSize]*buffer.jSize+Basics.BoundsCheck[j, buffer.jSize];
buffer[k] ← sample;
};
GetPointer: PUBLIC PROC [buffer: SampleBuffer, i, j, count: NAT] RETURNS [UnsafeSamples] ~ {
k: NAT ~ Basics.BoundsCheck[i, buffer.iSize]*buffer.jSize+Basics.BoundsCheck[j, buffer.jSize];
IF count#0 THEN [] ← Basics.BoundsCheck[j+count-1, buffer.jSize];
TRUSTED { RETURN[LOOPHOLE[@buffer[k]]] };
};
UnsafeAdd: PUBLIC UNSAFE PROC [src1, src2, dst: UnsafeSamples, count: NAT] ~ UNCHECKED {
THROUGH [0..count/8) DO
dst[0] ← src1[0]+src2[0];
dst[1] ← src1[1]+src2[1];
dst[2] ← src1[2]+src2[2];
dst[3] ← src1[3]+src2[3];
dst[4] ← src1[4]+src2[4];
dst[5] ← src1[5]+src2[5];
dst[6] ← src1[6]+src2[6];
dst[7] ← src1[7]+src2[7];
src1 ← src1+8;
src2 ← src2+8;
dst ← dst+8;
ENDLOOP;
FOR k: NAT IN[0..count MOD 8) DO dst[k] ← src1[k]+src2[k] ENDLOOP;
};
UnsafeSub: PUBLIC UNSAFE PROC [src1, src2, dst: UnsafeSamples, count: NAT] ~ UNCHECKED {
THROUGH [0..count/8) DO
dst[0] ← src1[0]-src2[0];
dst[1] ← src1[1]-src2[1];
dst[2] ← src1[2]-src2[2];
dst[3] ← src1[3]-src2[3];
dst[4] ← src1[4]-src2[4];
dst[5] ← src1[5]-src2[5];
dst[6] ← src1[6]-src2[6];
dst[7] ← src1[7]-src2[7];
src1 ← src1+8;
src2 ← src2+8;
dst ← dst+8;
ENDLOOP;
FOR k: NAT IN[0..count MOD 8) DO dst[k] ← src1[k]-src2[k] ENDLOOP;
};
UnsafeLookup: PUBLIC UNSAFE PROC [tbl, src, dst: UnsafeSamples, count: NAT] ~ UNCHECKED {
THROUGH [0..count/8) DO
dst[0] ← tbl[src[0]];
dst[1] ← tbl[src[1]];
dst[2] ← tbl[src[2]];
dst[3] ← tbl[src[3]];
dst[4] ← tbl[src[4]];
dst[5] ← tbl[src[5]];
dst[6] ← tbl[src[6]];
dst[7] ← tbl[src[7]];
src ← src+8;
dst ← dst+8;
ENDLOOP;
FOR k: NAT IN[0..count) DO dst[k] ← tbl[src[k]] ENDLOOP;
};
AddSamples: PUBLIC PROC [samples: SampleBuffer, si, sj: NAT ← 0,
buffer: SampleBuffer, bi, bj: NAT ← 0, count: NAT] ~ {
src: UnsafeSamples ~ GetPointer[samples, si, sj, count];
dst: UnsafeSamples ~ GetPointer[buffer, bi, bj, count];
TRUSTED { UnsafeAdd[src1: dst, src2: src, dst: dst, count: count] };
};
SubSamples: PUBLIC PROC [samples: SampleBuffer, si, sj: NAT ← 0,
buffer: SampleBuffer, bi, bj: NAT ← 0, count: NAT] ~ {
src: UnsafeSamples ~ GetPointer[samples, si, sj, count];
dst: UnsafeSamples ~ GetPointer[buffer, bi, bj, count];
TRUSTED { UnsafeSub[src1: dst, src2: src, dst: dst, count: count] };
};
LookupSamples: PUBLIC PROC [table: SampleBuffer, samples: SampleBuffer, si, sj: NAT ← 0,
buffer: SampleBuffer, bi, bj: NAT ← 0, count: NAT] ~ {
tbl: UnsafeSamples ~ GetPointer[table, 0, 0, 0];
src: UnsafeSamples ~ GetPointer[samples, si, sj, count];
dst: UnsafeSamples ~ GetPointer[buffer, bi, bj, count];
TRUSTED { FOR k: NAT IN[0..count) DO dst[k] ← table[src[k]] ENDLOOP };
};
LookupPixels: PUBLIC PROC [tables: SampleBuffer, pixels: SampleBuffer, pj: NAT ← 0,
buffer: SampleBuffer, bi, bj: NAT ← 0, count: NAT] ~ {
dst: UnsafeSamples ~ GetPointer[buffer, bi, bj, count];
SELECT tables.iSize FROM
0 => NULL;
1 => {
tbl0: UnsafeSamples ~ GetPointer[tables, 0, 0, 0];
src0: UnsafeSamples ~ GetPointer[pixels, 0, pj, count];
TRUSTED { FOR k: NAT IN[0..count) DO dst[k] ← tbl0[src0[k]] ENDLOOP };
};
2 => {
tbl0: UnsafeSamples ~ GetPointer[tables, 0, 0, 0];
tbl1: UnsafeSamples ~ GetPointer[tables, 1, 0, 0];
src0: UnsafeSamples ~ GetPointer[pixels, 0, pj, count];
src1: UnsafeSamples ~ GetPointer[pixels, 1, pj, count];
TRUSTED { FOR k: NAT IN[0..count) DO dst[k] ← tbl0[src0[k]]+tbl1[src1[k]] ENDLOOP };
};
3 => {
tbl0: UnsafeSamples ~ GetPointer[tables, 0, 0, 0];
tbl1: UnsafeSamples ~ GetPointer[tables, 1, 0, 0];
tbl2: UnsafeSamples ~ GetPointer[tables, 2, 0, 0];
src0: UnsafeSamples ~ GetPointer[pixels, 0, pj, count];
src1: UnsafeSamples ~ GetPointer[pixels, 1, pj, count];
src2: UnsafeSamples ~ GetPointer[pixels, 2, pj, count];
TRUSTED { FOR k: NAT IN[0..count) DO dst[k] ← tbl0[src0[k]]+tbl1[src1[k]]+tbl2[src2[k]] ENDLOOP };
};
ENDCASE => FOR k: NAT IN[0..count) DO
sum: Sample ← 0;
FOR i: NAT IN[0..tables.iSize) DO
sum ← sum+tables.GetSample[i, pixels.GetSample[i, pj+k]];
ENDLOOP;
buffer.PutSample[bi, bj+k, sum];
ENDLOOP;
};
LgEntry: TYPE ~ RECORD[powerOfTwo: BOOL, lg: NAT ← 0];
LgArray: TYPE ~ ARRAY BitsPerSample OF LgEntry;
lgArray: REF LgArray ~ InitLgArray[];
InitLgArray: PROC RETURNS [REF LgArray] ~ {
lgArray: REF LgArray ~ NEW[LgArray ← ALL[[powerOfTwo: FALSE]]];
FOR lg: NAT IN[0..lgBitsPerWord] DO
lgArray[Basics.BITSHIFT[1, lg]] ← [powerOfTwo: TRUE, lg: lg];
ENDLOOP;
RETURN[lgArray];
};
nullBitBltTable: PrincOps.BitBltTable ~ [
dst: [word: NIL, bit: 0], dstBpl: 0,
src: [word: NIL, bit: 0], srcDesc: [srcBpl[0]],
width: 0, height: 0, flags: []
];
UnsafeGetF: PUBLIC UNSAFE PROC [samples: UnsafeSamples, count: NAT, s, f: NAT ← 0,
base: LONG POINTER, wordsPerLine: NAT, bitsPerSample: BitsPerSample] ~ UNCHECKED {
lgEntry: LgEntry ~ lgArray[bitsPerSample];
line: LONG POINTER ~ base+Basics.LongMult[s, wordsPerLine];
bbTableSpace: PrincOps.BBTableSpace;
bb: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace];
bb^ ← nullBitBltTable;
bb.flags ← [disjoint: TRUE, gray: FALSE];
PrincOpsUtils.LongZero[where: samples, nwords: count];
IF lgEntry.powerOfTwo THEN {
lgBitsPerItem: NAT ~ lgEntry.lg;
bitsPerItem: NAT ~ Basics.BITSHIFT[1, lgBitsPerItem];
lgItemsPerWord: NAT ~ lgBitsPerWord-lgBitsPerItem;
itemsPerWord: NAT ~ Basics.BITSHIFT[1, lgItemsPerWord];
bb.dst.bit ← bitsPerWord-bitsPerItem;
bb.dstBpl ← Basics.BITSHIFT[bitsPerWord, lgItemsPerWord];
bb.srcDesc.srcBpl ← bitsPerWord;
bb.width ← bitsPerItem;
FOR k: NAT IN [0..MIN[itemsPerWord, count]) DO
x: CARDINAL ~ f+k;
bb.dst.word ← @samples[k];
bb.src.word ← line+Basics.BITSHIFT[x, -lgItemsPerWord];
bb.src.bit ← Basics.BITSHIFT[Basics.BITAND[x, itemsPerWord-1], lgBitsPerItem];
bb.height ← Basics.BITSHIFT[(count-k)+(itemsPerWord-1), -lgItemsPerWord];
bb.src.word ← line+x/itemsPerWord;
bb.src.bit ← (x MOD itemsPerWord)*bitsPerItem;
bb.height ← Ceiling[(count-k)/itemsPerWord];
PrincOpsUtils.BITBLT[bb];
ENDLOOP;
}
ELSE {
bit: LONG CARDINAL ~ Basics.LongMult[f, bitsPerSample];
bb.dst.word ← samples;
bb.dst.bit ← bitsPerWord-bitsPerSample;
bb.dstBpl ← bitsPerWord;
bb.src.word ← line+bit/bitsPerWord;
bb.src.bit ← bit MOD bitsPerWord;
bb.srcDesc.srcBpl ← bitsPerSample;
bb.width ← bitsPerSample;
bb.height ← count;
PrincOpsUtils.BITBLT[bb];
};
};
UnsafePutF: PUBLIC UNSAFE PROC [samples: UnsafeSamples, count: NAT, s, f: NAT ← 0,
base: LONG POINTER, wordsPerLine: NAT, bitsPerSample: BitsPerSample, srcFunc: PrincOps.SrcFunc ← null, dstFunc: PrincOps.DstFunc ← null] ~ UNCHECKED {
lgEntry: LgEntry ~ lgArray[bitsPerSample];
line: LONG POINTER ~ base+Basics.LongMult[s, wordsPerLine];
bbTableSpace: PrincOps.BBTableSpace;
bb: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace];
bb^ ← nullBitBltTable;
bb.flags ← [disjoint: TRUE, gray: FALSE, srcFunc: srcFunc, dstFunc: dstFunc];
IF lgEntry.powerOfTwo THEN {
lgBitsPerItem: NAT ~ lgEntry.lg;
bitsPerItem: NAT ~ Basics.BITSHIFT[1, lgBitsPerItem];
lgItemsPerWord: NAT ~ lgBitsPerWord-lgBitsPerItem;
itemsPerWord: NAT ~ Basics.BITSHIFT[1, lgItemsPerWord];
bb.src.bit ← bitsPerWord-bitsPerItem;
bb.srcDesc.srcBpl ← Basics.BITSHIFT[bitsPerWord, lgItemsPerWord];
bb.dstBpl ← bitsPerWord;
bb.width ← bitsPerItem;
FOR k: NAT IN [0..MIN[itemsPerWord, count]) DO
x: CARDINAL ~ f+k;
bb.src.word ← @samples[k];
bb.dst.word ← line+Basics.BITSHIFT[x, -lgItemsPerWord];
bb.dst.bit ← Basics.BITSHIFT[Basics.BITAND[x, itemsPerWord-1], lgBitsPerItem];
bb.height ← Basics.BITSHIFT[(count-k)+(itemsPerWord-1), -lgItemsPerWord];
bb.dst.word ← line+x/itemsPerWord;
bb.dst.bit ← (x MOD itemsPerWord)*bitsPerItem;
bb.height ← Ceiling[(count-k)/itemsPerWord];
PrincOpsUtils.BITBLT[bb];
ENDLOOP;
}
ELSE {
bit: LONG CARDINAL ~ Basics.LongMult[f, bitsPerSample];
bb.src.word ← samples;
bb.src.bit ← bitsPerWord-bitsPerSample;
bb.srcDesc.srcBpl ← bitsPerWord;
bb.dst.word ← line+bit/bitsPerWord;
bb.dst.bit ← bit MOD bitsPerWord;
bb.dstBpl ← bitsPerSample;
bb.width ← bitsPerSample;
bb.height ← count;
PrincOpsUtils.BITBLT[bb];
};
};
UnsafePutFSign: PUBLIC UNSAFE PROC [samples: UnsafeSamples, count: NAT, s, f: NAT ← 0,
base: LONG POINTER, wordsPerLine: NAT] ~ UNCHECKED {
line: LONG POINTER ~ base+Basics.LongMult[s, wordsPerLine];
bbTableSpace: PrincOps.BBTableSpace;
bb: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace];
bb^ ← nullBitBltTable;
bb.flags ← [disjoint: TRUE, gray: FALSE];
bb.srcDesc.srcBpl ← bitsPerWord*bitsPerWord;
bb.dstBpl ← bitsPerWord;
bb.width ← 1;
FOR k: NAT IN [0..MIN[bitsPerWord, count]) DO
x: CARDINAL ~ f+k;
bb.src.word ← @samples[k];
bb.dst.word ← line+x/bitsPerWord;
bb.dst.bit ← x MOD bitsPerWord;
bb.height ← (CARDINAL[count-k]+bitsPerWord-1)/bitsPerWord;
PrincOpsUtils.BITBLT[bb];
ENDLOOP;
};
UnsafeGetS: PUBLIC UNSAFE PROC [samples: UnsafeSamples, count: NAT, s, f: NAT ← 0,
base: LONG POINTER, wordsPerLine: NAT, bitsPerSample: BitsPerSample] ~ UNCHECKED {
lgEntry: LgEntry ~ lgArray[bitsPerSample];
bbTableSpace: PrincOps.BBTableSpace;
bb: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace];
bb^ ← nullBitBltTable;
bb.flags ← [disjoint: TRUE, gray: FALSE];
PrincOpsUtils.LongZero[where: samples, nwords: count];
bb.dst.word ← samples;
bb.dst.bit ← bitsPerWord-bitsPerSample;
bb.dstBpl ← bitsPerWord;
bb.srcDesc.srcBpl ← wordsPerLine*bitsPerWord;
bb.width ← bitsPerSample;
bb.height ← count;
IF lgEntry.powerOfTwo THEN {
lgBitsPerItem: NAT ~ lgEntry.lg;
lgItemsPerWord: NAT ~ lgBitsPerWord-lgBitsPerItem;
itemsPerWord: NAT ~ Basics.BITSHIFT[1, lgItemsPerWord];
bb.src.word ← base+Basics.LongMult[s, wordsPerLine]+Basics.BITSHIFT[f, -lgItemsPerWord];
bb.src.bit ← Basics.BITSHIFT[Basics.BITAND[f, itemsPerWord-1], lgBitsPerItem];
bb.src.word ← base+s*wordsPerLine+f/itemsPerWord;
bb.src.bit ← (f MOD itemsPerWord)*bitsPerItem;
PrincOpsUtils.BITBLT[bb];
}
ELSE {
x: LONG CARDINAL ~ Basics.LongMult[bitsPerSample, f];
bb.src.word ← base+Basics.LongMult[wordsPerLine, s]+x/bitsPerWord;
bb.src.bit ← x MOD bitsPerWord;
PrincOpsUtils.BITBLT[bb];
};
};
UnsafePutS: PUBLIC UNSAFE PROC [samples: UnsafeSamples, count: NAT, s, f: NAT ← 0,
base: LONG POINTER, wordsPerLine: NAT, bitsPerSample: BitsPerSample, srcFunc: PrincOps.SrcFunc ← null, dstFunc: PrincOps.DstFunc ← null] ~ UNCHECKED {
lgEntry: LgEntry ~ lgArray[bitsPerSample];
bbTableSpace: PrincOps.BBTableSpace;
bb: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace];
bb^ ← nullBitBltTable;
bb.flags ← [disjoint: TRUE, gray: FALSE, srcFunc: srcFunc, dstFunc: dstFunc];
bb.dstBpl ← wordsPerLine*bitsPerWord;
bb.src.word ← samples;
bb.src.bit ← bitsPerWord-bitsPerSample;
bb.srcDesc.srcBpl ← bitsPerWord;
bb.width ← bitsPerSample;
bb.height ← count;
IF lgEntry.powerOfTwo THEN {
lgBitsPerItem: NAT ~ lgEntry.lg;
lgItemsPerWord: NAT ~ lgBitsPerWord-lgBitsPerItem;
itemsPerWord: NAT ~ Basics.BITSHIFT[1, lgItemsPerWord];
bb.dst.word ← base+Basics.LongMult[s, wordsPerLine]+Basics.BITSHIFT[f, -lgItemsPerWord];
bb.dst.bit ← Basics.BITSHIFT[Basics.BITAND[f, itemsPerWord-1], lgBitsPerItem];
bb.dst.word ← base+s*wordsPerLine+f/itemsPerWord;
bb.dst.bit ← (f MOD itemsPerWord)*bitsPerItem;
PrincOpsUtils.BITBLT[bb];
}
ELSE {
x: LONG CARDINAL ~ Basics.LongMult[bitsPerSample, f];
bb.dst.word ← base+Basics.LongMult[wordsPerLine, s]+x/bitsPerWord;
bb.dst.bit ← x MOD bitsPerWord;
PrincOpsUtils.BITBLT[bb];
};
};
realLastInt: REALREAL[LAST[INT]];
Floor: PROC[a: REAL] RETURNS[c: REAL] ~ {
IF ABS[a] >= realLastInt THEN RETURN [a];
c ← REAL[Real.Fix[a]];
IF c>a THEN RETURN[c-1] ELSE RETURN[c]
};
ScaledFromRealMod: PROC [d: REAL, m: CARDINAL] RETURNS [INT] ~ {
s: Basics.LongNumber ← [li[0]];
IF m # 0 THEN {
modulus: REAL ~ m;
residue: REALIF d IN [0..modulus) THEN d ELSE (d-modulus*Floor[d/modulus]);
s.li ← Real.Round[Real.FScale[residue, Basics.bitsPerWord]];
Now some paranoia about floating-point fuzz
IF s.li < 0 THEN {s.hi ← s.hi + m};
IF s.hi >= m THEN {s.hi ← s.hi - m};
IF s.hi >= m THEN ERROR;
};
RETURN [s.li];
};
SetSamplerIncrements: PUBLIC PROC [sampler: Sampler, m: Transformation] ~ {
sSize: NAT ~ sampler.sSize;
fSize: NAT ~ sampler.fSize;
s, f: REAL ← 0.0;
[[s, f]] ← m.InverseTransformVec[[0, 1] ! Real.RealException => CONTINUE];
A singular transformation means the image can't be shown anyway.
sampler.sfDelta.li ← ScaledFromRealMod[s, sSize];
sampler.ffDelta.li ← ScaledFromRealMod[f, fSize];
s ← f ← 0.0;
[[s, f]] ← m.InverseTransformVec[[1, 0] ! Real.RealException => CONTINUE];
sampler.ssDelta.li ← ScaledFromRealMod[s, sSize];
sampler.fsDelta.li ← ScaledFromRealMod[f, fSize];
};
SetSamplerPosition: PUBLIC PROC [sampler: Sampler, m: Transformation, s, f: CARDINAL] ~ {
sSource, fSource: REAL ← 0.0;
sSize: NAT ~ sampler.sSize;
fSize: NAT ~ sampler.fSize;
[[sSource, fSource]] ← m.InverseTransform[[s+0.5, f+0.5] ! Real.RealException => CONTINUE];
sampler.sSource.li ← ScaledFromRealMod[sSource, sSize];
sampler.fSource.li ← ScaledFromRealMod[fSource, fSize];
sampler.sDest ← s;
sampler.fDest ← f;
};
Sample0: TYPE ~ CARDINAL[0..000001B]; -- 1 bit
Sample1: TYPE ~ CARDINAL[0..000003B]; -- 2 bits
Sample2: TYPE ~ CARDINAL[0..000017B]; -- 4 bits
Sample3: TYPE ~ CARDINAL[0..000377B]; -- 8 bits
Sample4: TYPE ~ CARDINAL[0..177777B]; -- 16 bits
Sequence0: TYPE ~ RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF Sample0];
Sequence1: TYPE ~ RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF Sample1];
Sequence2: TYPE ~ RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF Sample2];
Sequence3: TYPE ~ RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF Sample3];
Sequence4: TYPE ~ RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF Sample4];
Pointer0: TYPE ~ LONG POINTER TO Sequence0;
Pointer1: TYPE ~ LONG POINTER TO Sequence1;
Pointer2: TYPE ~ LONG POINTER TO Sequence2;
Pointer3: TYPE ~ LONG POINTER TO Sequence3;
Pointer4: TYPE ~ LONG POINTER TO Sequence4;
GetPointSamples: PUBLIC PROC [sampler: Sampler, s, f: CARDINAL,
buffer: SampleBuffer, bi, bj: NAT ← 0, count: NAT] ~ TRUSTED {
lgEntry: LgEntry ~ lgArray[sampler.bitsPerSample];
samples: UnsafeSamples ~ buffer.GetPointer[bi, bj, count];
base: LONG POINTER ~ sampler.base;
wordsPerLine: CARDINAL ~ sampler.wordsPerLine;
line: LONG POINTER ← base;
sLine: CARDINAL ← 0;
sSize: CARDINAL ~ sampler.sSize;
fSize: CARDINAL ~ sampler.fSize;
sMin: CARDINAL ~ sampler.sMin;
fMin: CARDINAL ~ sampler.fMin;
sMax: CARDINAL ~ sMin+sSize;
fMax: CARDINAL ~ fMin+fSize;
ssDelta: Basics.LongNumber ~ sampler.ssDelta;
fsDelta: Basics.LongNumber ~ sampler.fsDelta;
sfDelta: Basics.LongNumber ~ sampler.sfDelta;
ffDelta: Basics.LongNumber ~ sampler.ffDelta;
sSource: Basics.LongNumber ← sampler.sSource;
fSource: Basics.LongNumber ← sampler.fSource;
sDest: CARDINAL ← sampler.sDest;
fDest: CARDINAL ← sampler.fDest;
Process.CheckForAbort[];
WHILE sDest<s DO
sSource.lc ← sSource.lc+ssDelta.lc;
fSource.lc ← fSource.lc+fsDelta.lc;
IF NOT sSource.hi<sSize THEN sSource.hi ← sSource.hi-sSize;
IF NOT fSource.hi<fSize THEN fSource.hi ← fSource.hi-fSize;
sDest ← sDest+1;
ENDLOOP;
sampler.sSource ← sSource;
sampler.fSource ← fSource;
sampler.sDest ← sDest;
WHILE fDest<f DO
sSource.lc ← sSource.lc+sfDelta.lc;
fSource.lc ← fSource.lc+ffDelta.lc;
IF NOT sSource.hi<sSize THEN sSource.hi ← sSource.hi-sSize;
IF NOT fSource.hi<fSize THEN fSource.hi ← fSource.hi-fSize;
fDest ← fDest+1;
ENDLOOP;
IF s#sDest OR f#fDest THEN ERROR;
sSource.hi ← sSource.hi+sMin;
fSource.hi ← fSource.hi+fMin;
IF lgEntry.powerOfTwo THEN SELECT lgEntry.lg FROM
0 => FOR k: NAT IN[0..count) DO
IF sLine#sSource.hi THEN line ← base+Basics.LongMult[sLine ← sSource.hi, wordsPerLine];
samples[k] ← LOOPHOLE[line, Pointer0][fSource.hi];
sSource.lc ← sSource.lc+sfDelta.lc; fSource.lc ← fSource.lc+ffDelta.lc;
IF NOT sSource.hi<sMax THEN sSource.hi ← sSource.hi-sSize;
IF NOT fSource.hi<fMax THEN fSource.hi ← fSource.hi-fSize;
ENDLOOP;
1 => FOR k: NAT IN[0..count) DO
IF sLine#sSource.hi THEN line ← base+Basics.LongMult[sLine ← sSource.hi, wordsPerLine];
samples[k] ← LOOPHOLE[line, Pointer1][fSource.hi];
sSource.lc ← sSource.lc+sfDelta.lc; fSource.lc ← fSource.lc+ffDelta.lc;
IF NOT sSource.hi<sMax THEN sSource.hi ← sSource.hi-sSize;
IF NOT fSource.hi<fMax THEN fSource.hi ← fSource.hi-fSize;
ENDLOOP;
2 => FOR k: NAT IN[0..count) DO
IF sLine#sSource.hi THEN line ← base+Basics.LongMult[sLine ← sSource.hi, wordsPerLine];
samples[k] ← LOOPHOLE[line, Pointer2][fSource.hi];
sSource.lc ← sSource.lc+sfDelta.lc; fSource.lc ← fSource.lc+ffDelta.lc;
IF NOT sSource.hi<sMax THEN sSource.hi ← sSource.hi-sSize;
IF NOT fSource.hi<fMax THEN fSource.hi ← fSource.hi-fSize;
ENDLOOP;
3 => FOR k: NAT IN[0..count) DO
IF sLine#sSource.hi THEN line ← base+Basics.LongMult[sLine ← sSource.hi, wordsPerLine];
samples[k] ← LOOPHOLE[line, Pointer3][fSource.hi];
sSource.lc ← sSource.lc+sfDelta.lc; fSource.lc ← fSource.lc+ffDelta.lc;
IF NOT sSource.hi<sMax THEN sSource.hi ← sSource.hi-sSize;
IF NOT fSource.hi<fMax THEN fSource.hi ← fSource.hi-fSize;
ENDLOOP;
4 => FOR k: NAT IN[0..count) DO
IF sLine#sSource.hi THEN line ← base+Basics.LongMult[sLine ← sSource.hi, wordsPerLine];
samples[k] ← LOOPHOLE[line, Pointer4][fSource.hi];
sSource.lc ← sSource.lc+sfDelta.lc; fSource.lc ← fSource.lc+ffDelta.lc;
IF NOT sSource.hi<sMax THEN sSource.hi ← sSource.hi-sSize;
IF NOT fSource.hi<fMax THEN fSource.hi ← fSource.hi-fSize;
ENDLOOP;
ENDCASE => ERROR
ELSE ERROR;
};
GetInterpolatedSamples: PUBLIC PROC [sampler: Sampler, sDest, fDest: CARDINAL,
samples: Samples, startIndex: NAT ← 0, count: NAT] ~ TRUSTED {
lgEntry: LgEntry ~ lgArray[sampler.bitsPerSample];
base: LONG POINTER ~ sampler.base;
wordsPerLine: CARDINAL ~ sampler.wordsPerLine;
line: LONG POINTER ← base;
sLine: CARDINAL ← 0;
sSize: CARDINAL ~ sampler.sSize;
fSize: CARDINAL ~ sampler.fSize;
sfDelta: Basics.LongNumber ~ sampler.sfDelta;
ffDelta: Basics.LongNumber ~ sampler.ffDelta;
sSource: Basics.LongNumber ← sampler.sSource0;
fSource: Basics.LongNumber ← sampler.fSource0;
sDest0: CARDINAL ← sampler.sDest;
fDest0: CARDINAL ← sampler.fDest0;
IF sDest0=sDest THEN {
sSource ← sampler.sSource1;
fSource ← sampler.fSource1;
fDest0 ← sampler.fDest1;
}
ELSE {
ssDelta: Basics.LongNumber ~ sampler.ssDelta;
fsDelta: Basics.LongNumber ~ sampler.fsDelta;
WHILE sDest0<sDest DO
sSource.lc ← sSource.lc+ssDelta.lc;
fSource.lc ← fSource.lc+fsDelta.lc;
IF NOT sSource.hi<sSize THEN sSource.hi ← sSource.hi-sSize;
IF NOT fSource.hi<fSize THEN fSource.hi ← fSource.hi-fSize;
sDest0 ← sDest0+1;
ENDLOOP;
sampler.sSource0 ← sSource;
sampler.fSource0 ← fSource;
sampler.sDest ← sDest0;
};
WHILE fDest0<fDest DO
sSource.lc ← sSource.lc+sfDelta.lc;
fSource.lc ← fSource.lc+ffDelta.lc;
IF NOT sSource.hi<sSize THEN sSource.hi ← sSource.hi-sSize;
IF NOT fSource.hi<fSize THEN fSource.hi ← fSource.hi-fSize;
fDest0 ← fDest0+1;
ENDLOOP;
IF sDest<sDest0 OR fDest<fDest0 THEN ERROR;
IF lgEntry.powerOfTwo THEN {
lgBitsPerSample: [0..4] ~ lgEntry.lg;
s: Scaled.Value ← LOOPHOLE[sSource];
f: Scaled.Value ← LOOPHOLE[fSource];
sDelta: Scaled.Value ← LOOPHOLE[ffDelta];
fDelta: Scaled.Value ← LOOPHOLE[ffDelta];
normalDelta: INTINT[sDelta.Floor]*wordsPerLine;
j: CARDINAL ← 0;
WHILE j < pixelSeq.fSize DO
IF NOT s.LESS[sMin] AND s.LESS[sMax] AND NOT f.LESS[fMin] AND f.LESS[fMax] THEN TRUSTED {
ss: Scaled.Value ← s.MINUS[Scaled.half];
ff: Scaled.Value ← f.MINUS[Scaled.half];
ssFloor: INTEGER ← ss.Floor;
lineOffset: INTINT[ss.Floor - source.sOrigin]*wordsPerLine;
toGo: INT ← pixelSeq.fSize-j;
IF sDelta.GREATER[Scaled.zero] THEN {
toGo ← MIN[toGo, TruncDiv[sMax.MINUS[s], sDelta]];
};
IF sDelta.LESS[Scaled.zero] THEN {
toGo ← MIN[toGo, TruncDiv[s.MINUS[sMin], sDelta.UMINUS]];
};
IF fDelta.GREATER[Scaled.zero] THEN {
toGo ← MIN[toGo, TruncDiv[fMax.MINUS[f], fDelta]];
};
IF fDelta.LESS[Scaled.zero] THEN {
toGo ← MIN[toGo, TruncDiv[f.MINUS[fMin], fDelta.UMINUS]];
};
THROUGH [0..INTEGER[toGo]) DO
k: INTEGER ← ff.Floor - source.fOrigin;
a: CARDINAL ← ss.fraction;
b: CARDINAL ← ff.fraction;
ab: CARDINAL ← Basics.HighHalf[Basics.LongMult[a, b]];
v00, v01, v10, v11: CARDINAL;
SELECT lgBitsPerPixel FROM
0 => {
p: LONG POINTER TO RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF [0..2)] ← LOOPHOLE[base + lineOffset];
v00 ← p[k]; v01 ← p[k + 1];
p ← p + wordsPerLine; v10 ← p[k]; v11 ← p[k + 1];
};
1 => {
p: LONG POINTER TO RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF [0..4)] ← LOOPHOLE[base + lineOffset];
v00 ← p[k]; v01 ← p[k + 1];
p ← p + wordsPerLine; v10 ← p[k]; v11 ← p[k + 1];
};
2 => {
p: LONG POINTER TO RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF [0..16)] ← LOOPHOLE[base + lineOffset];
v00 ← p[k]; v01 ← p[k + 1];
p ← p + wordsPerLine; v10 ← p[k]; v11 ← p[k + 1];
};
3 => {
p: LONG POINTER TO RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF [0..256)] ← LOOPHOLE[base + lineOffset];
v00 ← p[k]; v01 ← p[k + 1];
p ← p + wordsPerLine; v10 ← p[k]; v11 ← p[k + 1];
};
4 => {
p: LONG POINTER TO RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF CARDINAL] ← LOOPHOLE[base + lineOffset];
v00 ← p[k]; v01 ← p[k + 1];
p ← p + wordsPerLine; v10 ← p[k]; v11 ← p[k + 1];
};
ENDCASE => ERROR;
IF multiplier # 1 OR lgScale # 0 THEN {
v00 ← Basics.BITSHIFT[v00*multiplier, lgScale];
v01 ← Basics.BITSHIFT[v01*multiplier, lgScale];
v10 ← Basics.BITSHIFT[v10*multiplier, lgScale];
v11 ← Basics.BITSHIFT[v11*multiplier, lgScale];
};
pixelSeq[j] ← IF a=0 AND b=0 THEN v00 ELSE Basics.HighHalf[
Basics.LongMult[CARDINAL.LAST-a+ab-b+1, v00] +
Basics.LongMult[b-ab, v01] +
Basics.LongMult[a-ab, v10] +
Basics.LongMult[ab, v11]
];
ss ← LOOPHOLE[LOOPHOLE[ss, INT]+LOOPHOLE[sDelta, INT]];
ff ← LOOPHOLE[LOOPHOLE[ff, INT]+LOOPHOLE[fDelta, INT]];
lineOffset ← lineOffset + normalDelta;
ssFloor ← ssFloor + sDelta.Floor;
IF ssFloor < ss.Floor THEN {
ssFloor ← ssFloor + 1;
lineOffset ← lineOffset + wordsPerLine;
};
j ← j + 1;
ENDLOOP;
s ← ss.PLUS[Scaled.half];
f ← ff.PLUS[Scaled.half];
IF ssFloor # ss.Floor THEN ERROR;
};
IF j < pixelSeq.fSize THEN {
WHILE s.Floor < 0 DO s ← s.PLUS[Scaled.FromInt[sPixels]] ENDLOOP;
WHILE s.Floor >= sPixels DO s ← s.MINUS[Scaled.FromInt[sPixels]] ENDLOOP;
WHILE f.Floor < 0 DO f ← f.PLUS[Scaled.FromInt[fPixels]] ENDLOOP;
WHILE f.Floor >= fPixels DO f ← f.MINUS[Scaled.FromInt[fPixels]] ENDLOOP;
IF s.Floor IN [rect.sMin..rect.sMin+rect.sSize) AND f.Floor IN [rect.fMin..rect.fMin+rect.fSize) THEN {
pix: CARDINAL ← source.GetPixel[s.Floor, f.Floor];
pixelSeq[j] ← Basics.BITSHIFT[pix*multiplier, lgScale];
};
s ← s.PLUS[sDelta];
f ← f.PLUS[fDelta];
j ← j + 1;
};
ENDLOOP;
}
ELSE ERROR;
sampler.sSource1 ← sSource;
sampler.fSource1 ← fSource;
sampler.fDest1 ← fDest0+count;
};
Hi: PROC [a: CARDINAL] RETURNS [CARDINAL]
~ INLINE {RETURN[Basics.BITSHIFT[a, 1-bitsPerWord]]};
Shift: PROC [a: CARDINAL, amt: INTEGER] RETURNS [CARDINAL]
~ INLINE {RETURN[Basics.BITSHIFT[a, amt]]};
SixteenWords: TYPE ~ MACHINE DEPENDENT RECORD [
w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15: CARDINAL
];
UnsafeHalftone: PUBLIC UNSAFE PROC [
samples, thresholds: UnsafeSamples, count: NAT,
base: LONG POINTER, wordsPerLine: NAT, s, f: NAT ← 0,
invertOutput: BOOLFALSE, transparent: BOOLFALSE
] ~ UNCHECKED {
linePointer: LONG POINTER ~ base+Basics.LongMult[s, wordsPerLine];
bitOffset: CARDINAL ~ f;
p: LONG POINTER TO SixteenWords ← LOOPHOLE[@samples[0]];
q: LONG POINTER TO SixteenWords ← LOOPHOLE[@thresholds[0]];
allInvert: CARDINALIF invertOutput THEN LAST[CARDINAL] ELSE 0;
GetN: UNSAFE PROC [n: [0..16)] RETURNS [CARDINAL] ~ UNCHECKED {
w: CARDINAL ← 0;
THROUGH [0..n) DO
w ← w*2 + Hi[p^.w0-q^.w0];
p ← p + 1;
q ← q + 1;
ENDLOOP;
RETURN [Basics.BITXOR[w, Basics.BITSHIFT[allInvert, n-16]]];
}; -- GetFirst
Get16: UNSAFE PROC RETURNS [CARDINAL] ~ UNCHECKED {
s, h: SixteenWords;
s ← p^; p ← p + SIZE[SixteenWords];
h ← q^; q ← q + SIZE[SixteenWords];
RETURN [Basics.BITXOR[allInvert, ((((((((((((((Hi[s.w0-h.w0]*2+Hi[s.w1-h.w1])*2+Hi[s.w2-h.w2])*2+Hi[s.w3-h.w3])*2+Hi[s.w4-h.w4])*2+Hi[s.w5-h.w5])*2+Hi[s.w6-h.w6])*2+Hi[s.w7-h.w7])*2+Hi[s.w8-h.w8])*2+Hi[s.w9-h.w9])*2+Hi[s.w10-h.w10])*2+Hi[s.w11-h.w11])*2+Hi[s.w12-h.w12])*2+Hi[s.w13-h.w13])*2+Hi[s.w14-h.w14])*2+Hi[s.w15-h.w15]]]
}; -- Get16
d: LONG POINTER TO CARDINALLOOPHOLE[linePointer + bitOffset/16];
IF transparent THEN {
IF bitOffset MOD 16 # 0 THEN {
firstBits: INTEGER ← 16-(bitOffset MOD 16);
z: INTEGERMAX[firstBits-INTEGER[count], 0];
d^ ← Basics.BITOR[d^, Shift[GetN[firstBits-z], z]];
d ← d + 1;
count ← count - (firstBits-z);
};
WHILE count >= 16 DO
d^ ← Basics.BITOR[d^, Get16[]];
d ← d + 1;
count ← count - 16;
ENDLOOP;
IF count > 0 THEN {
d^ ← Basics.BITOR[d^, Shift[GetN[count], 16-count]];
};
}
ELSE {
IF bitOffset MOD 16 # 0 THEN {
firstBits: INTEGER ← 16-(bitOffset MOD 16);
z: INTEGERMAX[firstBits-INTEGER[count], 0];
m: CARDINAL ← Shift[1, firstBits] - Shift[1, z];
d^ ← Basics.BITOR[Basics.BITAND[d^, Basics.BITNOT[m]], Shift[GetN[firstBits-z], z]];
d ← d + 1;
count ← count - (firstBits-z);
};
WHILE count >= 16 DO
d^ ← Get16[];
d ← d + 1;
count ← count - 16;
ENDLOOP;
IF count > 0 THEN {
d^ ← Basics.BITOR[Basics.BITAND[d^, Shift[1, 16-count]-1], Shift[GetN[count], 16-count]];
};
};
};
END.