~
BEGIN
DeviceRectangle: TYPE ~ ImagerPixelMap.DeviceRectangle;
PixelMap: TYPE ~ ImagerPixelMap.PixelMap;
PixelMapRep: TYPE ~ ImagerPixelMap.PixelMapRep;
SampleBuffer: TYPE ~ ImagerSample.SampleBuffer;
UnsafeSamples: TYPE ~ ImagerSample.UnsafeSamples;
Sample: TYPE ~ ImagerSample.Sample;
Sampler: TYPE ~ ImagerSample.Sampler;
AISData: TYPE ~ PixelMapOps.AISData;
bitsPerWord: NAT ~ Basics.bitsPerWord;
Check:
PROC[x:
CARDINAL, max:
NAT]
RETURNS[
NAT] ~
TRUSTED MACHINE CODE { PrincOps.zINC; PrincOps.zBNDCK };
IF x IN[0..max] THEN RETURN[x] ELSE ERROR RuntimeError.BoundsFault
GetPointer:
PROC [buffer: SampleBuffer, i, j, count:
NAT]
RETURNS [UnsafeSamples] ~
INLINE {
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]]] };
};
ClearSamples:
PUBLIC
PROC [buffer: SampleBuffer, i, j:
NAT ← 0, count:
NAT] ~
TRUSTED {
pointer: LONG POINTER ~ GetPointer[buffer, i, j, count];
PrincOpsUtils.LongZero[where: pointer, nwords: count*SIZE[Sample]];
};
FillSamples:
PUBLIC
PROC [buffer: SampleBuffer, i, j:
NAT ← 0, count:
NAT, sample: Sample] ~
TRUSTED {
IF count # 0
THEN {
wps: NAT ~ SIZE[Sample];
pointer: UnsafeSamples ~ GetPointer[buffer, i, j, count];
pointer[0] ← sample;
PrincOpsUtils.LongCopy[from: pointer, nwords: (count-1)*wps, to: pointer+wps];
};
};
CopySamples:
PUBLIC
PROC [buffer: SampleBuffer, bi, bj:
NAT ← 0, count:
NAT, source: SampleBuffer, si, sj:
NAT ← 0] ~
TRUSTED {
dst: UnsafeSamples ~ GetPointer[buffer, bi, bj, count];
src: UnsafeSamples ~ GetPointer[source, si, sj, count];
PrincOpsUtils.LongCopy[from: src, nwords: count, to: dst];
};
GetF:
PUBLIC
PROC [pixelMap: PixelMap, s:
INTEGER, f:
INTEGER, buffer: SampleBuffer, bi:
NAT, bj:
NAT, count:
NAT] ~
TRUSTED {
lgbpp: [0..4] ~ pixelMap.refRep.lgBitsPerPixel;
wpl: NAT ~ pixelMap.refRep.rast;
ppl: NAT ~ Basics.BITSHIFT[wpl, 4-lgbpp];
lines: NAT ~ pixelMap.refRep.lines;
sbuf: NAT ~ Basics.BoundsCheck[s-pixelMap.sOrigin, lines];
fbuf: NAT ~ f-pixelMap.fOrigin;
fbufmax: NAT ~ Check[fbuf+count, ppl];
destPointer: UnsafeSamples ~ GetPointer[buffer, bi, bj, count];
ImagerSample.UnsafeGetF[samples: destPointer, count: count, s: sbuf, f: fbuf, base: pixelMap.refRep.pointer, wordsPerLine: wpl, bitsPerSample: Basics.BITSHIFT[1, lgbpp]];
};
PutF:
PUBLIC
PROC [pixelMap: PixelMap, s:
INTEGER, f:
INTEGER, buffer: SampleBuffer, bi:
NAT, bj:
NAT, count:
NAT, srcFunc: PrincOps.SrcFunc ← null, dstFunc: PrincOps.DstFunc ← null] ~
TRUSTED {
lgbpp: [0..4] ~ pixelMap.refRep.lgBitsPerPixel;
wpl: NAT ~ pixelMap.refRep.rast;
ppl: NAT ~ Basics.BITSHIFT[wpl, 4-lgbpp];
lines: NAT ~ pixelMap.refRep.lines;
sbuf: NAT ~ Basics.BoundsCheck[s-pixelMap.sOrigin, lines];
fbuf: NAT ~ f-pixelMap.fOrigin;
fbufmax: NAT ~ Check[fbuf+count, ppl];
sourcePointer: UnsafeSamples ~ GetPointer[buffer, bi, bj, count];
ImagerSample.UnsafePutF[samples: sourcePointer, count: count, s: sbuf, f: fbuf, base: pixelMap.refRep.pointer, wordsPerLine: wpl, bitsPerSample: Basics.BITSHIFT[1, lgbpp], srcFunc: srcFunc, dstFunc: dstFunc];
};
GetS:
PUBLIC
PROC [pixelMap: PixelMap, s:
INTEGER, f:
INTEGER, buffer: SampleBuffer, bi:
NAT, bj:
NAT, count:
NAT] ~
TRUSTED {
lgbpp: [0..4] ~ pixelMap.refRep.lgBitsPerPixel;
wpl: NAT ~ pixelMap.refRep.rast;
ppl: NAT ~ Basics.BITSHIFT[wpl, 4-lgbpp];
lines: NAT ~ pixelMap.refRep.lines;
sbuf: NAT ~ s-pixelMap.sOrigin;
fbuf: NAT ~ Basics.BoundsCheck[f-pixelMap.fOrigin, ppl];
sbufmax: NAT ~ Check[sbuf+count, lines];
destPointer: UnsafeSamples ~ ImagerSample.GetPointer[buffer, bi, bj, count];
ImagerSample.UnsafeGetS[samples: destPointer, count: count, s: sbuf, f: fbuf, base: pixelMap.refRep.pointer, wordsPerLine: wpl, bitsPerSample: Basics.BITSHIFT[1, lgbpp]];
};
PutS:
PUBLIC
PROC [pixelMap: PixelMap, s:
INTEGER, f:
INTEGER, buffer: SampleBuffer, bi:
NAT, bj:
NAT, count:
NAT, srcFunc: PrincOps.SrcFunc ← null, dstFunc: PrincOps.DstFunc ← null] ~
TRUSTED {
lgbpp: [0..4] ~ pixelMap.refRep.lgBitsPerPixel;
wpl: NAT ~ pixelMap.refRep.rast;
ppl: NAT ~ Basics.BITSHIFT[wpl, 4-lgbpp];
lines: NAT ~ pixelMap.refRep.lines;
sbuf: NAT ~ s-pixelMap.sOrigin;
fbuf: NAT ~ Basics.BoundsCheck[f-pixelMap.fOrigin, ppl];
sbufmax: NAT ~ Check[sbuf+count, lines];
sourcePointer: UnsafeSamples ~ ImagerSample.GetPointer[buffer, bi, bj, count];
ImagerSample.UnsafePutS[samples: sourcePointer, count: count, s: sbuf, f: fbuf, base: pixelMap.refRep.pointer, wordsPerLine: wpl, bitsPerSample: Basics.BITSHIFT[1, lgbpp], srcFunc: srcFunc, dstFunc: dstFunc];
};
Halftone:
PUBLIC
PROC [pixelMap: PixelMap, s:
INTEGER, f:
INTEGER, samples, thresholds: UnsafeSamples, count:
NAT, invertOutput:
BOOL ←
FALSE, transparent:
BOOL ←
FALSE] ~
TRUSTED {
lgbpp: [0..0] ~ pixelMap.refRep.lgBitsPerPixel;
wpl: NAT ~ pixelMap.refRep.rast;
ppl: NAT ~ Basics.BITSHIFT[wpl, 4-lgbpp];
lines: NAT ~ pixelMap.refRep.lines;
sbuf: NAT ~ Basics.BoundsCheck[s-pixelMap.sOrigin, lines];
fbuf: NAT ~ f-pixelMap.fOrigin;
fbufmax: NAT ~ Check[fbuf+count, ppl];
UnsafeHalftone[samples: samples, thresholds: thresholds, count: count, base: pixelMap.refRep.pointer, wordsPerLine: wpl, s: sbuf, f: fbuf, invertOutput: invertOutput, transparent: transparent];
};
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:
BOOL ←
FALSE, transparent:
BOOL ←
FALSE] ~
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: CARDINAL ← IF 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
sixteen: [16..16] ~ bitsPerWord;
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 CARDINAL ← LOOPHOLE[linePointer + bitOffset/16];
IF transparent
THEN {
IF bitOffset
MOD 16 # 0
THEN {
firstBits: INTEGER ← 16-(bitOffset MOD 16);
z: INTEGER ← MAX[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: INTEGER ← MAX[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]];
};
};
};
BoxFilter:
PUBLIC
PROC [pixelMap: PixelMap, sSizeBox, fSizeBox: [0..256), wrap:
BOOL ←
TRUE] ~ {
lgbps: [0..3] ~ pixelMap.refRep.lgBitsPerPixel;
IF
LONG[sSizeBox]*fSizeBox*255 >
CARDINAL.
LAST
THEN {
BoxFilter[pixelMap, sSizeBox, 1];
BoxFilter[pixelMap, 1, fSizeBox];
}
ELSE {
unit: LONG CARDINAL ~ LONG[LAST[WORD]]+1;
half: LONG CARDINAL ~ unit/2;
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;
fSize: NAT ~ pixelMap.fSize;
sum: ARRAY [0..256) OF SampleBuffer;
nPixels: CARDINAL ~ Basics.LongMult[sSizeBox, fSizeBox];
nPixelsRecip: CARDINAL ~ Basics.LongDiv[unit, nPixels];
sOrigin: INTEGER ← sStart-2*sSizeBox+sHalf;
result: SampleBuffer ← ImagerSample.NewBuffer[iSize: 1, jSize: fSize];
paddedSize: NAT ← fSize+2*fSizeBox;
MoveToNextRow:
PROC ~ {
t: SampleBuffer ← sum[0];
s: INTEGER ← sOrigin+1+sSizeBox;
IF wrap
THEN {
WHILE s >= sEnd DO s ← s - pixelMap.sSize ENDLOOP;
WHILE s < sStart DO s ← s + pixelMap.sSize ENDLOOP;
}
ELSE {s ← MAX[MIN[s, sEnd-1], sStart]};
FOR i:
NAT
IN [0..sSizeBox)
DO
sum[i] ← sum[i+1];
ENDLOOP;
GetF[pixelMap: pixelMap, s: s, f: fStart, buffer: t, bi: 0, bj: fSizeBox, count: fSize];
IF wrap
THEN {
CopySamples[buffer: t, bi: 0, bj: fSizeBox+fSize, count: fSizeBox, source: t, si: 0, sj: fSizeBox];
CopySamples[buffer: t, bi: 0, bj: 0, count: fSizeBox, source: t, si: 0, sj: fSize];
}
ELSE {
FillSamples[buffer: t, i: 0, j: fSize+fSizeBox, count: fSizeBox, sample: t.GetSample[0, fSize+fSizeBox-1]];
FillSamples[buffer: t, i: 0, j: 0, count: fSizeBox, sample: t.GetSample[0, fSizeBox]];
};
ImagerSample.AddSamples[samples: t, si: 0, sj: 0, buffer: t, bi: 0, bj: 1, count: paddedSize-1]; -- ripple add!
ImagerSample.AddSamples[samples: sum[sSizeBox-1], si: 0, sj: 0, buffer: t, bi: 0, bj: 0, count: paddedSize];
sOrigin ← sOrigin + 1;
sum[sSizeBox] ← t;
};
FOR i:
NAT
IN [0..sSizeBox]
DO
sum[i] ← ImagerSample.NewBuffer[iSize: 1, jSize: paddedSize];
ENDLOOP;
FOR s:
INTEGER
IN [sStart..sEnd)
DO
WHILE sOrigin+sHalf+1 # s DO MoveToNextRow[] ENDLOOP;
TRUSTED {
prevLine: UnsafeSamples ~ ImagerSample.GetPointer[sum[sSizeBox], 0, 0, paddedSize];
curLine: UnsafeSamples ~ ImagerSample.GetPointer[sum[0], 0, 0, paddedSize];
resultLine: UnsafeSamples ~ ImagerSample.GetPointer[result, 0, 0, fSize];
FOR j:
INTEGER
IN [0..fSize)
DO
f0: NAT ~ j+fSizeBox-fHalf;
f1: NAT ~ Basics.BoundsCheck[f0+fSizeBox, paddedSize];
boxSum: Sample ← prevLine[f1] - prevLine[f0] - curLine[f1] + curLine[f0];
val: CARDINAL ~ Basics.HighHalf[Basics.LongMult[boxSum, nPixelsRecip] + half];
resultLine[j] ← val;
ENDLOOP;
};
PutF[pixelMap: pixelMap, s: s, f: fStart, buffer: result, bi: 0, bj: 0, count: fSize, srcFunc: null, dstFunc: null];
ENDLOOP;
};
};
ChangeBitsPerPixel:
PUBLIC
PROC [pixelMap: PixelMap, newLgBitsPerPixel: [0..4], scratch:
REF PixelMapRep ←
NIL]
RETURNS [pm: PixelMap] ~ {
action:
PROC [sampleBuffer: SampleBuffer] ~ {
bounds: DeviceRectangle ~ pixelMap.Window;
new: PixelMap ← ImagerPixelMap.Reshape[scratch, newLgBitsPerPixel, bounds];
FOR s:
INTEGER
IN [bounds.sMin..bounds.sMin+bounds.sSize)
DO
GetF[pixelMap, s, bounds.fMin, sampleBuffer, 0, 0, bounds.fSize];
PutF[new, s, bounds.fMin, sampleBuffer, 0, 0, bounds.fSize, null, null];
ENDLOOP;
};
ImagerSample.DoWithScratchBuffer[1, pixelMap.fSize, action];
};
ChangeContrast:
PUBLIC
PROC [pixelMap: PixelMap, oldminvalue, oldmaxvalue, newminvalue, newmaxvalue:
REAL] ~ {
action:
PROC [sampleBuffer: SampleBuffer] ~
TRUSTED {
bounds: DeviceRectangle ~ pixelMap.Window;
sample: UnsafeSamples ~ GetPointer[sampleBuffer, 0, 0, bounds.fSize];
m: REAL ~ (newmaxvalue-newminvalue)/(oldmaxvalue-oldminvalue);
maxVal: INT ~ CARDINAL[Basics.BITSHIFT[1, Basics.BITSHIFT[1, pixelMap.refRep.lgBitsPerPixel]]-1];
FOR s:
INTEGER
IN [bounds.sMin..bounds.sMin+bounds.sSize)
DO
GetF[pixelMap, s, bounds.fMin, sampleBuffer, 0, 0, bounds.fSize];
FOR j:
NAT
IN [0..bounds.fSize)
DO
pix: REAL ← sample[j];
out: REAL ← (pix-oldminvalue)*m+newminvalue;
sample[j] ← MAX[MIN[Real.Round[out], maxVal], 0];
ENDLOOP;
PutF[pixelMap, s, bounds.fMin, sampleBuffer, 0, 0, bounds.fSize, null, null];
ENDLOOP;
};
ImagerSample.DoWithScratchBuffer[1, pixelMap.fSize, action];
};
ReadAIS: PUBLIC PROC [pixelMap: PixelMap, aisName: ROPE] ~ TRUSTED {
ais: AIS.FRef ← AIS.OpenFile[aisName];
window: AIS.WRef ← AIS.OpenWindow[ais];
raster: AIS.Raster ← AIS.ReadRaster[ais];
lgBitsPerPixel: [0..4] ← SELECT raster.bitsPerPixel FROM
0, 1 => 0,
2 => 1,
4 => 2,
8 => 3,
16 => 4,
ENDCASE => ERROR;
comment: ROPE ~ AIS.ReadComment[ais];
lineMap: PixelMap ← ImagerPixelMap.Create[lgBitsPerPixel, [0, 0, 1, raster.scanLength]];
lineBufferDesc: AIS.Buffer ← [length: lineMap.refRep.words, addr: lineMap.refRep.pointer];
w: DeviceRectangle ← ImagerPixelMap.Window[pixelMap];
FOR i: NAT IN [MAX[w.sMin, 0]..MIN[raster.scanCount, w.sMin+w.sSize]) DO
AIS.UnsafeReadLine[window, lineBufferDesc, i];
pixelMap.Transfer[lineMap];
lineMap.sOrigin ← lineMap.sOrigin + 1;
ENDLOOP;
AIS.CloseWindow[window];
AIS.CloseFile[ais];
};
LoadAIS: PUBLIC PROC [aisName: ROPE] RETURNS [AISData] ~ TRUSTED {
ais: AIS.FRef ← AIS.OpenFile[aisName];
window: AIS.WRef ← AIS.OpenWindow[ais];
raster: AIS.Raster ← AIS.ReadRaster[ais];
lgBitsPerPixel: [0..4] ← SELECT raster.bitsPerPixel FROM
0, 1 => 0,
2 => 1,
4 => 2,
8 => 3,
16 => 4,
ENDCASE => ERROR;
comment: ROPE ~ AIS.ReadComment[ais];
lineMap: PixelMap ← ImagerPixelMap.Create[lgBitsPerPixel, [0, 0, 1, raster.scanLength]];
lineBufferDesc: AIS.Buffer ← [length: lineMap.refRep.words, addr: lineMap.refRep.pointer];
pixelMap: PixelMap ← ImagerPixelMap.Create[lgBitsPerPixel, [0, 0, raster.scanCount, raster.scanLength]];
FOR i: NAT IN [0..raster.scanCount) DO
AIS.UnsafeReadLine[window, lineBufferDesc, i];
pixelMap.Transfer[lineMap];
lineMap.sOrigin ← lineMap.sOrigin + 1;
ENDLOOP;
AIS.CloseWindow[window];
AIS.CloseFile[ais];
RETURN [[
pixelMap: pixelMap,
bitmap: raster.bitsPerPixel=0,
comment: comment
]]
};
StoreAIS: PUBLIC PROC [aisName: ROPE, aisData: AISData] ~ {
source: PixelMap ~ aisData.pixelMap;
output: AIS.FRef ← AIS.CreateFile[name: aisName, raster: NEW[AIS.RasterPart ← [
scanCount: source.sSize,
scanLength: source.fSize,
scanMode: rd,
bitsPerPixel: IF source.refRep.lgBitsPerPixel = 0 AND aisData.bitmap THEN 0 ELSE Basics.BITSHIFT[1, source.refRep.lgBitsPerPixel],
linesPerBlock: -1,
paddingPerBlock: 65535
]]];
outputWindow: AIS.WRef ← AIS.OpenWindow[output];
lineMap: PixelMap ← ImagerPixelMap.Create[source.refRep.lgBitsPerPixel, [source.sOrigin+source.sMin, source.fOrigin+source.fMin, 1, source.fSize]];
lineBufferDesc: AIS.Buffer ← [length: lineMap.refRep.words, addr: lineMap.refRep.pointer];
AIS.WriteComment[output, aisData.comment];
FOR i: NAT IN [0..source.sSize) DO
lineMap.Clear;
lineMap.Transfer[source];
lineMap.sOrigin ← lineMap.sOrigin + 1;
TRUSTED {AIS.UnsafeWriteLine[outputWindow, lineBufferDesc, i]};
ENDLOOP;
AIS.CloseFile[output];
};