MakeRESImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Rick Beach, July 1, 1986 2:27:23 pm PDT
Michael Plass, June 20, 1986 12:47:04 pm PDT
DIRECTORY
Atom USING [GetPName],
BasicTime USING [Now],
Commander USING [CommandProc, Handle, Register],
Convert USING [Error, IntFromRope, RopeFromTime],
FS USING [ComponentPositions, Error, ExpandName, FileInfo],
Imager USING [Context, Error, PixelArray, Transformation],
ImagerColorOperator USING [GrayLinearColorModel],
ImagerFastShow USING [Create],
ImagerInterpressFragment USING [Close, Create, PushColorOperator, PushInt, PushPixelArray, PushVector, Ref, VectorProc, StreamFromRef],
ImagerOps USING [PixelArrayFromPixelMaps],
ImagerPixelArray USING [FromAIS, MaxSampleValue],
ImagerPixelMap USING [Clear, Create, PixelMap, Trim],
ImagerTransformation USING [Create],
Interpress USING [DoPage, LogProc, Master, Open],
IO USING [atom, CharClass, EndOfStream, GetIndex, GetTokenRope, int, PutF, PutFR, PutRope, RIS, rope, SetIndex, STREAM],
IPMaster USING [PutInt, PutOp, PutRational],
PixelMapOps USING [StoreAIS],
Real USING [Round],
Rope USING [Cat, Equal, Index, ROPE, Substr];
MakeRESImpl: CEDAR PROGRAM
IMPORTS Atom, BasicTime, Commander, Convert, FS, Imager, ImagerColorOperator, ImagerInterpressFragment, ImagerFastShow, ImagerOps, ImagerPixelArray, ImagerPixelMap, ImagerTransformation, Interpress, IO, IPMaster, PixelMapOps, Real, Rope
~ BEGIN
Stolen shamelessly from MakeFIS, wherein a Font Interchange Standard Interpress master is created to contain an Interpress Font.
ROPE: TYPE ~ Rope.ROPE;
resHeader: ROPE ← "Interpress/Xerox/2.1/RasterEncoding/1.0 ";
resSignature: INT = 13086;
Complain: ERROR [complaint: ROPE] ~ CODE;
MakeRESFromAIS: PROC [inputName, outputName: ROPE] ~ {
ip: ImagerInterpressFragment.Ref ~ ImagerInterpressFragment.Create[outputName, resHeader];
pa: Imager.PixelArray ← ImagerPixelArray.FromAIS[inputName];
IF ImagerPixelArray.MaxSampleValue[pa, 0] # 1 THEN
Complain["AIS file must have only 1 bits per sample"];
PushRESImage[inputName, ip, pa, 300];
ImagerInterpressFragment.Close[ip];
};
PushRESImage: PROC [inputName: Rope.ROPE, ip: ImagerInterpressFragment.Ref, pa: Imager.PixelArray, res: INT] ~ {
PushScaleVector: PROC ~ {
the scale vector must conform to several limitations imposed by ancient implementations
stream: IO.STREAM ← ImagerInterpressFragment.StreamFromRef[ip];
IF res # 72 AND res # 300 THEN Complain["RES bitmap resolution must be 72 or 300"];
IPMaster.PutRational[stream, 254, res*10000];
IPMaster.PutOp[stream, dup];
IPMaster.PutInt[stream, 2];
IPMaster.PutOp[stream, makevec];
};
attributeVector: ImagerInterpressFragment.VectorProc ~ {
putIdentifier[$name];
putString[inputName];
putIdentifier[$creationTime];
putString[Convert.RopeFromTime[from: BasicTime.Now[], end: seconds]];
};
PushScaleVector[];
ImagerInterpressFragment.PushInt[ip, pa.fSize];
ImagerInterpressFragment.PushInt[ip, pa.sSize];
ImagerInterpressFragment.PushInt[ip, 0]; -- no mask image
ImagerInterpressFragment.PushPixelArray[ip, pa];
ImagerInterpressFragment.PushColorOperator[ip, ImagerColorOperator.GrayLinearColorModel[sWhite: 0, sBlack: 1, maxSampleValue: 0, sampleMap: NIL]]; -- bitmap values
ImagerInterpressFragment.PushVector[ip, attributeVector];
ImagerInterpressFragment.PushInt[ip, resSignature];
};
ActionProc: TYPE ~ PROC [inputName: ROPE, outputName: ROPE, cmd: Commander.Handle, cmds: IO.STREAM];
MakeRESFromAISAction: ActionProc ~ {
MakeRESFromAIS[inputName, outputName];
};
Direction: TYPE ~ {left, right, up, down};
ScanMode: TYPE ~ RECORD [slow, fast: Direction];
SFToXY: PROC [scanMode: ScanMode, sSize, fSize: INT] RETURNS [Imager.Transformation] ~ {
a: REAL ~ SELECT scanMode.slow FROM right => 1.0, left => -1.0, ENDCASE => 0.0;
b: REAL ~ SELECT scanMode.fast FROM right => 1.0, left => -1.0, ENDCASE => 0.0;
d: REAL ~ SELECT scanMode.slow FROM up => 1.0, down => -1.0, ENDCASE => 0.0;
e: REAL ~ SELECT scanMode.fast FROM up => 1.0, down => -1.0, ENDCASE => 0.0;
tX: REAL ~ MAX[-(a*sSize + b*fSize), 0];
tY: REAL ~ MAX[-(d*sSize + e*fSize), 0];
RETURN[ImagerTransformation.Create[a, b, tX, d, e, tY]];
};
The result transforms [s, f] to [x, y], given the source (e.g., pixel array) scan mode.
MakeAISFromInterpressAction: ActionProc ~ {
Log: Interpress.LogProc ~ {
cmd.out.PutF["Interpress error (class %g) %g: %g\n", IO.int[class], IO.atom[code], IO.rope[explanation]];
};
master: Interpress.Master ~ Interpress.Open[inputName, Log];
res: INT ~ Convert.IntFromRope[GetCmdToken[cmds]];
sSize: NAT ~ Real.Round[res*8.5];
fSize: NAT ~ Real.Round[res*11.0];
pixelMap: ImagerPixelMap.PixelMap ← ImagerPixelMap.Create[lgBitsPerPixel: 0, bounds: [0, 0, sSize, fSize]];
context: Imager.Context ~ ImagerFastShow.Create[pm: pixelMap, pixelsPerInch: res, pixelUnits: FALSE];
pa: Imager.PixelArray ← NIL;
ImagerPixelMap.Clear[pixelMap];
Interpress.DoPage[master: master, page: 1, context: context, log: Log];
pixelMap ← ImagerPixelMap.Trim[pixelMap];
PixelMapOps.StoreAIS[Rope.Cat[outputName, ".ais"], [pixelMap, TRUE, NIL]];
};
MakeRESFromInterpressAction: ActionProc ~ {
Log: Interpress.LogProc ~ {
cmd.out.PutF["Interpress error (class %g) %g: %g\n", IO.int[class], IO.atom[code], IO.rope[explanation]];
};
master: Interpress.Master ~ Interpress.Open[inputName, Log];
res: INT ~ Convert.IntFromRope[GetCmdToken[cmds]];
sSize: NAT ~ Real.Round[res*8.5];
fSize: NAT ~ Real.Round[res*11.0];
pixelMap: ImagerPixelMap.PixelMap ← ImagerPixelMap.Create[lgBitsPerPixel: 0, bounds: [0, 0, sSize, fSize]];
context: Imager.Context ~ ImagerFastShow.Create[pm: pixelMap, pixelsPerInch: res, pixelUnits: FALSE];
pa: Imager.PixelArray ← NIL;
ip: ImagerInterpressFragment.Ref ~ ImagerInterpressFragment.Create[outputName, resHeader];
ImagerPixelMap.Clear[pixelMap];
Interpress.DoPage[master: master, page: 1, context: context, log: Log];
pixelMap ← ImagerPixelMap.Trim[pixelMap];
pa ← ImagerOps.PixelArrayFromPixelMaps[
pms: LIST[pixelMap],
um: SFToXY[[slow: down, fast: right], pixelMap.sSize, pixelMap.fSize]
];
IF ImagerPixelArray.MaxSampleValue[pa, 0] # 1 THEN
Complain["AIS file must have only 1 bits per sample"];
PushRESImage[inputName, ip, pa, res];
ImagerInterpressFragment.Close[ip];
};
FindFullName: PROC [inputName: ROPE] RETURNS [ROPE] ~ {
fullFName: ROPENIL;
fullFName ← FS.FileInfo[inputName].fullFName;
RETURN [fullFName]
};
Command: Commander.CommandProc ~ {
refAction: REF ActionProc ~ NARROW[cmd.procData.clientData];
stream: IO.STREAMIO.RIS[cmd.commandLine];
outputName: Rope.ROPE ← GetCmdToken[stream];
secondTokenIndex: INTIO.GetIndex[stream];
gets: Rope.ROPE ← GetCmdToken[stream];
inputName: Rope.ROPENIL;
IF NOT gets.Equal["←"] THEN {
inputName ← outputName;
outputName ← NIL;
stream.SetIndex[secondTokenIndex];
}
ELSE inputName ← GetCmdToken[stream];
IF inputName = NIL THEN RETURN[result: $Failure, msg: cmd.procData.doc];
inputName ← FindFullName[inputName ! FS.Error => {
IF error.group = user THEN {result ← $Failure; msg ← error.explanation; GOTO Quit}
}];
IF outputName = NIL THEN {
outputName ← MakeOutputName[inputName, cmd.procData.doc];
};
cmd.out.PutRope["Converting "];
cmd.out.PutRope[inputName];
cmd.out.PutRope[" . . . "];
refAction^[inputName, outputName, cmd, stream !
Convert.Error => {result ← $Failure; msg ← "Syntax error in command line: expected a number"; GOTO Quit};
Complain => {result ← $Failure; msg ← complaint; GOTO Quit};
FS.Error => {result ← $Failure; msg ← error.explanation; GOTO Quit};
Imager.Error => {result ← $Failure; msg ← IO.PutFR["Imager.Error[[$%g, %g]]", IO.rope[Atom.GetPName[error.code]], IO.rope[error.explanation]]; GOTO Quit}
];
outputName ← FindFullName[outputName ! FS.Error => {
outputName ← "Output file(s)"; CONTINUE};
];
cmd.out.PutRope[outputName];
cmd.out.PutRope[" written.\n"];
EXITS Quit => NULL
};
GetCmdToken: PROC [stream: IO.STREAM] RETURNS [rope: Rope.ROPE] = {
rope ← NIL;
rope ← stream.GetTokenRope[CmdTokenBreak ! IO.EndOfStream => CONTINUE].token;
};
CmdTokenBreak: PROC [char: CHAR] RETURNS [IO.CharClass] = {
IF char = '← THEN RETURN [break];
IF char = ' OR char = '\t OR char = ', OR char = '; OR char = '\n THEN RETURN [sepr];
RETURN [other];
};
MakeOutputName: PROC [inputName: Rope.ROPE, doc: Rope.ROPE] RETURNS [Rope.ROPE] ~ {
start: INT ← Rope.Index[s1: doc, s2: " to "]+4;
end: INT ← Rope.Index[s1: doc, pos1: start, s2: " "];
cp: FS.ComponentPositions;
[inputName, cp] ← FS.ExpandName[inputName];
RETURN [Rope.Cat[Rope.Substr[inputName, cp.base.start, cp.base.length], ".", Rope.Substr[doc, start, end-start]]];
};
Commander.Register["MakeRESFromAIS", Command, "Convert an AIS image to RES format image", NEW[ActionProc ← MakeRESFromAISAction]];
Commander.Register["MakeRESBitmapFromInterpress", Command, "Convert an Interpress file to RES format bitmap ([<outputFileName> ←] <inputFileName> <resolution>)", NEW[ActionProc ← MakeRESFromInterpressAction]];
Commander.Register["MakeAISBitmapFromInterpress", Command, "Convert an Interpress file to AIS format bitmap ([<outputFileName> ←] <inputFileName> <resolution>)", NEW[ActionProc ← MakeAISFromInterpressAction]];
END.