PixelMapOpsImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Michael Plass, November 27, 1985 7:14:20 pm PST
DIRECTORY Basics, ImagerPixelMap, ImagerSample, PixelMapOps, PrincOps, PrincOpsUtils, Real, AIS, Rope;
PixelMapOpsImpl: CEDAR PROGRAM
IMPORTS Basics, ImagerPixelMap, ImagerSample, PrincOpsUtils, Real
EXPORTS PixelMapOps
~ 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;
ROPE: TYPE ~ Rope.ROPE;
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: BOOLFALSE, transparent: BOOLFALSE] ~ 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: 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
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 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]];
};
};
};
BoxFilter: PUBLIC PROC [pixelMap: PixelMap, sSizeBox, fSizeBox: [0..256), wrap: BOOLTRUE] ~ {
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];
};
END.