2012年11月26日月曜日

[Java][iText]iTextでPDFを最適化する

iTextを使って、フォントや画像を埋め込んだ複数のPDFを1つのPDFにするケースはよくあると思います。
マージする先のDocumentのPdfWriterと、マージされる各PDFのPdfReaderを使用してマージしたりしますが、この場合、複数のPDFに同一のフォントや画像が埋め込まれていたとしても、出来上がったPDFにはそれらのフォントや画像が全部入ってしまい、PDFのサイズが大きくなってしまいます。
Document doc = new Document();
FileOutputStream fout = new FileOutputStream(new File("hoge.pdf"));
PdfWriter writer = PdfWriter.getInstance(document, fout);

String[] files = {"foo.pdf","bar.pdf","moge.pdf"};
for(int i = 0;i < files.length;i++){
PdfReader reader = new PdfReader(files[i]);
int pageNum = reader.getNumberOfPages();
for(int p = 1;p <= pageNum;p++){
PdfImportedPage page = writer.getImportedPage(reader, p);
PdfContentByte cb = writer.getDirectContent();
cb.addTemplate(page, 1f, 0, 0, 1f, 0, 0);
}
}
例えばこの例だと、foo.pdfとbar.pdfに同一のフォントが入っていた場合でも、出来上がるhoge.pdfには同一の2つのフォントデータが入ってしまいます。

これを回避するには、PdfSmartCopyクラスを使用します。
Document doc = new Document();
FileOutputStream fout = new FileOutputStream(new File("hoge.pdf"));
PdfSmartCopy copy= new PdfSmartCopy(document, fout);

String[] files = {"foo.pdf","bar.pdf","moge.pdf"};
for(int i = 0;i < files.length;i++){
PdfReader reader = new PdfReader(files[i]);
int pageNum = reader.getNumberOfPages();
for(int p = 1;p <= pageNum;p++){
PdfImportedPage page = copy.getImportedPage(reader, p);
copy.addPage(page);
}
}
PdfSmartCopyは内部にPDFリソースのマップを持っており、同一のリソースの場合は同じところを見るようにPDFを生成してくれます。
以下PdfSmartCopyのJavaDocです。
/**
* PdfSmartCopy has the same functionality as PdfCopy,
* but when resources (such as fonts, images,...) are
* encountered, a reference to these resources is saved
* in a cache, so that they can be reused.
* This requires more memory, but reduces the file size
* of the resulting PDF document.
*/
フォントや画像の量にもよると思いますが、私の環境だとAcrobat Professionalの標準的な最適化よりもサイズを小さくすることが出来ました。
PDFのサイズを気にする向きは、これを利用されたらいいと思います。

0 件のコメント:

コメントを投稿