-- ScanImpl.mesaedit by McGregorDecember 9, 1980 11:06 AM

DIRECTORY
JasmineDefs: FROM "JasmineDefs",
GraphicsDefs: FROM "GraphicsDefs",
HalftoneDefs: FROM "HalftoneDefs",
ImageDefs: FROM "ImageDefs",
InlineDefs: FROM "InlineDefs",
IODefs: FROM "IODefs",
Mopcodes: FROM "Mopcodes",
OsStaticDefs: FROM "OsStaticDefs",
StreamDefs: FROM "StreamDefs",
StringDefs: FROM "StringDefs";

ScanImpl: PROGRAM IMPORTS GraphicsDefs, HalftoneDefs, ImageDefs, InlineDefs, IODefs, JasmineDefs, StreamDefs, StringDefs =
BEGIN OPEN JasmineDefs;
Black: CARDINAL ← 0;
White: CARDINAL ← 255;
XStart: CARDINAL ← 0;
XLen: CARDINAL ← 1024;
YStart: CARDINAL ← 177777B;
YLen: CARDINAL ← 1024;
ScanLen: CARDINAL ← 608;
DCBHead: POINTER TO CARDINAL = LOOPHOLE[420B];
nScanLines: CARDINAL ← 808;
keys: StreamDefs.StreamHandle ← IODefs.GetInputStream[];
CursorY: POINTER TO CARDINAL = LOOPHOLE[425B];
ControllerOn: BOOLEAN ← TRUE;

RamVal: TYPE = MACHINE DEPENDENT RECORD
[
blank: [0..17B],
offset: [0..77B],
gain: [0..77B]
];

AISHeader: TYPE = MACHINE DEPENDENT RECORD
[
password: CARDINAL ← 102252B,
headerLen: CARDINAL ← 1024,
partType: [0..77B] ← 1,
partLen: [0..1777B] ← 10,
scanCount: CARDINAL,
scanLength: CARDINAL,
scanDir: CARDINAL ← 3,
samplesPerPixel: CARDINAL ← 1,
codingType: CARDINAL ← 1,
bitsPerSample: CARDINAL ← 8,
wordsPerScanline: CARDINAL,
scanlinesPerBlock: CARDINAL ← 177777B,
padPerBlock: CARDINAL ← 177777B,
nextPartType: CARDINAL ← 0
];
PressCommands: TYPE = MACHINE DEPENDENT RECORD
[
SetCoding: [0..377B] ← 1,
code: [0..377B] ← 8,
dots: CARDINAL,
lines: CARDINAL,
SetMode: [0..377B] ← 2,
mode: [0..377B] ← 3,
SetSize: CARDINAL ← 2,
width: CARDINAL,
height: CARDINAL,
SetSamplingProperties: CARDINAL ← 6,
n: CARDINAL ← 7,
SSPInputIntensity: CARDINAL ← 0,
min: CARDINAL,
max: CARDINAL,
SSPScreen: CARDINAL ← 2,
angle: CARDINAL ← 45,
amplitude: CARDINAL ← 100,
frequency: CARDINAL,
SetWindow: CARDINAL ← 1,
pd: CARDINAL ← 0,
dd: CARDINAL,
pl: CARDINAL ← 0,
dl: CARDINAL,
DotsFollow: CARDINAL ← 3
];
PressTrailer: TYPE = MACHINE DEPENDENT RECORD
[
zero: CARDINAL ← 0,
SetX: [0..377B] ← 356B,
xHigh: [0..377B] ← (2540/2)/256,
xLow: [0..377B] ← (2540/2) MOD 256,
SetY: [0..377B] ← 357B,
y: CARDINAL ← 2540/2,
nop: [0..377B] ← 377B,
ShowDots: [0..377B] ← 374B,
nDotsWordsHigh: CARDINAL,
nDotsWordsLow: CARDINAL,
typeFontset: CARDINAL ← 0,
beginByteHigh: CARDINAL ← 0,
beginByte: CARDINAL ← 2*(1024-SIZE[PressCommands]),
nEntityWordsHigh: CARDINAL,
nEntityWordsLow: CARDINAL,
Xe: CARDINAL ← 0,
Ye: CARDINAL ← 0,
Left: CARDINAL ← 0,
Bottom: CARDINAL ← 0,
Width: CARDINAL ← 0,
Height: CARDINAL ← 0,
TrailerLen: CARDINAL ← 18
];
PressPartDir: TYPE = MACHINE DEPENDENT RECORD
[
dataPage: CARDINAL ← 0,
dataStart: CARDINAL ← 0,
dataRecords: CARDINAL,
dataPadLen: CARDINAL,
fontPage: CARDINAL ← 1,
fontStart: CARDINAL,
fontRecords: CARDINAL ← 1,
fontPadLen: CARDINAL ← 255
];
PressDocDirHeader: TYPE = MACHINE DEPENDENT RECORD
[
password: CARDINAL ← 27183,
nRecords: CARDINAL,
nParts: CARDINAL ← 2,
partDirStart: CARDINAL,
partDirLen: CARDINAL ← 1
];

