<<>> <> <> <> <> <> <<>> <> <<>> <<>> DIRECTORY Commander USING [CommandProc, Handle, Register], CommanderOps, Convert, FS, Imager, ImagerInterpress USING [Close, Create, DoPage, Ref ], ImagerFont, InterpressInterpreter USING [DoPage, LogProc, Master, Open ], IO, Rope USING [ Cat, ROPE, Fetch, Equal, Length, Substr ]; InterpressBookletImpl: CEDAR PROGRAM IMPORTS Commander, CommanderOps, Convert, FS, Imager, ImagerInterpress, ImagerFont, InterpressInterpreter, IO, Rope ~ { ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; BookletCmd: Commander.CommandProc ~ { ENABLE FS.Error => CommanderOps.Failed[error.explanation]; argv: CommanderOps.ArgumentVector ¬ CommanderOps.Parse[cmd]; scaleIt: BOOL ¬ FALSE; renumber: BOOL ¬ FALSE; up: INT ¬ 0; paperWidth: REAL ¬ 0.01 * 2.54 * 8.5; -- meters paperHeight: REAL ¬ 0.01 * 2.54 * 11.0; -- meters scaleFactor: REAL ¬ 0.0; input: ROPE; output: ROPE; BookletLogProc: InterpressInterpreter.LogProc ~ { cmd.err.PutRope["\n *** "]; cmd.err.PutRope[explanation]; cmd.err.PutRope[" *** "]; }; Booklet: PROC [output, input: ROPE, logProc: InterpressInterpreter.LogProc, ms: STREAM] ~ { fullFName: ROPE ~ FS.FileInfo[input].fullFName; master: InterpressInterpreter.Master ~ InterpressInterpreter.Open[fileName: fullFName, log: logProc]; ref: ImagerInterpress.Ref ~ ImagerInterpress.Create[fileName: output]; inPages: INT = master.pages; outPages: INT = (inPages+3)/4; lowPage: INT ¬ 1; highPage: INT ¬ outPages * 4; DoPage: PROC [context: Imager.Context, page: INT] ~ { Renumber: PROC ~ { font: ImagerFont.Font ~ Imager.FindFontScaled["Xerox/XC1-1-1/Modern", 9]; rope: ROPE ~ Convert.RopeFromInt[page]; Imager.ScaleT[context, 0.0254/72]; Imager.SetXY[context, [x: IF page MOD 2 = 0 THEN 36.0 ELSE 5.5*72-36-ImagerFont.RopeEscapement[font, rope].x, y: 8.5*72-36]]; Imager.SetFont[context, font]; Imager.ShowRope[context, rope]; }; IF renumber AND page > 1 THEN Imager.DoSave[context, Renumber]; IF scaleIt THEN Imager.ScaleT[context, scaleFactor]; IF up#0 THEN Imager.TranslateT[context, [0, up*0.5*0.0254]]; -- move up InterpressInterpreter.DoPage[master: master, page: page, context: context, log: logProc]; }; WriteSide1: PROC [context: Imager.Context] ~ { LowPageAction: PROC ~ { IF lowPage > inPages THEN RETURN; Imager.TranslateT[context, [paperWidth, paperHeight/2.0]]; Imager.RotateT[context, 90.0]; DoPage[context, lowPage]; lowPage ¬ lowPage + 1; }; HighPageAction: PROC ~ { IF highPage > inPages THEN {highPage ¬ highPage - 1; RETURN}; Imager.TranslateT[context, [paperWidth, 0]]; Imager.RotateT[context, 90.0]; DoPage[context, highPage]; highPage ¬ highPage - 1; }; Imager.DoSave[context, LowPageAction]; Imager.DoSave[context, HighPageAction]; }; WriteSide2: PROC [context: Imager.Context] ~ { LowPageAction: PROC ~ { IF lowPage > inPages THEN RETURN; Imager.TranslateT[context, [0, paperHeight]]; Imager.RotateT[context, 270.0]; DoPage[context, lowPage]; lowPage ¬ lowPage + 1; }; HighPageAction: PROC ~ { IF highPage > inPages THEN {highPage ¬ highPage - 1; RETURN}; Imager.TranslateT[context, [0, paperHeight/2.0]]; Imager.RotateT[context, 270.0]; DoPage[context, highPage]; highPage ¬ highPage - 1; }; Imager.DoSave[context, LowPageAction]; Imager.DoSave[context, HighPageAction]; }; ms.PutFL["Making booklet %g (%g/4 pages) from %g (%g input pages) ... ", LIST[ [rope[output]], [integer[outPages*4]], [rope[input]], [integer[inPages]]]]; WHILE lowPage < highPage DO ms.PutF["[%g] [%g", [integer[(lowPage*2)-1]], [integer[lowPage*2]]]; ImagerInterpress.DoPage[self: ref, action: WriteSide1]; ms.PutF["] [%g] [%g", [integer[(lowPage*2)-1]], [integer[lowPage*2]]]; ImagerInterpress.DoPage[self: ref, action: WriteSide2]; ms.PutRope["] "]; ENDLOOP; ImagerInterpress.Close[self: ref]; ms.PutF1["\n%g written.\n", [rope[output]]]; }; ProcessArgs: PROC [cmd: Commander.Handle, argv: CommanderOps.ArgumentVector] RETURNS [msg: ROPE ¬ NIL] ~ { i: INT ¬ 1; arrowSpecified: BOOL ¬ FALSE; inputWidth: REAL ¬ 0.01 * 2.54 * 8.5; -- meters inputHeight: REAL ¬ 0.01 * 2.54 * 11.0; -- meters input ¬ NIL; output ¬ NIL; scaleIt ¬ FALSE; scaleFactor ¬ 0.0; WHILE i < argv.argc DO len: INT ~ Rope.Length[argv[i]]; IF len = 0 THEN { msg ¬ "Null argument"; GOTO Bad }; IF Rope.Fetch[argv[i], 0] = '- THEN { IF len = 1 THEN { msg ¬ "Missing option"; GOTO Bad }; SELECT Rope.Fetch[argv[i], 1] FROM 'b => scaleIt ¬ FALSE; -- booklet style, no scaling 'f => scaleIt ¬ TRUE; -- fit a "standard" 8.5 x 11 'n => { renumber ¬ TRUE }; -- renumber 'u => { up ¬ up + 1 }; -- up a little 's => { -- use an arbitrary scaling factor scaleIt ¬ TRUE; scaleFactor ¬ Convert.RealFromRope[Rope.Substr[argv[i], 2]]; }; 'p => IF i+1 >= argv.argc THEN GOTO Bad ELSE { arg: ROPE ~ argv[i+1]; i ¬ i + 1; SELECT TRUE FROM Rope.Equal[arg, "usletter", FALSE] => { paperWidth ¬ 0.01 * 2.54 * 8.5; -- meters paperHeight ¬ 0.01 * 2.54 * 11.0; -- meters }; Rope.Equal[arg, "uslegal", FALSE] => { paperWidth ¬ 0.01 * 2.54 * 8.5; -- meters paperHeight ¬ 0.01 * 2.54 * 14.0; -- meters }; Rope.Equal[arg, "usledger", FALSE] => { paperWidth ¬ 0.01 * 2.54 * 11.0; -- meters paperHeight ¬ 0.01 * 2.54 * 17.0; -- meters }; Rope.Equal[arg, "a4", FALSE] => { paperWidth ¬ 0.210; -- meters paperHeight ¬ 0.297; -- meters }; ENDCASE => msg ¬ "known paper sizes are: usletter, uslegal, usledger, a4"; }; 'i => IF i+1 >= argv.argc THEN GOTO Bad ELSE { arg: ROPE ~ argv[i+1]; i ¬ i + 1; SELECT TRUE FROM Rope.Equal[arg, "usletter", FALSE] => { inputWidth ¬ 0.01 * 2.54 * 8.5; -- meters inputHeight ¬ 0.01 * 2.54 * 11.0; -- meters }; Rope.Equal[arg, "uslegal", FALSE] => { inputWidth ¬ 0.01 * 2.54 * 8.5; -- meters inputHeight ¬ 0.01 * 2.54 * 14.0; -- meters }; Rope.Equal[arg, "usledger", FALSE] => { inputWidth ¬ 0.01 * 2.54 * 11.0; -- meters inputHeight ¬ 0.01 * 2.54 * 17.0; -- meters }; Rope.Equal[arg, "a4", FALSE] => { inputWidth ¬ 0.210; -- meters inputHeight ¬ 0.297; -- meters }; ENDCASE => msg ¬ "known paper sizes are: usletter, uslegal, usledger, a4"; }; ENDCASE => { msg ¬ "Invalid option"; GOTO Bad }; } ELSE { SELECT TRUE FROM Rope.Equal[argv[i], "_"], Rope.Equal[argv[i], "¬"] => { IF input = NIL THEN { msg ¬ "No output file specified"; GOTO Bad }; arrowSpecified ¬ TRUE; }; input = NIL => input ¬ argv[i]; (output = NIL) AND arrowSpecified => { output ¬ input; input ¬ argv[i]; }; ENDCASE => { IF arrowSpecified THEN msg ¬ "Too much in command line" ELSE msg ¬ "Missing \"¬\""; GOTO Bad; }; }; i ¬ i.SUCC; ENDLOOP; IF scaleFactor = 0.0 THEN scaleFactor ¬ MIN[(paperHeight*0.5)/inputWidth, paperWidth/inputHeight]; IF input = NIL OR output = NIL THEN { msg ¬ "File name missing"; GOTO Bad }; EXITS Bad => { msg ¬ Rope.Cat[msg, ":\n", cmd.procData.doc]}; }; IF argv = NIL THEN RETURN; msg ¬ ProcessArgs[cmd, argv]; IF msg # NIL THEN { result ¬ $Failure; RETURN }; Booklet[output, input, BookletLogProc, cmd.out]; }; doc: ROPE ¬ "Create a new IP master that will print as a booklet (paper folded in half, in correct page order). -b booklet style, no scaling (default) -f scale to fit -s use an arbitrary scaling factor -p specify paper size (default: USLetter) -i specify image size (default: USLetter) -n add page numbers"; Commander.Register["InterpressBooklet", BookletCmd, doc]; Commander.Register["IPBooklet", BookletCmd, doc]; }.