TSIncludeAISImpl.mesa
Michael Plass, December 19, 1983 12:23 pm
Last edited by Tim Diebert: May 22, 1984 12:02:17 pm PDT
DIRECTORY
CGAIS,
FS,
Real,
Rope,
SirPress,
TSArtwork,
TSOutputPress,
TextNode,
TSGraphic,
IO,
TSOutput,
TSTypes USING [Dimn, zeroDimn, RealDimn, DimnRatio, bp, Dimensions];
TSIncludeAISImpl: CEDAR PROGRAM
IMPORTS FS, Real, Rope, SirPress, TSArtwork, TextNode, IO, TSTypes
= BEGIN OPEN TSTypes;
bytesPerPage: NAT ~ 512; -- as per press file format.
micasPerPoint: REAL = 2540.0/72.0;
pointsPerMica: REAL = 72.0/2540.0;
ObjectFromBranchProc: TYPE = TSArtwork.ObjectFromBranchProc;
ROPE: TYPE = Rope.ROPE;
IncludeAISRec: TYPE = RECORD [aisFileName: ROPE, height, width: REAL ← -1, indent: REAL ← 0, screen: INT ← 85, aisStream: IO.STREAM, wordOffset: INT, rasterPart: CGAIS.RasterPart, uca: CGAIS.UCA];
Break: PROC [char: CHAR] RETURNS [IO.CharClass] = {
IF char = ': THEN RETURN [break];
IF char = ' OR char = '  OR char = ', OR char = '; OR char = '\n THEN RETURN [sepr];
RETURN [other];
};
GetName: PROC [stream: IO.STREAM] RETURNS [name: ROPE] ~ {
name ← NIL;
name ← IO.GetTokenRope[stream, Break ! IO.EndOfStream => CONTINUE].token;
};
GetBP: PROC [stream: IO.STREAM] RETURNS [REAL] = {
r: REALIO.GetReal[stream];
unit: ROPE ← GetName[stream];
multipler: REALSELECT TRUE FROM
unit.Equal["in"] => 72.0,
unit.Equal["pt"] => 72.0/72.27,
unit.Equal["cm"] => 72.0/2.54,
unit.Equal["mm"] => 72.0/25.4,
unit.Equal["bp"] => 1.0,
ENDCASE => 0.0;
IF multipler = 0.0 THEN ERROR;
RETURN [r*multipler];
};
ReadBlock: UNSAFE PROC [stream: IO.STREAM, destPointer: LONG POINTER, wordCount: INT] = UNCHECKED {
bytes: INTIO.UnsafeGetBlock[stream, [destPointer, 0, wordCount*2]];
IF bytes # wordCount*2 THEN ERROR;
};
IncludeAISFromBranch: ObjectFromBranchProc = {
data: REF IncludeAISRec ← NEW[IncludeAISRec];
textNode: TextNode.RefTextNode ← TextNode.NarrowToTextNode[node];
nodeContents: ROPE ← textNode.rope;
stream: IO.STREAMIO.RIS[nodeContents];
header: CGAIS.Header;
rasterPart: CGAIS.RasterPart;
uca: CGAIS.UCA;
dotSize: REAL ← 0;
imageWidth, imageHeight: CARDINAL ← 0;
byteIndex: INT ← 0;
data.aisFileName ← GetName[stream];
UNTIL IO.EndOf[stream] DO
keyword: ROPE ← GetName[stream];
colon: ROPE ← GetName[stream];
IF colon.Equal[":"] THEN NULL ELSE ERROR;
SELECT TRUE FROM
keyword.Equal["Height", FALSE] => data.height ← GetBP[stream];
keyword.Equal["Width", FALSE] => data.width ← GetBP[stream];
keyword.Equal["Indent", FALSE] => data.indent ← GetBP[stream];
keyword.Equal["DotSize", FALSE] => dotSize ← GetBP[stream];
keyword.Equal["Screen", FALSE] => data.screen ← IO.GetInt[stream];
ENDCASE => ERROR;
ENDLOOP;
data.aisStream ← FS.StreamOpen[data.aisFileName];
TRUSTED {ReadBlock[data.aisStream, @header, SIZE[CGAIS.Header]]};
IF header.password # CGAIS.password THEN ERROR; -- not an AIS file.
data.wordOffset ← header.attributeLength;
byteIndex ← IO.GetIndex[data.aisStream];
DO
TRUSTED {ReadBlock[data.aisStream, @rasterPart, SIZE[CGAIS.RasterPart]]};
IF rasterPart.aph.length = 0 THEN ERROR;
byteIndex ← byteIndex + 2*rasterPart.aph.length;
IF byteIndex/2 > header.attributeLength THEN ERROR;
IF rasterPart.aph.type = raster THEN EXIT;
IO.SetIndex[data.aisStream, byteIndex];
ENDLOOP;
IF rasterPart.codingType # CGAIS.UCACodingType THEN ERROR; -- not the kind we expected
TRUSTED {ReadBlock[data.aisStream, @uca, SIZE[CGAIS.UCA]]};
data.rasterPart ← rasterPart;
data.uca ← uca;
IF rasterPart.scanDirection MOD 4 < 2 THEN {
imageWidth ← rasterPart.scanCount;
imageHeight ← rasterPart.scanLength;
}
ELSE {
imageWidth ← rasterPart.scanLength;
imageHeight ← rasterPart.scanCount;
};
IF data.height < 0 AND data.width < 0 THEN {
IF dotSize <= 0 THEN ERROR; --must specify dotSize if height and width are omitted.
data.height ← dotSize*imageHeight;
data.width ← dotSize*imageWidth;
};
IF data.height < 0 THEN data.height ← (data.width * imageHeight)/imageWidth;
IF data.width < 0 THEN data.width ← (data.height * imageWidth)/imageHeight;
object ← NEW[TSGraphic.ObjectRec];
object.paintProc ← IncludeAISPaint;
object.layoutProc ← IncludeAISLayout;
object.data ← data;
};
IncludeAISLayout: TSGraphic.LayoutProc = {
data: REF IncludeAISRec ← NARROW[self.data];
extent ← [zeroDimn, RealDimn[data.width+data.indent, bp], zeroDimn, RealDimn[data.height, bp]];
};
IncludeAISPaint: TSGraphic.PaintProc = TRUSTED {
data: REF IncludeAISRec ~ NARROW[self.data];
handle: TSOutput.Handle ~ NARROW[context];
x: INT ~ Real.RoundLI[(DimnRatio[originX, bp]+data.indent)*micasPerPoint];
y: INT ~ Real.RoundLI[(DimnRatio[originY, bp])*micasPerPoint];
pressState: TSOutputPress.PressState ~ NARROW[handle.outputState];
pressHandle: SirPress.PressHandle ~ pressState.pressHandle;
windowWidth: INT ~ Real.RoundLI[data.width*micasPerPoint];
windowHeight: INT ~ Real.RoundLI[data.height*micasPerPoint];
bytesPerLine: INT ~ data.uca.wordsPerScanLine*2;
ScratchRec: TYPE ~ RECORD [SEQUENCE length: NAT OF WORD];
scratch: REF ScratchRec ← NEW[ScratchRec[data.uca.wordsPerScanLine]];
pressHandle.BeginScannedRectangle[
x: x, y: y-windowHeight,
dotsPerLine: data.rasterPart.scanLength,
numberOfLines: data.rasterPart.scanCount,
width: windowWidth,
height: windowHeight,
nextLineDirection: LOOPHOLE[data.rasterPart.scanDirection MOD 4],
nextDotDirection: LOOPHOLE[data.rasterPart.scanDirection / 4],
coding: SELECT data.uca.bitsPerSample FROM
0 => bitMap,
1 => bitSampled,
2 => bitBitSampled,
4 => nybbleSampled,
8 => byteSampled,
ENDCASE => ERROR,
samplingProperties: [screenFrequency: data.screen]
];
scratch[bytesPerLine/2-1] ← 0; -- make sure array is big enough
IO.SetIndex[data.aisStream, data.wordOffset*2];
FOR i: INT IN [0..data.rasterPart.scanCount) DO
TRUSTED {ReadBlock[data.aisStream, @scratch[0], scratch.length]};
TRUSTED {pressHandle.UnsafeShowLine[@scratch[0]]};
ENDLOOP;
pressHandle.EndScannedRectangle;
IO.Close[data.aisStream];
};
TSArtwork.Register["IncludeAIS", IncludeAISFromBranch];
END.