Main: PROCEDURE =
BEGIN
Screen: POINTER TO GraphicsDefs.Bitmap;
nextDCB: POINTER TO ARRAY[0..3] OF CARDINAL ← LOOPHOLE[DCBHead↑];
DCBtop: POINTER ← nextDCB;

UNTIL nextDCB[0] = 0 DO
nScanLines ← nScanLines - nextDCB[3]*2;
nextDCB ← LOOPHOLE[nextDCB[0]];
ENDLOOP;
nScanLines ← nScanLines - nextDCB[3]*2;

GraphicsDefs.SetDefaultBitmap[608,nScanLines];
Screen ← GraphicsDefs.TurnOnGraphics[];
nextDCB ← LOOPHOLE[DCBHead↑];
nextDCB[0] ← LOOPHOLE[DCBtop];

JasmineInit[];

DO
--main loop
JasmineMotorOff[];
IODefs.WriteLine[""];
SELECT IODefs.ReadChar[] FROM
’? =>BEGIN
IODefs.WriteString[" Black: "];IODefs.WriteDecimal[Black];
IODefs.WriteString[" White: "];IODefs.WriteDecimal[White];
IODefs.WriteString[" XStart: "];IODefs.WriteDecimal[XStart];
IODefs.WriteString[" XLen: "];IODefs.WriteDecimal[XLen];
IODefs.WriteString[" YStart: "];IODefs.WriteDecimal[YStart];
IODefs.WriteString[" YLen: "];IODefs.WriteDecimal[YLen];
END;
’! =>BEGIN
IODefs.WriteString["Controller "];
ControllerOn ← NOT ControllerOn;
IF ControllerOn THEN
BEGIN JasmineControllerOn[];IODefs.WriteString["ON"];END
ELSE
BEGIN JasmineControllerOff[];IODefs.WriteString["OFF"];END;
END;
’b =>BEGIN IODefs.WriteString["Black: "];Black←IODefs.ReadDecimal[];END;
’c =>BEGIN
IODefs.WriteLine["Calibrate: Insert sheet of white paper"];
JasmineEject[]; --first, eject old page
IODefs.WriteString["Press any key when ready"];
[] ← IODefs.ReadChar[];
JasmineNewPage[14];
JasmineCalibrate[];
JasmineEject[]; --eject this page
END;
’d =>BEGIN IODefs.WriteString["Delay setting: "];
JasmineSetDelay[IODefs.ReadDecimal[]];
END;
’e => BEGIN IODefs.WriteString["Erase"];
GraphicsDefs.EraseArea[0,0,ScanLen,700];
END;
’f =>BEGIN
IODefs.WriteString["ForwardnSteps: "];
JasmineStep[IODefs.ReadDecimal[],TRUE];
END;
’h =>BEGIN
IODefs.WriteString["Halftone"];
DoHalftone[];
END;
’i => BEGIN
r: RamVal ← [0,64-10,0];
a: ARRAY [0..1024) OF RamVal ← ALL[r];
IODefs.WriteString["Initialize RAMs"];
JasmineLoadRam[LOOPHOLE[@a]];
END;
’l =>BEGIN IODefs.WriteString["Length of scan: "];
ScanLen←IODefs.ReadDecimal[];
END;
’n =>BEGIN
IODefs.WriteLine["New Page"];
JasmineEject[]; --first, eject old page
IODefs.WriteString["Press any key when ready"];
[] ← IODefs.ReadChar[];
JasmineNewPage[14];
XStart←0;XLen←1024;YStart←0;YLen←1400;
JasmineSetWindow[XStart,XLen,YStart,YLen];
END;
’o => BEGIN
savedDCB: CARDINAL ← DCBHead↑;
fileName: STRING ← [40];
IODefs.WriteString["Output file name: "];
IODefs.ReadID[fileName];
DCBHead↑← 0;
WriteFile[fileName];
DCBHead↑← savedDCB;
END;
’q =>BEGIN IODefs.WriteString["Quit"];
JasmineEject[];
JasmineControllerOff[];
ImageDefs.StopMesa[];
END;
’r =>BEGIN
IODefs.WriteString["ReversenSteps: "];
JasmineStep[IODefs.ReadDecimal[],FALSE];
END;
’s =>BEGIN IODefs.WriteString["Skip count: "];
JasmineSetResolution[IODefs.ReadDecimal[]];
END;
’t =>BEGIN IODefs.WriteString["Time for integration: "];
JasmineSetTime[IODefs.ReadDecimal[]];
END;
’w =>BEGIN IODefs.WriteString["White: "];White←IODefs.ReadDecimal[];END;
’x =>BEGIN
IODefs.WriteString["X"];
SELECT IODefs.ReadChar[] FROM
’l =>BEGIN
IODefs.WriteString["Len: "];
XLen←MIN[IODefs.ReadDecimal[],1024-XStart];
END;
’s =>BEGIN
IODefs.WriteString["Start: "];XStart←IODefs.ReadDecimal[];
XLen←MIN[XLen,1024-XStart];
END;
ENDCASE => IODefs.WriteString["???"];
END;
’y =>BEGIN
IODefs.WriteString["Y"];
SELECT IODefs.ReadChar[] FROM
’l =>BEGIN
IODefs.WriteString["Len: "];YLen←IODefs.ReadDecimal[];
END;
’s =>BEGIN
IODefs.WriteString["Start: "];YStart←IODefs.ReadDecimal[];
END;
ENDCASE => IODefs.WriteString["???"];
END;
’z =>BEGIN
Buttons: TYPE = MACHINE DEPENDENT RECORD
[ KeyPadAndGarbage: [0..10000B),
Red: [0..1],
Blue: [0..1],
Yellow: [0..1]
];
MouseButtons: POINTER TO Buttons = LOOPHOLE[177030B];
CursorX: POINTER TO CARDINAL = LOOPHOLE[426B];
CursorY: POINTER TO CARDINAL = LOOPHOLE[427B];
x,y: CARDINAL;
dx,dy: INTEGER ← 0;
IODefs.WriteString["Zoom"];
UNTIL MouseButtons.Red = 0 DO ENDLOOP;
x ← CursorX↑;y ← CursorY↑;
DO
WHILE MouseButtons.Red = 0 DO
XorBox[x,y,dx,dy];
dx ← CursorX↑ - x;dy ← CursorY↑ - y;
XorBox[x,y,dx,dy];
ENDLOOP;
IF dx < 0 THEN BEGIN x ← x+dx;dx ← ABS[dx];END;
IF dy < 0 THEN BEGIN y ← y+dy;dy ← ABS[dy];END;
WHILE MouseButtons.Yellow = 0 DO --move origin
XorBox[x,y,dx,dy];
x ← CursorX↑;y ← CursorY↑;
XorBox[x,y,dx,dy];
ENDLOOP;
IF MouseButtons.Blue = 0 THEN EXIT;
ENDLOOP;
XorBox[x,y,dx,dy];
XStart ← XStart + MulDiv[x,XLen,ScanLen];
YStart ← YStart + MulDiv[y,XLen,ScanLen];
YLen ← MulDiv[dy,XLen,ScanLen];
XLen ← MulDiv[dx,XLen,ScanLen];
DoHalftone[];
END;
ENDCASE;
ENDLOOP;
--main loop on characters
END;

