DIRECTORY
Basics USING [BITSHIFT, NonNegative],
ImagerPixel USING [PixelBuffer, PixelMap, PixelMapRep],
ImagerPixelArray USING [ErrorDesc, maxCount, maxVec, PixelArray, PixelArrayClassRep, PixelArrayRep],
ImagerPixelArrayPrivate USING [CopyProc, GetProc, GetSamplesProc, MaxSampleValueProc, PixelArrayClass, PixelArrayClassRep, TransferProc],
ImagerSample USING [BasicTransfer, Copy, DoWithScratchMap, DoWithScratchSamples, Function, Get, GetBitsPerSample, GetBox, GetSamples, maxBitsPerSample, maxCount, NewSampleMap, nullFunction, Put, PutSamples, ReIndex, Sample, SampleBuffer, SampleMap],
ImagerTransformation USING [Equal, ScanMode, SFToXY, Transformation],
RuntimeError USING [BoundsFault],
SF USING [Box, Inside, Min, Neg, Size, Sub, Vec, zeroVec];
~
BEGIN
OPEN ImagerPixelArrayPrivate, ImagerPixelArray;
Vec: TYPE ~ SF.Vec;
Transformation: TYPE ~ ImagerTransformation.Transformation;
ScanMode: TYPE ~ ImagerTransformation.ScanMode;
Sample: TYPE ~ ImagerSample.Sample;
SampleBuffer: TYPE ~ ImagerSample.SampleBuffer;
PixelBuffer: TYPE ~ ImagerPixel.PixelBuffer;
SampleMap: TYPE ~ ImagerSample.SampleMap;
PixelMap: TYPE ~ ImagerPixel.PixelMap;
PixelMapRep: TYPE ~ ImagerPixel.PixelMapRep;
Function: TYPE ~ ImagerSample.Function;
nullFunction: Function ~ ImagerSample.nullFunction;
zeroVec: SF.Vec ~ SF.zeroVec;
PixelArrayClass: TYPE ~ ImagerPixelArrayPrivate.PixelArrayClass;
PixelArrayClassRep: PUBLIC TYPE ~ ImagerPixelArrayPrivate.PixelArrayClassRep;
Error: PUBLIC ERROR [error: ErrorDesc] ~ CODE;
BoundsCheck:
PROC [arg:
INT, limit:
NAT]
RETURNS [sameArg:
NAT] ~
INLINE {
IF LOOPHOLE[arg, CARD] >= CARD[limit] THEN ERROR RuntimeError.BoundsFault;
RETURN [arg]
};
GetClass:
PUBLIC
PROC [pa: PixelArray]
RETURNS [
ATOM] ~ {
class: PixelArrayClass ~ pa.class;
RETURN[class.type];
};
MaxSampleValue:
PUBLIC
PROC [pa: PixelArray, i:
NAT]
RETURNS [Sample] ~ {
class: PixelArrayClass ~ pa.class;
RETURN class.MaxSampleValue[pa: pa, i: BoundsCheck[i, pa.samplesPerPixel]];
};
Get:
PUBLIC
PROC [pa: PixelArray, i:
NAT, s, f:
INT]
RETURNS [Sample] ~ {
class: PixelArrayClass ~ pa.class;
iCheck: NAT ~ BoundsCheck[i, pa.samplesPerPixel];
sRem: INT ~ Basics.NonNegative[pa.sSize-Basics.NonNegative[s]];
fRem: INT ~ Basics.NonNegative[pa.fSize-Basics.NonNegative[f]];
[] ¬ Basics.NonNegative[sRem-1];
[] ¬ Basics.NonNegative[fRem-1];
RETURN class.Get[pa: pa, i: i, s: s, f: f];
};
GetSamples:
PUBLIC
PROC [pa: PixelArray, i:
NAT ¬ 0, s, f:
INT ¬ 0,
buffer: SampleBuffer, start:
NAT ¬ 0, count:
NAT ¬ maxCount] ~ {
class: PixelArrayClass ~ pa.class;
iCheck: NAT ~ BoundsCheck[i, pa.samplesPerPixel];
sRem: INT ~ Basics.NonNegative[pa.sSize-Basics.NonNegative[s]];
fRem: INT ~ Basics.NonNegative[pa.fSize-Basics.NonNegative[f]];
actualCount: NAT ~ MIN[buffer.length-start, count];
[] ¬ Basics.NonNegative[sRem-1];
[] ¬ Basics.NonNegative[fRem-actualCount];
class.GetSamples[pa: pa, i: i, s: s, f: f, buffer: buffer, start: start, count: actualCount];
};
GetPixels:
PUBLIC
PROC [pa: PixelArray, s, f:
INT ¬ 0,
pixels: PixelBuffer, start:
NAT ¬ 0, count:
NAT ¬ maxCount] ~ {
FOR i:
NAT
IN[0..pa.samplesPerPixel)
DO
GetSamples[pa, i, s, f, pixels[i], start, count]
ENDLOOP
};
Transfer:
PUBLIC
PROC [pa: PixelArray, i:
NAT ¬ 0, s, f:
INT ¬ 0, dst: SampleMap, dstMin: Vec ¬ zeroVec, size: Vec ¬ maxVec, function: Function ¬ nullFunction] ~ {
class: PixelArrayClass ~ pa.class;
iCheck: NAT ~ BoundsCheck[i, pa.samplesPerPixel];
sRem: INT ~ Basics.NonNegative[pa.sSize-Basics.NonNegative[s]];
fRem: INT ~ Basics.NonNegative[pa.fSize-Basics.NonNegative[f]];
dstBox: SF.Box ~ ImagerSample.GetBox[dst];
actualSize: Vec ¬ dstBox.max.Sub[dstMin].Min[size];
IF sRem<actualSize.s THEN actualSize.s ¬ sRem;
IF fRem<actualSize.f THEN actualSize.f ¬ fRem;
class.Transfer[pa: pa, i: i, s: s, f: f, dst: dst, dstMin: dstMin, size: actualSize, function: function];
};
BitsPerSampleFromMaxSample:
PROC [maxSample:
CARD]
RETURNS [bitsPerSample:
NAT ¬ 0] ~ {
UNTIL maxSample = 0
DO
bitsPerSample ¬ bitsPerSample + 1;
maxSample ¬ maxSample / 2;
ENDLOOP;
};
Copy:
PUBLIC
PROC [pa: PixelArray]
RETURNS [PixelArray] ~ {
class: PixelArrayClass ~ pa.class;
SELECT
TRUE
FROM
pa.immutable => RETURN [pa];
class.Copy#NIL => RETURN [class.Copy[pa]];
ENDCASE => {
samplesPerPixel: NAT ~ pa.samplesPerPixel;
pm: PixelMapData ~ NEW[PixelMapRep[samplesPerPixel]];
sSize: INT ~ pa.sSize;
fSize: INT ~ pa.fSize;
pm.box ¬ [max: [s: sSize, f: fSize]];
FOR i:
NAT
IN[0..samplesPerPixel)
DO
bitsPerSample: NAT ~ BitsPerSampleFromMaxSample[MaxSampleValue[pa, i]];
sm: SampleMap ~ ImagerSample.NewSampleMap[box: pm.box, bitsPerSample: bitsPerSample];
Transfer[pa: pa, i: i, dst: sm];
pm[i] ¬ sm;
ENDLOOP;
RETURN[New[class: pixelMapClass, data: pm, immutable:
TRUE,
samplesPerPixel: samplesPerPixel, sSize: sSize, fSize: fSize, m: pa.m]];
};
};
GetViaGetSamples:
PROC [pa: PixelArray, i:
NAT, s, f:
INT]
RETURNS [Sample] ~ {
class: PixelArrayClass ~ pa.class;
value: Sample ¬ 0;
action:
PROC [buffer: SampleBuffer] ~ {
class.GetSamples[pa: pa, i: i, s: s, f: f, buffer: buffer, start: 0, count: 1];
value ¬ buffer[0];
};
ImagerSample.DoWithScratchSamples[1, action];
RETURN[value];
};
GetViaTransfer:
PROC [pa: PixelArray, i:
NAT, s, f:
INT]
RETURNS [Sample] ~ {
class: PixelArrayClass ~ pa.class;
value: Sample ¬ 0;
action:
PROC [map: SampleMap] ~ {
class.Transfer[pa: pa, i: i, s: s, f: f, dst: map, dstMin: [0, 0], size: [1, 1],
function: [null, null]];
value ¬ ImagerSample.Get[map: map, index: [0, 0]];
};
ImagerSample.DoWithScratchMap[[[0,0], [1, 1]], ImagerSample.maxBitsPerSample, action];
RETURN[value];
};
GetSamplesViaGet:
PROC [pa: PixelArray, i:
NAT, s, f:
INT,
buffer: SampleBuffer, start:
NAT, count:
NAT] ~ {
class: PixelArrayClass ~ pa.class;
FOR k:
NAT
IN[0..count)
DO
buffer[start+k] ¬ class.Get[pa: pa, i: i, s: s, f: f+k];
ENDLOOP;
};
GetSamplesViaTransfer:
PROC [pa: PixelArray, i:
NAT, s, f:
INT,
buffer: SampleBuffer, start:
NAT, count:
NAT] ~ {
class: PixelArrayClass ~ pa.class;
action:
PROC [map: SampleMap] ~ {
class.Transfer[pa: pa, i: i, s: s, f: f, dst: map, dstMin: [0, 0], size: [s: 1, f: count],
function: [null, null]];
ImagerSample.GetSamples[map: map, buffer: buffer, start: start, count: count];
};
ImagerSample.DoWithScratchMap[[[0, 0], [s: 1, f: count]], ImagerSample.maxBitsPerSample, action];
};
TransferViaGet:
PROC [pa: PixelArray, i:
NAT, s, f:
INT,
dst: SampleMap, dstMin: Vec, size: Vec, function: Function] ~ {
class: PixelArrayClass ~ pa.class;
FOR ks:
NAT
IN[0..size.s)
DO
FOR kf:
NAT
IN[0..size.f)
DO
value: Sample ~ class.Get[pa: pa, i: i, s: s+ks, f: f+kf];
ImagerSample.Put[map: dst, index: [s: dstMin.s+ks, f: dstMin.f+kf], value: value, function: function];
ENDLOOP;
ENDLOOP;
};
TransferViaGetSamples:
PROC [pa: PixelArray, i:
NAT, s, f:
INT,
dst: SampleMap, dstMin: Vec, size: Vec, function: Function] ~ {
class: PixelArrayClass ~ pa.class;
action:
PROC [buffer: SampleBuffer] ~ {
FOR k:
NAT
IN[0..size.s)
DO
class.GetSamples[pa: pa, i: i, s: s+k, f: f, buffer: buffer, start: 0, count: size.f];
ImagerSample.PutSamples[map: dst, initIndex: [s: dstMin.s+k, f: dstMin.f], delta: [s: 0, f: 1], buffer: buffer, function: function];
ENDLOOP;
};
ImagerSample.DoWithScratchSamples[size.f, action];
};
NewClass:
PUBLIC
PROC [type:
ATOM,
MaxSampleValue: MaxSampleValueProc,
Get: GetProc ¬
NIL,
GetSamples: GetSamplesProc ¬
NIL,
Transfer: TransferProc ¬
NIL,
Copy: CopyProc ¬
NIL
]
RETURNS [PixelArrayClass] ~ {
class: PixelArrayClass ~
NEW[PixelArrayClassRep ¬ [
type: type,
MaxSampleValue: MaxSampleValue,
Get: Get,
GetSamples: GetSamples,
Transfer: Transfer,
Copy: Copy
]];
IF Get=
NIL
THEN
SELECT
TRUE
FROM
GetSamples#NIL => class.Get ¬ GetViaGetSamples;
Transfer#NIL => class.Get ¬ GetViaTransfer;
ENDCASE;
IF GetSamples=
NIL
THEN
SELECT
TRUE
FROM
Transfer#NIL => class.GetSamples ¬ GetSamplesViaTransfer;
Get#NIL => class.GetSamples ¬ GetSamplesViaGet;
ENDCASE;
IF Transfer=
NIL
THEN
SELECT
TRUE
FROM
GetSamples#NIL => class.Transfer ¬ TransferViaGetSamples;
Get#NIL => class.Transfer ¬ TransferViaGet;
ENDCASE;
RETURN[class];
};
New:
PUBLIC
PROC [class: PixelArrayClass, data:
REF, immutable:
BOOL, samplesPerPixel:
NAT, sSize, fSize:
INT, m: Transformation]
RETURNS [PixelArray] ~ {
RETURN[NEW[PixelArrayRep ¬ [immutable: immutable, samplesPerPixel: samplesPerPixel,
sSize: Basics.NonNegative[sSize], fSize: Basics.NonNegative[fSize],
m: m, class: class, data: data]]];
};
Layer: TYPE ~ RECORD [base: PixelArray, i: NAT];
extractedClass: PixelArrayClass ~ NewClass[
type: $Extracted,
MaxSampleValue: ExtractedMaxSampleValue,
Get: ExtractedGet,
GetSamples: ExtractedGetSamples,
Transfer: ExtractedTransfer
];
ExtractedData: TYPE ~ REF ExtractedDataRep;
ExtractedDataRep:
TYPE ~
RECORD [
base: PixelArray,
select: SEQUENCE samplesPerPixel: NAT OF NAT
];
ExtractedLayer:
PROC [data: ExtractedData, i:
NAT]
RETURNS [Layer] ~ {
RETURN[[base: data.base, i: data.select[i]]];
};
ExtractedMaxSampleValue: MaxSampleValueProc ~ {
data: ExtractedData ~ NARROW[pa.data];
layer: Layer ~ ExtractedLayer[data, i];
class: PixelArrayClass ~ layer.base.class;
RETURN class.MaxSampleValue[pa: layer.base, i: layer.i];
};
ExtractedGet: GetProc ~ {
data: ExtractedData ~ NARROW[pa.data];
layer: Layer ~ ExtractedLayer[data, i];
class: PixelArrayClass ~ layer.base.class;
RETURN class.Get[pa: layer.base, i: layer.i, s: s, f: f];
};
ExtractedGetSamples: GetSamplesProc ~ {
data: ExtractedData ~ NARROW[pa.data];
layer: Layer ~ ExtractedLayer[data, i];
class: PixelArrayClass ~ layer.base.class;
class.GetSamples[pa: layer.base, i: layer.i,
s: s, f: f, buffer: buffer, start: start, count: count];
};
ExtractedTransfer: TransferProc ~ {
data: ExtractedData ~ NARROW[pa.data];
layer: Layer ~ ExtractedLayer[data, i];
class: PixelArrayClass ~ layer.base.class;
class.Transfer[pa: layer.base, i: layer.i,
s: s, f: f, dst: dst, dstMin: dstMin, size: size, function: function];
};
Extract:
PUBLIC
PROC [old: PixelArray, samplesPerPixel:
NAT, select:
PROC [
NAT]
RETURNS [
NAT]]
RETURNS [new: PixelArray] ~ {
data: ExtractedData ~ NEW[ExtractedDataRep[samplesPerPixel]];
data.base ¬ old;
FOR i:
NAT
IN [0..data.samplesPerPixel)
DO
data.select[i] ¬ BoundsCheck[select[i], old.samplesPerPixel];
ENDLOOP;
RETURN[New[class: extractedClass, data: data, immutable: old.immutable,
samplesPerPixel: samplesPerPixel, sSize: old.sSize, fSize: old.fSize, m: old.m]];
};
joinedClass: PixelArrayClass ~ NewClass[
type: $Joined,
MaxSampleValue: JoinedMaxSampleValue,
Get: JoinedGet,
GetSamples: JoinedGetSamples,
Transfer: JoinedTransfer
];
JoinedData:
TYPE ~
LIST
OF PixelArray;
JoinedLayer:
PROC [data: JoinedData, i:
NAT]
RETURNS [Layer] ~ {
FOR each:
LIST
OF PixelArray ¬ data, each.rest
UNTIL each=
NIL
DO
base: PixelArray ~ each.first;
IF i<base.samplesPerPixel THEN RETURN[[base: base, i: i]]
ELSE i ¬ i-base.samplesPerPixel;
ENDLOOP;
ERROR; -- pa.samplesPerPixel was wrong?
};
JoinedMaxSampleValue: MaxSampleValueProc ~ {
data: JoinedData ~ NARROW[pa.data];
layer: Layer ~ JoinedLayer[data, i];
class: PixelArrayClass ~ layer.base.class;
RETURN class.MaxSampleValue[pa: layer.base, i: layer.i];
};
JoinedGet: GetProc ~ {
data: JoinedData ~ NARROW[pa.data];
layer: Layer ~ JoinedLayer[data, i];
class: PixelArrayClass ~ layer.base.class;
RETURN class.Get[pa: layer.base, i: layer.i, s: s, f: f];
};
JoinedGetSamples: GetSamplesProc ~ {
data: JoinedData ~ NARROW[pa.data];
layer: Layer ~ JoinedLayer[data, i];
class: PixelArrayClass ~ layer.base.class;
class.GetSamples[pa: layer.base, i: layer.i,
s: s, f: f, buffer: buffer, start: start, count: count];
};
JoinedTransfer: TransferProc ~ {
data: JoinedData ~ NARROW[pa.data];
layer: Layer ~ JoinedLayer[data, i];
class: PixelArrayClass ~ layer.base.class;
class.Transfer[pa: layer.base, i: layer.i,
s: s, f: f, dst: dst, dstMin: dstMin, size: size, function: function];
};
Join:
PUBLIC
PROC [list:
LIST
OF PixelArray]
RETURNS [PixelArray] ~ {
immutable: BOOL ¬ TRUE;
samplesPerPixel: NAT ¬ 0;
sSize, fSize: INT ¬ 0;
m: Transformation ¬ NIL;
FOR each:
LIST
OF PixelArray ¬ list, each.rest
UNTIL each=
NIL
DO
pa: PixelArray ~ each.first;
immutable ¬ immutable AND pa.immutable;
samplesPerPixel ¬ samplesPerPixel+pa.samplesPerPixel;
IF each=list THEN { sSize ¬ pa.sSize; fSize ¬ pa.fSize; m ¬ pa.m } -- first one
ELSE {
IF NOT(pa.sSize=sSize AND pa.fSize=fSize) THEN ERROR Error[[
code: $incompatibleJoin, explanation: "Sizes do not match"]];
IF NOT pa.m.Equal[m] THEN ERROR Error[[
code: $incompatibleJoin, explanation: "Transformations do not match"]];
};
ENDLOOP;
RETURN[New[class: joinedClass, data: list, immutable: immutable,
samplesPerPixel: samplesPerPixel, sSize: sSize, fSize: fSize, m: m]];
};
Join3:
PUBLIC
PROC [pa1, pa2, pa3: PixelArray]
RETURNS [PixelArray] ~ {
RETURN[Join[LIST[pa1, pa2, pa3]]];
};
pixelMapClass: PixelArrayClass ~ NewClass[
type: $PixelMap,
MaxSampleValue: PixelMapMaxSampleValue,
Get: PixelMapGet,
GetSamples: PixelMapGetSamples,
Transfer: PixelMapTransfer,
Copy: PixelMapCopy
];
PixelMapData:
TYPE ~ PixelMap;
PixelMapMaxSampleValue: MaxSampleValueProc ~ {
data: PixelMapData ~ NARROW[pa.data];
map: SampleMap ~ data[i];
RETURN[Basics.BITSHIFT[1, ImagerSample.GetBitsPerSample[map]]-1];
};
PixelMapGet: GetProc ~ {
data: PixelMapData ~ NARROW[pa.data];
map: SampleMap ~ data[i];
index: Vec ~ [s: s, f: f];
RETURN[map.Get[index]];
};
PixelMapGetSamples: GetSamplesProc ~ {
data: PixelMapData ~ NARROW[pa.data];
map: SampleMap ~ data[i];
index: Vec ~ [s: s, f: f];
ImagerSample.GetSamples[map: map, initIndex: index, buffer: buffer, start: start, count: count];
};
PixelMapTransfer: TransferProc ~ {
data: PixelMapData ~ NARROW[pa.data];
map: SampleMap ~ data[i];
index: Vec ~ [s: s, f: f];
ImagerSample.BasicTransfer[dst: dst, src: map, dstMin: dstMin, srcMin: index, size: size, function: function];
};
PixelMapCopy: CopyProc ~ {
data0: PixelMapData ~ NARROW[pa.data];
data1: PixelMapData ~ NEW[PixelMapRep[data0.samplesPerPixel]];
data1.box ¬ data0.box;
FOR i: NAT IN[0..data1.samplesPerPixel) DO data1[i] ¬ ImagerSample.Copy[data0[i]] ENDLOOP;
RETURN[New[class: pixelMapClass, data: data1, immutable:
TRUE,
samplesPerPixel: pa.samplesPerPixel, sSize: pa.sSize, fSize: pa.fSize, m: pa.m]];
};
FromPixelMap:
PUBLIC
PROC [pixelMap: PixelMap, box:
SF.Box, scanMode: ScanMode, immutable:
BOOL]
RETURNS [PixelArray] ~ {
samplesPerPixel: NAT ~ pixelMap.samplesPerPixel;
IF
SF.Inside[box, pixelMap.box]
THEN {
delta: Vec ~ SF.Neg[box.min];
size: Vec ~ SF.Size[box];
m: Transformation ~ ImagerTransformation.SFToXY[scanMode: scanMode, sSize: size.s, fSize: size.f];
new: PixelMap ¬ NEW[PixelMapRep[samplesPerPixel]];
new.box ¬ [max: size];
FOR j:
NAT
IN [0..samplesPerPixel)
DO
new[j] ¬ ImagerSample.ReIndex[map: pixelMap[j], delta: delta, box: [max: size]];
ENDLOOP;
RETURN[New[class: pixelMapClass, data: new, immutable: immutable,
samplesPerPixel: samplesPerPixel, sSize: size.s, fSize: size.f, m: m]];
};
ERROR RuntimeError.BoundsFault;
};