PressImageImpl:
CEDAR
PROGRAM
IMPORTS Basics, IO, ImagerPixelMap, ImagerPixelArray, ImagerColorOperator, Imager, ImagerTransformation, SafeStorage, ImagerSample, PrincOpsUtils
EXPORTS PressImage, ImagerPixelArrayDefs
Context: TYPE = Imager.Context;
Transformation: TYPE = ImagerTransformation.Transformation;
PixelArray: TYPE = ImagerPixelArrayDefs.PixelArray;
PixelMap:
TYPE = ImagerPixelMap.PixelMap;
ru: NAT = 2;
rd: NAT = 3;
lu: NAT = 6;
ld: NAT = 7;
ul: NAT = 9;
ur: NAT = 8;
dl: NAT = 13;
TransformationFromScanMode:
PROC [scanMode:
NAT, lines, pixelsPerLine:
INT]
RETURNS [Transformation] ~ {
pixelDeltaX:
REAL ←
SELECT scanMode
FROM
ru, rd => 1,
lu, ld => -1,
ENDCASE => 0;
pixelDeltaY:
REAL ←
SELECT scanMode
FROM
ul, ur => 1,
dr, dl => -1,
ENDCASE => 0;
lineDeltaX:
REAL ←
SELECT scanMode
FROM
dr, ur => 1,
ul, dl => -1,
ENDCASE => 0;
lineDeltaY:
REAL ←
SELECT scanMode
FROM
ru, lu => 1,
ld, rd => -1,
ENDCASE => 0;
RETURN [ImagerTransformation.Create[
a: lineDeltaX,
b: pixelDeltaX,
c: MAX[-(pixelDeltaX*pixelsPerLine + lineDeltaX*lines), 0],
d: lineDeltaY,
e: pixelDeltaY,
f: MAX[-(pixelDeltaY*pixelsPerLine + lineDeltaY*lines), 0]
]]
};
PressImage: PUBLIC TYPE = REF PressImageData;
PressImageData:
PUBLIC
TYPE =
RECORD [
stream: IO.STREAM,
streamIndex: INT,
byteLength: INT,
scanMode: CARDINAL,
scanCount: CARDINAL, -- lines
scanLength: CARDINAL, -- dots
wordsPerLine: CARDINAL, -- words per scan line
passDots: NAT,
displayDots: NAT,
passLines: NAT,
displayLines: NAT,
imageHeight: REAL,
imageWidth: REAL,
lgBitsPerPixel: [0..4],
isBitmap: BOOL
];
PressImageError: PUBLIC ERROR = CODE;
MakePressImage:
PUBLIC
PROC [sampleType, dots, lines, mode, pd, dd, pl, dl:
INT, width, height:
REAL, bits: PressReader.Dots]
RETURNS [self: PressImage ←
NIL] = {
bitsperline: LONG CARDINAL ← Basics.LongMult[dots, IF sampleType IN [1..16] THEN sampleType ELSE 1];
wpl: CARDINAL ← (bitsperline + (bitsPerWord-1)) / bitsPerWord;
lgBitsPerPixel: [0..4] ~
SELECT sampleType
FROM
0, 1 => 0,
2 => 1,
4 => 2,
8 => 3,
16 => 4,
ENDCASE => ERROR PressImageError;
IF bitsperline MOD bitsPerWord # 0 THEN ERROR PressImageError;
self ←
NEW[PressImageData ← [
stream: bits.file,
streamIndex: LONG[bits.pageNumber]*512+bits.byteOffset,
byteLength: bits.length*Basics.bytesPerWord, -- bits.length is in words!
scanMode: mode,
scanCount: lines,
scanLength: dots,
wordsPerLine: wpl,
passDots: pd,
displayDots: dd,
passLines: pl,
displayLines: dl,
imageHeight: height,
imageWidth: width,
lgBitsPerPixel: lgBitsPerPixel,
isBitmap: sampleType = 0
]];
RETURN [self];
};
PixelArrayImpl: TYPE ~ ImagerPixelArrayPrivate.PixelArrayImpl;
PixelArrayImplRep:
PUBLIC
TYPE ~ ImagerPixelArrayPrivate.PixelArrayImplRep;
Concrete representation of PixelArrayImplRep, exported to ImagerPixelArrayDefs.
PixelArrayClass: TYPE ~ REF PixelArrayClassRep;
PixelArrayClassRep:
PUBLIC
TYPE ~ ImagerPixelArrayPrivate.PixelArrayClassRep;
pixelArrayClass: PixelArrayClass ~
NEW[PixelArrayClassRep ← [
type: $PressImage,
MaxSampleValue: MyMaxSampleValue,
UnsafeGetSamples: MyUnsafeGetSamples,
UnsafeGetBits: MyUnsafeGetBits
]];
MyMaxSampleValue:
PROC [pa: PixelArray, i:
NAT]
RETURNS [ImagerPixelArray.Sample] ~ {
impl: PixelArrayImpl ~ pa.impl;
data: REF PixelMap ~ NARROW[pa.data];
pm: PixelMap ~ data^;
lgBitsPerPixel: [0..4] ← pm.refRep.lgBitsPerPixel;
RETURN [Basics.BITSHIFT[1, Basics.BITSHIFT[1, lgBitsPerPixel]]-1]
};
MyUnsafeGetSamples:
UNSAFE
PROC [pa: PixelArray, i:
NAT, s, f:
INT,
samples: ImagerSample.UnsafeSamples, count:
NAT] ~
UNCHECKED {
data: REF PixelMap ~ NARROW[pa.data];
ImagerSample.UnsafeGetF[samples: samples, count: count, base: data.refRep.pointer, wordsPerLine: data.refRep.rast, bitsPerSample: Basics.BITSHIFT[1, data.refRep.lgBitsPerPixel], s: s+data.sOrigin, f: f+data.fOrigin];
};
bitsPerWord: NAT ~ Basics.bitsPerWord;
MyUnsafeGetBits:
UNSAFE
PROC [pa: PixelArray, i:
NAT ← 0, s, f:
INT,
dst: PrincOps.BitAddress, dstBpl:
INTEGER, width, height:
CARDINAL,
srcFunc: PrincOps.SrcFunc ← null, dstFunc: PrincOps.DstFunc ← null] ~
UNCHECKED {
data: REF PixelMap ~ NARROW[pa.data];
source: PixelMap ~ data^;
sStartSource: NAT ~ s-source.sOrigin;
fMinSource: NAT ~ f-source.fOrigin;
bbTableSpace: PrincOps.BBTableSpace;
bb: PrincOps.BBptr ~ PrincOpsUtils.AlignedBBTable[@bbTableSpace];
IF source.refRep.lgBitsPerPixel # 0 THEN ERROR;
bb^ ← [
dstBpl: dstBpl,
srcDesc: [srcBpl[source.refRep.rast*bitsPerWord]],
height: height,
width: width,
flags: [direction: forward, disjoint: TRUE, disjointItems: TRUE, gray: FALSE, srcFunc: srcFunc, dstFunc: dstFunc],
dst: dst,
src: [word: (source.refRep.pointer + Basics.LongMult[sStartSource, source.refRep.rast] + (fMinSource/bitsPerWord)), bit: fMinSource MOD bitsPerWord]
];
PrincOpsUtils.BITBLT[bb];
};
identity: Transformation ~ ImagerTransformation.Scale[1];
MakePixelArray:
PROC [pressImage: PressImage]
RETURNS [ImagerPixelArray.PixelArray] ~ {
pm: PixelMap ~ ImagerPixelMap.Create[lgBitsPerPixel: pressImage.lgBitsPerPixel, bounds: [0, 0, pressImage.scanCount, pressImage.scanLength]];
IF INT[pm.refRep.words*Basics.bytesPerWord] < pressImage.byteLength THEN ERROR PressImageError;
IO.SetIndex[pressImage.stream, pressImage.streamIndex];
TRUSTED {
[] ← IO.UnsafeGetBlock[pressImage.stream, [LOOPHOLE[pm.refRep.pointer], 0, pressImage.byteLength]];
};
RETURN [
NEW[ImagerPixelArrayDefs.PixelArrayRep ← [
samplesPerPixel: 1,
sSize: pressImage.displayLines,
fSize: pressImage.displayDots,
m: TransformationFromScanMode[pressImage.scanMode, pressImage.displayLines, pressImage.displayDots],
impl: NIL,
class: pixelArrayClass,
data: NEW[PixelMap ← pm.ShiftMap[-pressImage.passLines, -pressImage.passDots].Clip[[0,0,pressImage.displayLines, pressImage.displayDots]]]
]]];
};
DrawPressImage:
PUBLIC
PROC [self: Context, image: PressImage] = {
Proc:
PROC ~ {
pa: ImagerPixelArray.PixelArray ~ MakePixelArray[image];
paDimen: Imager.VEC ~ ImagerTransformation.TransformVec[pa.m, [pa.sSize, pa.fSize]];
Imager.Move[self];
Imager.Scale2T[self, [image.imageWidth/ABS[paDimen.x], image.imageHeight/ABS[paDimen.y]]];
IF image.isBitmap
THEN {
WhiteBackground:
PROC ~ {
Imager.SetColor[self, Imager.white];
Imager.MaskRectangle[self, [0, 0, ABS[paDimen.x], ABS[paDimen.y]]];
};
IF TRUE -- NOT show dots opaque -- THEN Imager.DoSave[self, WhiteBackground];
Imager.MaskPixel[context: self, pa: pa];
}
ELSE {
maxSampleValue: INT ~ ImagerPixelArray.MaxSampleValue[pa, 0];
SampleMap:
PROC [cardinal:
CARDINAL]
RETURNS [
REAL] ~ {
RETURN [cardinal]
};
colorOperator: ImagerColorOperator.ColorOperator ~ ImagerColorOperator.GrayLinearColorModel[
sWhite: maxSampleValue,
sBlack: 0.0,
maxSampleValue: maxSampleValue,
sampleMap: SampleMap
];
Imager.SetSampledColor[
context: self,
pa: pa,
m: identity,
colorOperator: colorOperator
];
Imager.MaskRectangle[self, [0, 0, ABS[paDimen.x], ABS[paDimen.y]]];
};
};
Imager.DoSave[self, Proc];
SafeStorage.ReclaimCollectibleObjects[];
};
END.