WriteFile: PROCEDURE [fileName: STRING] =
BEGIN OPEN StreamDefs;
jx: CARDINAL ← JasmineCoord[XLen];
odd: CARDINAL ←
jx MOD 2;
ais: AISHeader ←
[
scanCount: JasmineCoord[YLen],scanLength: jx+odd,
wordsPerScanline: (jx+1)/2
];
micaWidth: CARDINAL ← MulDiv[ScanLen,2540,100];
press: PressCommands ←
[
dots: jx+odd,lines: JasmineCoord[YLen],
width: micaWidth,height: MulDiv[micaWidth,YLen,XLen],
min: --Black--0, max: --White--255,
frequency: MIN[85,MulDiv[jx,100,ScanLen]],
dd: jx,dl: JasmineCoord[YLen]
];
nDotsWords: LONG CARDINAL ← LONG[(
jx+1)/2]*JasmineCoord[YLen];
nEntityWords: LONG CARDINAL ← nDotsWords+18;
trailer: PressTrailer ←
[
nDotsWordsHigh: InlineDefs.HighHalf[nDotsWords],
nDotsWordsLow: InlineDefs.LowHalf[nDotsWords],
nEntityWordsHigh: InlineDefs.HighHalf[nEntityWords],
nEntityWordsLow: InlineDefs.LowHalf[nEntityWords]
];
padLen: CARDINAL ← 377B-(InlineDefs.LowHalf[nEntityWords] MOD 256);
recordLen: CARDINAL ← (InlineDefs.HighHalf[nEntityWords] MOD 256)*256 +
(InlineDefs.LowHalf[nEntityWords]/256) + 4 + 1;--4 for 1024 hdr
partdir: PressPartDir ←
[
dataRecords: recordLen,dataPadLen: padLen,fontStart: recordLen];
docdirhdr: PressDocDirHeader ←
[
nRecords: recordLen+3,--font,part,doc
partDirStart: recordLen+1
];
file: StreamHandle ← NewWordStream[fileName,Write+Append];
scanHead: POINTER TO ScanHead;
x, y: CARDINAL;
bcplFileName: StringDefs.BcplSTRING;
sl: POINTER TO PACKED ARRAY OF [0..377B];
range:CARDINAL←White-Black;

