InterpressPageImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Michael Plass, June 13, 1986 12:57:33 pm PDT
Pier, May 26, 1987 5:24:42 pm PDT
Christophe Cuenod May 27, 1987 9:32:01 am PDT
Provides commands for making an Interpress package by splitting out and combining pages of other Interpress masters.
DIRECTORY
Commander USING [CommandProc, Register],
Convert USING [RopeFromInt],
FS USING [ComponentPositions, Error, ExpandName, FileInfo, Rename],
Imager,
ImagerBox,
ImagerInterpress USING [Close, Create, DoPage, Ref],
Interpress USING [DoPage, Master, Open],
IO,
Rope USING [Cat, Concat, Equal, Length, ROPE, Substr, ToRefText];
InterpressPageImpl: CEDAR PROGRAM
IMPORTS Commander, Convert, FS, Imager, ImagerInterpress, Interpress, IO, Rope
~ BEGIN
Copied Types
ROPE: TYPE ~ Rope.ROPE;
Command parsing aids
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];
};
GetCmdToken: PROC [stream: IO.STREAM] RETURNS [rope: ROPE] = {
rope ← NIL;
rope ← stream.GetTokenRope[CmdTokenBreak ! IO.EndOfStream => CONTINUE].token;
};
ExpandedName: TYPE ~ RECORD [fullFName: ROPE, cp: FS.ComponentPositions];
ExpandName: PROC [inputName: ROPE] RETURNS [e: ExpandedName] ~ INLINE {
[e.fullFName, e.cp] ← FS.ExpandName[inputName];
};
Extracting pages
PageRange: TYPE ~ RECORD [startPage, nPages: INT];
SpecError: PUBLIC ERROR [offset: INT] ~ CODE;
DoExtract: PUBLIC PROC [inputFile, outputFile: ROPE, pageSpec: LIST OF PageRange, log: IO.STREAM] RETURNS [success: BOOLEANTRUE] ~ {
logProc: PROC [class: INT, code: ATOM, explanation: ROPE] ~ {
IO.PutRope[log, "\n *** Interpress Error "];
IO.PutRope[log, explanation];
success ← FALSE;
};
n: ExpandedName ~ ExpandName[FS.FileInfo[inputFile].fullFName];
master: Interpress.Master ~ Interpress.Open[n.fullFName, logProc];
out: ImagerInterpress.Ref ~ ImagerInterpress.Create[outputFile];
IO.PutRope[log, "Reading "];
IO.PutRope[log, n.fullFName];
IO.PutRope[log, " . . . "];
FOR each: LIST OF PageRange ← pageSpec, each.rest UNTIL each=NIL DO
pageRange: PageRange ~ each.first;
FOR i: INT IN [pageRange.startPage..MIN[pageRange.startPage+pageRange.nPages-1, master.pages]] DO
OnePage: PROC [context: Imager.Context] ~ {Interpress.DoPage[master, i, context, logProc]};
IO.PutF[stream: log, format: " [%g", v1: [integer[i]]];
ImagerInterpress.DoPage[out, OnePage];
IO.PutRope[self: log, r: "]"];
ENDLOOP;
ENDLOOP;
ImagerInterpress.Close[out];
IO.PutRope[log, " written.\n"];
};
InterpressExtractCommand: Commander.CommandProc ~ {
GetToken: PROC [stream: IO.STREAM] RETURNS [token: ROPENIL] = {
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];
};
token ← stream.GetTokenRope[Break ! IO.EndOfStream => CONTINUE].token;
};
ParsePageSpec: PUBLIC PROC [pageSpecRope: ROPE] RETURNS [pageSpec: LIST OF PageRange, charsParsed: INT] ~ {
Reverse: PROC [pageSpec: LIST OF PageRange] RETURNS [reversed: LIST OF PageRange] ~ {
WHILE pageSpec # NIL DO
t: LIST OF PageRange ← pageSpec;
pageSpec ← t.rest;
t.rest ← reversed;
reversed ← t;
ENDLOOP;
};
text: REF TEXT ~ pageSpecRope.ToRefText;
i: NAT ← 0;
c: CHAR;
SkipSpaces: PROC ~ {c ← ' ; WHILE i < text.length AND ((c ← text[i]) = ', OR c = ' OR c = ' OR c = '\n) DO i ← i+1 ENDLOOP};
GetChar: PROC RETURNS [CHAR] ~ {IF i < text.length THEN {i ← i+1; RETURN [text[i-1]]} ELSE RETURN ['\000]};
Int: PROC RETURNS [value: INT𡤀] ~ {
SkipSpaces[];
IF NOT c IN ['0..'9] THEN ERROR SpecError[i];
WHILE i < text.length AND (c ← text[i]) IN ['0..'9] DO
value ← value * 10 + (c-'0);
i ← i+1;
ENDLOOP;
};
spec: LIST OF PageRange ← NIL;
SkipSpaces[];
WHILE i < text.length DO
SELECT text[i] FROM
IN ['0..'9] => spec ← CONS[[Int[], 1], spec];
'[, '( => {
open: CHAR ← GetChar[];
start: INT ← Int[];
end: INT;
SkipSpaces[];
IF i < text.length AND text[i] = '. THEN i ← i+1 ELSE ERROR SpecError[i];
IF i < text.length AND text[i] = '. THEN i ← i+1 ELSE ERROR SpecError[i];
end ← Int[];
SkipSpaces[];
IF (c ← GetChar[]) = '] OR c = ') THEN {
IF open = '( THEN start ← start + 1;
IF c = '] THEN end ← end + 1;
IF end > start THEN spec ← CONS[[start, end-start], spec]
}
ELSE ERROR SpecError[i];
};
ENDCASE => EXIT;
SkipSpaces[];
ENDLOOP;
RETURN [Reverse[spec], i]
};
stream: IO.STREAMIO.RIS[cmd.commandLine];
outputName: ROPE ← GetToken[stream];
inputName: ROPE;
pagesToken: ROPE;
pageSpec: LIST OF PageRange;
IF outputName.Length = 0 THEN {cmd.out.PutRope["Output file missing.\n"]; RETURN};
IF NOT GetToken[stream].Equal["←"] THEN {cmd.out.PutRope["Missing \"←\".\n"]; RETURN};
inputName ← GetToken[stream];
pagesToken ← GetToken[stream];
IF pagesToken.Equal["PAGE", FALSE] OR pagesToken.Equal["PAGES", FALSE] THEN {
skip: INT;
[pageSpec, skip] ← ParsePageSpec[cmd.commandLine.Substr[stream.GetIndex]];
stream.SetIndex[stream.GetIndex+skip];
}
ELSE pageSpec ← LIST[[1, 1000000]];
IF NOT DoExtract[inputName, outputName, pageSpec, cmd.out] THEN {
cmd.out.PutRope["Unable to extract any pages from "];
cmd.out.PutRope[inputName];
cmd.out.PutChar['\n];
}
ELSE {cmd.out.PutRope[outputName]; cmd.out.PutRope[" Written.\n"]};
IF NOT stream.EndOf THEN {cmd.out.PutRope["Ignored: "]; cmd.out.PutRope[cmd.commandLine.Substr[stream.GetIndex]]; cmd.out.PutChar['\n]};
};
Breaking into single pages
DoBreakup: PROC [inputName: ROPE, log: IO.STREAM] ~ {
logProc: PROC [class: INT, code: ATOM, explanation: ROPE] ~ {
IO.PutRope[log, "\n *** Interpress Error "];
IO.PutRope[log, explanation];
};
n: ExpandedName ~ ExpandName[FS.FileInfo[inputName].fullFName];
base: ROPE ~ Rope.Substr[n.fullFName, n.cp.base.start, n.cp.base.length];
ext: ROPE ~ Rope.Substr[n.fullFName, n.cp.ext.start, n.cp.ext.length];
master: Interpress.Master ~ Interpress.Open[n.fullFName, logProc];
IO.PutRope[log, "Reading "];
IO.PutRope[log, n.fullFName];
IO.PutRope[log, " . . . "];
FOR i: INT IN [1..master.pages] DO
name: ROPE ~ Rope.Cat[base, "-", Convert.RopeFromInt[i], ".", ext];
out: ImagerInterpress.Ref ~ ImagerInterpress.Create[name];
onePage: PROC [context: Imager.Context] ~ {Interpress.DoPage[master, i, context, logProc]};
IO.PutRope[log, FS.FileInfo[name].fullFName];
ImagerInterpress.DoPage[out, onePage];
IO.PutRope[log, " "];
ImagerInterpress.Close[out];
ENDLOOP;
IO.PutRope[log, "written.\n"];
};
InterpressBreakupCommand: Commander.CommandProc ~ {
stream: IO.STREAMIO.RIS[cmd.commandLine];
inputName: ROPE ← GetCmdToken[stream];
IF inputName = NIL THEN RETURN[result: $Failure, msg: cmd.procData.doc];
DoBreakup[inputName, cmd.out ! FS.Error => IF error.group = user THEN {result ← $Failure; msg ← error.explanation; CONTINUE}];
};
Clipping to specified rectangle
DoClip: PROC [inputName: ROPE, r: Imager.Rectangle, log: IO.STREAM] ~ {
logProc: PROC [class: INT, code: ATOM, explanation: ROPE] ~ {
IO.PutRope[log, "\n *** Interpress Error "];
IO.PutRope[log, explanation];
};
name: ROPE;
n: ExpandedName ~ ExpandName[FS.FileInfo[inputName].fullFName];
base: ROPE ~ Rope.Substr[n.fullFName, 0, n.cp.base.start+n.cp.base.length];
ext: ROPE ~ Rope.Substr[n.fullFName, n.cp.ext.start, n.cp.ext.length];
master: Interpress.Master ~ Interpress.Open[n.fullFName, logProc];
IO.PutRope[log, "Reading "];
IO.PutRope[log, n.fullFName];
IO.PutRope[log, " . . . "];
name ← Rope.Cat[base, "-", "Clipped"];
IF n.cp.ext.length # 0 THEN name ← Rope.Cat[name, ".", ext];
{
out : ImagerInterpress.Ref ~ ImagerInterpress.Create[name];
onePage: PROC [context: Imager.Context] ~ {
context.ClipRectangle[r];
Interpress.DoPage[master, 1, context, logProc];
};
IO.PutRope[log, FS.FileInfo[name].fullFName];
ImagerInterpress.DoPage[out, onePage];
IO.PutRope[log, " "];
ImagerInterpress.Close[out];
IO.PutRope[log, "written.\n"];
};
};
InterpressClipCommand: Commander.CommandProc ~ {
stream: IO.STREAMIO.RIS[cmd.commandLine];
inputName: ROPE ← GetCmdToken[stream];
r: Imager.Rectangle;
IF inputName = NIL THEN RETURN[result: $Failure, msg: cmd.procData.doc];
r.x ← IO.GetReal[stream];
r.y ← IO.GetReal[stream];
r.w ← IO.GetReal[stream];
r.h ← IO.GetReal[stream];
DoClip[inputName, r, cmd.out ! FS.Error => IF error.group = user THEN {result ← $Failure; msg ← error.explanation; CONTINUE}];
};
Concatenating masters together
DoConcatenate: PROC [outputName: ROPE, cmdLineStream: IO.STREAM, log: IO.STREAM] ~ {
pageNumber: INT ← 0;
logProc: PROC [class: INT, code: ATOM, explanation: ROPE] ~ {
IO.PutRope[log, "\n *** Interpress Error "];
IO.PutRope[log, explanation];
};
n: ExpandedName ~ ExpandName[outputName];
extendedName: ROPE ~ IF n.cp.ext.length = 0
THEN Rope.Substr[n.fullFName, 0, n.cp.base.start+n.cp.base.length].Concat[".interpress"]
ELSE n.fullFName;
tempName: ROPE ← "TempConcatenation.interpress";
Write it with a temp name to avoid lock conflicts if it is also an input.
out: ImagerInterpress.Ref ~ ImagerInterpress.Create[tempName];
tempName ← FS.FileInfo[tempName].fullFName;
IO.PutRope[log, "Reading "];
FOR inputName: ROPE ← GetCmdToken[cmdLineStream], GetCmdToken[cmdLineStream] UNTIL inputName = NIL DO
fullInputName: ROPE ~ FS.FileInfo[inputName].fullFName;
master: Interpress.Master ~ Interpress.Open[fullInputName, logProc];
IO.PutRope[log, fullInputName];
IO.PutRope[log, " "];
FOR i: INT IN [1..master.pages] DO
onePage: PROC [context: Imager.Context] ~ {Interpress.DoPage[master, i, context, logProc]};
IO.PutRope[log, "["];
IO.PutRope[log, Convert.RopeFromInt[pageNumber ← pageNumber + 1]];
ImagerInterpress.DoPage[out, onePage];
IO.PutRope[log, "] "];
ENDLOOP;
ENDLOOP;
ImagerInterpress.Close[out];
FS.Rename[from: tempName, to: extendedName];
IO.PutRope[log, FS.FileInfo[extendedName].fullFName];
IO.PutRope[log, " written.\n"];
};
InterpressConcatenateCommand: Commander.CommandProc ~ {
stream: IO.STREAMIO.RIS[cmd.commandLine];
outputName: ROPE ← GetCmdToken[stream];
gets: ROPE ← GetCmdToken[stream];
IF outputName = NIL OR NOT gets.Equal["←"] THEN RETURN[result: $Failure, msg: cmd.procData.doc];
DoConcatenate[outputName, stream, cmd.out ! FS.Error => IF error.group = user THEN {result ← $Failure; msg ← error.explanation; CONTINUE}];
};
Command Registration
Commander.Register[key: "InterpressExtract", proc: InterpressExtractCommand, doc: "Extract pages from interpress files, e.g. result.ip ← source.ip PAGES 1, 3, [10..15]"];
Commander.Register[key: "IPExtract", proc: InterpressExtractCommand, doc: "Extract pages from interpress files, e.g. result.ip ← source.ip PAGES 1, 3, [10..15] (alias for InterpressExtract)"];
Commander.Register[key: "InterpressBreakup", proc: InterpressBreakupCommand, doc: "Breaks an interpress master into a collection of one-page interpress masters"];
Commander.Register[key: "InterpressClip", proc: InterpressClipCommand, doc: "Clips a single page Interpress master to a specified rectangle: x, y, w, h"];
Commander.Register[key: "IPBreakup", proc: InterpressBreakupCommand, doc: "Breaks an interpress master into a collection of one-page interpress masters (alias for InterpressBreakup)"];
Commander.Register[key: "InterpressConcatenate", proc: InterpressConcatenateCommand, doc: "Concatenates a collection of Interpress masters into one. (output ← input1 input2 . . .)"];
Commander.Register[key: "IPConcatenate", proc: InterpressConcatenateCommand, doc: "Concatenates a collection of Interpress masters into one. (output ← input1 input2 . . .) (alias for InterpressConcatenate)"];
END.