大量の帳票印刷への対応
最近、PDFで帳票を出力するサーバアプリケーションについての本を書き始めました。主に、「サーバ側でデータベースなどを参照して動的にPDFを生成し、ブラウザに返す」という使い方を想定していますが、毎日大量の帳票を出力する業務などでは、その都度ブラウザから印刷を操作するのでは手間がかかり過ぎるという場合もあるでしょう。そこでサーバサイドで印刷する方法についていろいろ調べてみました。AcrobatまたはAdobeReader
AcrobatやAdobeReaderをコマンドラインから実行して指定したファイルを印刷できるようです。http://kb2.adobe.com/jp/cps/510/510705.html
しかし、環境に依存しそうですし、せっかくなのでJavaで書ける方法を探しました。
Java 印刷サービス
J2SEに標準の「Java 印刷サービス」が使えるかどうか試してみました。http://java.sun.com/javase/ja/6/docs/ja/technotes/guides/jps/spec/jpsOverview.fm4.html
このページのサンプルコードはそのままではコンパイルできないので、いろいろ修正を加えて次のようなコードを書きました。
import javax.print.attribute.standard.Sides;
//以下 import 略
public class PdfPrintTest{
public static void main(String[] args){
FileInputStream textStream=null;
try {
textStream = new FileInputStream("Test.pdf");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
if (textStream == null) {
return;
}
DocFlavor myFormat = DocFlavor.INPUT_STREAM.PDF;
Doc myDoc = new SimpleDoc(textStream, myFormat, null);
PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
aset.add(new Copies(1));
aset.add(MediaSizeName.ISO_A4);
aset.add(Sides.DUPLEX);
PrintService service = PrintServiceLookup.lookupDefaultPrintService();
DocPrintJob job = service.createPrintJob();
try {
job.print(myDoc, aset);
System.out.println("test1");
} catch (PrintException e) {
e.printStackTrace();
}
}
}
しかし、このコードを実行するとinvalid flavorというエラーが出てしまいます。DocFlavor.INPUT_STREAM.PDF を指定するには、PDF出力に対応したプリンタ(およびプリンタドライバ)を使う必要があるようです。//以下 import 略
public class PdfPrintTest{
public static void main(String[] args){
FileInputStream textStream=null;
try {
textStream = new FileInputStream("Test.pdf");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
if (textStream == null) {
return;
}
DocFlavor myFormat = DocFlavor.INPUT_STREAM.PDF;
Doc myDoc = new SimpleDoc(textStream, myFormat, null);
PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
aset.add(new Copies(1));
aset.add(MediaSizeName.ISO_A4);
aset.add(Sides.DUPLEX);
PrintService service = PrintServiceLookup.lookupDefaultPrintService();
DocPrintJob job = service.createPrintJob();
try {
job.print(myDoc, aset);
System.out.println("test1");
} catch (PrintException e) {
e.printStackTrace();
}
}
}
PDFBox
ApacheにPDFBoxというPDF処理ライブラリのプロジェクトがあります。http://pdfbox.apache.org/download.html
ここで公開されているバイナリをダウンロードしてみました。このライブラリには、コマンドラインからそのまま実行できるコマンドも含まれていました。次のようなコマンドでPDFファイルを印刷できます。
> java -jar pdfbox-app-1.5.0.jar PrintPDF -silentPrint Test.pdf
一応印刷はできましたが、日本語のメトリック(文字幅の情報)がライブラリの中に含まれていないので文字間隔がだいぶ空いてしまいます。この問題はPDFを生成する際にフォントを埋め込むことで対処できるようです。ウェブアプリケーションでも使いやすいように、次のようなラッパーを書いてみました。
import java.awt.print.PrinterJob;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import org.apache.pdfbox.pdmodel.PDDocument;
import java.io.InputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.awt.print.PrinterException;
public class PdfPrint{
public static void main(String[] args){
if(args.length!=1){
System.out.println("no pdf file specified");
}
try{
InputStream stream = new FileInputStream(args[0]);
print(stream);
}catch(FileNotFoundException e){
System.out.println("file not found");
}
}
public static void print(InputStream is){
try{
PDDocument document = PDDocument.load(is);
PrinterJob printJob = PrinterJob.getPrinterJob();
PrintService service = PrintServiceLookup.lookupDefaultPrintService();
printJob.setPrintService(service);
document.silentPrint( printJob );
document.close();
}catch(IOException e){
e.printStackTrace();
}catch(PrinterException e){
e.printStackTrace();
}
}
}
まだ試していませんが、サーバサイドで生成したPDFのOutputStreamをInputStreamに変換してprintメソッドに渡せばサーバアプリケーションで動的に生成したPDFデータを直接プリンタに送ることができると思います。たとえば、ショッピングサイトなどで、購入の決済処理と同時に帳票を印刷することができます。import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import org.apache.pdfbox.pdmodel.PDDocument;
import java.io.InputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.awt.print.PrinterException;
public class PdfPrint{
public static void main(String[] args){
if(args.length!=1){
System.out.println("no pdf file specified");
}
try{
InputStream stream = new FileInputStream(args[0]);
print(stream);
}catch(FileNotFoundException e){
System.out.println("file not found");
}
}
public static void print(InputStream is){
try{
PDDocument document = PDDocument.load(is);
PrinterJob printJob = PrinterJob.getPrinterJob();
PrintService service = PrintServiceLookup.lookupDefaultPrintService();
printJob.setPrintService(service);
document.silentPrint( printJob );
document.close();
}catch(IOException e){
e.printStackTrace();
}catch(PrinterException e){
e.printStackTrace();
}
}
}
投稿:竹形 誠司[takegata]/2011年 05月 24日 02時 12分
/更新:2011年 05月 24日 02時 16分