I need to write a Java method in order to send postscript files to a printer in one job. In other words, I need to reproduce the effect of the following Unix command:
lp -d printer file1.ps file2.ps file3.ps
First I thought I could just concatenate the PS files (using classes like ConcatInputStream and PrintJobWatcher). But the resulting merged PS file is not always valid.
If it helps, here is my current code (I have been asked to do it in Groovy):
/**
* Prints the {@code files} {@code copyCount} times using
* {@code printService}.
* <p>
* Exceptions may be thrown.
* @param printService Print service
* @param files Groovy array of {@code File} objects
* @param copyCount Number of copies to print
*/
private static void printJob(
PrintService printService,
def files,
int copyCount) {
// No multiple copy support for PS file, must do it manually
copyCount.times { i ->
InputStream inputStream = null
try {
log.debug("Create stream for copy #${i}")
inputStream = new ConcatInputStream()
for (def file in files) {
if (file != null) {
log.debug("Add '${file.absolutePath}' to the stream")
((ConcatInputStream)inputStream).addInputStream(
new FileInputStream(file))
}
}
log.debug("Create document")
Doc doc = new SimpleDoc(
inputStream, DocFlavor.INPUT_STREAM.AUTOSENSE, null)
log.debug("Create print job")
DocPrintJob docPrintJob = printService.createPrintJob()
log.debug("Create watcher")
PrintJobWatcher watcher = new PrintJobWatcher(docPrintJob)
log.debug("Print copy #${i}")
docPrintJob.print(doc, null)
log.debug("Wait for completion")
watcher.waitForDone()
} finally {
if (inputStream) log.debug("Close the stream")
inputStream?.close()
}
}
}
I’m not allowed to convert the PS into PDF.
I read here that I could insert false 0 startjob pop
between the PS files. But then would there be only one job?
I may be confusing the concept of "jobs"...
I didn’t find a post on the topic (sending multiple PS files to the printer in one job). The solution may be so obvious that it blinded me, that why I posted this question.
My next attempt will be to execute lp
from the class, even if it looks dirty I know I can make it work that way... If you know a simpler way, please tell me.
Edit:
Executing lp
(as below) works well:
/**
* Prints the {@code files} {@code copyCount} times using an executable.
* <p>
* Exceptions may be thrown.
* @param config ConfigObject containing closures for building the
* command line to the printing executable, and to analyze the
* return code. Example of config file:
*
* print {
* commandClosure = { printerName, files ->
* [
* 'lp',
* '-d', printerName,
* files.collect{ it.absolutePath }
* ].flatten()
* }
* errorClosure = { returnCode, stdout, stderr -> returnCode != 0 }
* warnClosure = { returnCode, stdout, stderr ->
* !stderr?.isAllWhitespace() }
* }
*
* @param printerName Printer name
* @param files Groovy array of {@code File} objects
* @param copyCount Number of copies to print
*/
private static void printJob(
ConfigObject config,
String printerName,
def files,
int copyCount) {
files.removeAll([null])
Integer copyCount = job.copyCountString.toInteger()
copyCount.times { i ->
def command = config.print.commandClosure(printerName, files)
log.debug("Command: `" + command.join(' ') + "`")
def proc = command.execute()
proc.waitFor()
def returnCode = proc.exitValue()
def stdout = proc.in.text
def stderr = proc.err.text
def debugString = "`" + command.join(' ') +
"`\nReturn code: " + returnCode +
"\nSTDOUT:\n" + stdout + "\nSTDERR:\n" + stderr
if (config.print.errorClosure(returnCode, stdout, stderr)) {
log.error("Error while calling ${debugString}")
throw new PrintException("Error while calling ${debugString}")
} else if (config.print.warnClosure(returnCode, stdout, stderr)) {
log.warn("Warnings while calling ${debugString}")
} else {
log.debug("Command successful ${debugString}")
}
}
}
Even if I would prefer not to use an external executable... This issue is not anymore critical for me. I will accept an answer if it does not require the call to an external executable.