JasmineSetWindow[XStart,XLen,YStart,YLen];
scanHead ← JasmineScanInit[];

[] ← WriteBlock[file,@ais,1024-SIZE[PressCommands]];
[] ← WriteBlock[file,@press,SIZE[PressCommands]];
FOR y IN [1..JasmineCoord[YLen]] DO
sl ← JasmineReadLine[scanHead];
IF odd = 1 THEN sl[jx] ← sl[jx-1];
IF White#255 OR Black#0 THEN FOR x IN [1..jx] DO-- save user threshhold values
sl[x]←((MAX[Black,MIN[sl[x],White]]-Black)*255)/range;
ENDLOOP;
[] ← WriteBlock[file,sl,(jx+1)/2];
CursorY↑ ← MulDiv[y,800,JasmineCoord[YLen]];
ENDLOOP;
JasmineScanClose[scanHead];
[] ← WriteBlock[file,@trailer,SIZE[PressTrailer]+padLen];
--nil font part
file.put[file,0];
[] ← WriteBlock[file,NIL,255];
--part dir
[] ← WriteBlock[file,@partdir,256];
--doc dir
[] ← WriteBlock[file,@docdirhdr,SIZE[PressDocDirHeader]];
THROUGH[SIZE[PressDocDirHeader]..177B] DO file.put[file,-1];ENDLOOP;
StringDefs.MesaToBcplString[fileName,@bcplFileName];
[] ← WriteBlock[file,@bcplFileName,26];
[] ← WriteBlock[file,OsStaticDefs.OsStatics.UserName,16];
[] ← WriteBlock[file,NIL,256-252B];
file.destroy[file];
END;

DoHalftone: PROCEDURE =
BEGIN OPEN HalftoneDefs;
scanHead: POINTER TO ScanHead;
depth: CARDINAL ← 1;

JasmineSetWindow[XStart,XLen,YStart,YLen];
scanHead ← JasmineScanInit[];
InitHalftone[0,0,JasmineCoord[XLen],ScanLen,Black,White];
--
blackDCB!3=1
--
unless DisplayOn do @#420=blackDCB
THROUGH [0..JasmineCoord[YLen]) DO
IF NOT keys.endof[keys] THEN EXIT;
BEGIN
depth ← depth + PrintHalftoneLine[JasmineReadLine[scanHead]];
--
blackDCB!3=(depth+1)/2
IF depth >= nScanLines-10 THEN EXIT; --WRONG!!!
END;
ENDLOOP;
JasmineScanClose[scanHead];
--
@#420=dcb
END;

MulDiv: PROCEDURE [a,b,c: CARDINAL] RETURNS [CARDINAL] =
BEGIN
RETURN[InlineDefs.LongDiv[InlineDefs.LongMult[a,b],c]];
END;

XorBox: PROCEDURE[x,y,dx,dy: CARDINAL] =
BEGIN
GraphicsDefs.XorArea[x,y,x+dx,y];
GraphicsDefs.XorArea[x+dx,y,x+dx,y+dy];
GraphicsDefs.XorArea[x+dx,y+dy,x,y+dy];
GraphicsDefs.XorArea[x,y+dy,x,y];
END;

Main[];
END.