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のサイズを気にする向きは、これを利用されたらいいと思います。