ホームページ > 記事 > ウェブフロントエンド > iText を使用して PDF_html/css_WEB-ITnose を生成する
iText のアップデートは大きく変更されており、初期のバージョンでは PDF スタイルに欠陥がある可能性があります。私が使用しているのは最新の 5.5.6 パッケージだけです。
1. Maven の依存関係を追加します。
itext コア パッケージと xmlworder フォント パッケージ
<dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.5.6</version></dependency>
<dependency> <groupId>com.itextpdf.tool</groupId> <artifactId>xmlworker</artifactId> <version>5.5.6</version></dependency>2. PDF を直接生成する方法は非常に簡単です。テキストを使用して段落などを作成し、フォント、間隔を設定するだけです。と位置合わせ あとは待って、Hello World の例を取得します。
package com.thunisoft.demo; import java.io.FileOutputStream; import com.itextpdf.text.Document; import com.itextpdf.text.Font; import com.itextpdf.text.FontFactoryImp; import com.itextpdf.text.PageSize; import com.itextpdf.text.Paragraph; import com.itextpdf.text.pdf.BaseFont; import com.itextpdf.text.pdf.PdfPHeaderCell; import com.itextpdf.text.pdf.PdfPTable; import com.itextpdf.text.pdf.PdfWriter; /** * 创建一个简单pdf文档,文字、表格 * * @author zhangwd * @version 1.0 * */ public class PdfDemo_1 { private static void create() throws Exception { // 创建一个文档(默认大小A4,边距36, 36, 36, 36) Document document = new Document(); // 设置文档大小 document.setPageSize(PageSize.A4); // 设置边距,单位都是像素,换算大约1厘米=28.33像素 document.setMargins(50, 50, 50, 50); // 创建writer,通过writer将文档写入磁盘 PdfWriter writer = PdfWriter.getInstance(document,newFileOutputStream("c:/demo.1.pdf")); // demo String title = "凉州词"; String content = "黄河远上白云间,一片孤城万仞山。羌笛何须怨杨柳,春风不度玉门关。"; // 定义字体 FontFactoryImp ffi = new FontFactoryImp(); // 注册全部默认字体目录,windows会自动找fonts文件夹的,返回值为注册到了多少字体 ffi.registerDirectories(); // 获取字体,其实不用这么麻烦,后面有简单方法 Font font = ffi.getFont("宋体",BaseFont.IDENTITY_H,BaseFont.EMBEDDED, 12, Font.UNDEFINED, null); // 打开文档,只有打开后才能往里面加东西 document.open(); // 设置作者 document.addAuthor("王之涣"); // 设置创建者 document.addCreator("王之涣"); // 设置主题 document.addSubject("测试"); // 设置标题 document.addTitle("凉州词"); // 增加一个段落 document.add(new Paragraph(title, font)); document.add(new Paragraph(content, font)); document.add(new Paragraph("\n\r", font)); // 创建表格,5列的表格 PdfPTable table = new PdfPTable(4); table.setTotalWidth(PageSize.A4.getWidth()- 100); table.setLockedWidth(true); // 创建头 PdfPHeaderCell header = new PdfPHeaderCell(); header.addElement(new Paragraph(title, font)); header.setColspan(4); table.addCell(header); // 添加内容 table.addCell(new Paragraph("黄河远上白云间",font)); table.addCell(new Paragraph("一片孤城万仞山",font)); table.addCell(new Paragraph("羌笛何须怨杨柳",font)); table.addCell(new Paragraph("春风不度玉门关",font)); document.add(table); // 关闭文档,才能输出 document.close(); writer.close(); } public static void main(String[] args) throws Exception { create(); } }3. フォント
私たちのプロジェクト ドキュメント フォントは、Song 王朝 (99% がこれを使用)、中国語の模倣 Song (Office のインストール後に提供される) を使用するなど、非常に特殊です。 imitation Song_GB2312 待って、PDF フォントについて調べてみました。実際、バージョン 5.0 以降では、中国語フォントを使用する方法がたくさんあります。
引き続き HelloWorld の例:
import java.io.FileOutputStream; import com.itextpdf.text.Document; import com.itextpdf.text.Font; import com.itextpdf.text.FontFactoryImp; import com.itextpdf.text.Paragraph; import com.itextpdf.text.pdf.PdfWriter; import com.itextpdf.tool.xml.XMLWorkerFontProvider; /** * 字体 * * @author zhangwd * @version 1.0 * */ public class PdfDemo_2 { public static void create() throws Exception { Document document = new Document(); PdfWriter writer = PdfWriter.getInstance(document,new FileOutputStream("c:/demo.2.pdf")); String title = "凉州词"; String content = "黄河远上白云间,一片孤城万仞山。羌笛何须怨杨柳,春风不度玉门关。"; document.open(); document.add(newParagraph(title, getFont("方正兰亭黑简体"))); document.add(newParagraph(content, getFont("迷你简娃娃篆"))); document.close(); writer.close(); } private static Font getFont(String fontName) { // xmlworker主要功能是html转pdf用的,非常好用,也是itext官方的 // 这个是xmlworker提供的获取字体方法,很方便,对中文支持很好 FontFactoryImp fp = newXMLWorkerFontProvider(); // 注册指定的字体目录,默认构造方法中会注册全部目录,我这里注册了src/font目录 fp.registerDirectory(PdfDemo_2.class.getClassLoader().getResource("font").getFile(), true); // 最好的地方是直接支持获取中文的名字 return fp.getFont(fontName); // 当然,最好的方法是自己继承XMLWorkerFontProvider,提供一些常用字体,简单方便 } public static void main(String[]args) throws Exception { create(); } }XmlWorker の XMLWorkerFontProvider は、フォントを取得するための非常に便利な方法を提供します。
1. フォルダーを登録すると、そのフォルダー内の任意のフォントを取得できます。私のデモのフォントなど
2. getFont (フォント名) を使用して取得しますが、フォント名はどこから来たのでしょうか?
3. ヘッダーとフッター
PdfPageEvent は、PDF が作成されるときに、各ページがロードされた後にヘッダーとフッターが書き込まれるいくつかのイベントを提供します。
各ページにページ番号を付けるのは非常に簡単ですが、iTextはストリーミングモードで書き込むと最後までページ数が分かるので面倒です。総ページ数を表示するのは面倒ですが、面倒だからできないというわけではありません。
実際、iText はリリース テンプレート メソッドを呼び出した後にのみ PdfTemplate を OutputStream に書き込みます。そうでない場合、オブジェクトはドキュメントが閉じるまでメモリに保存されます。
したがって、最後にドキュメントを閉じる前に、PdfTemplate を使用して合計ページ番号を書き込むことができます。これは、最初にプレースホルダーを記述し、次にそれを均一に置き換えることとして理解できます。
まだ HelloWorld の例:
<span style="font-size:18px;">package com.thunisoft.demo; import java.io.FileOutputStream; import com.itextpdf.text.BaseColor; import com.itextpdf.text.Document; import com.itextpdf.text.Element; import com.itextpdf.text.ExceptionConverter; import com.itextpdf.text.Font; import com.itextpdf.text.Image; import com.itextpdf.text.PageSize; import com.itextpdf.text.Paragraph; import com.itextpdf.text.Rectangle; import com.itextpdf.text.pdf.ColumnText; import com.itextpdf.text.pdf.PdfContentByte; import com.itextpdf.text.pdf.PdfPCell; import com.itextpdf.text.pdf.PdfPTable; import com.itextpdf.text.pdf.PdfPageEventHelper; import com.itextpdf.text.pdf.PdfTemplate; import com.itextpdf.text.pdf.PdfWriter; import com.itextpdf.tool.xml.XMLWorkerFontProvider; /** * 页眉、页脚 * * @author zhangwd * @version 1.0 * */ public class PdfDemo_3 { public static void create() throws Exception { Document document = newDocument(PageSize.A4, 50, 50, 50, 50); PdfWriter writer = PdfWriter.getInstance(document,new FileOutputStream("c:/demo.3.pdf")); // 增加页眉页脚 writer.setPageEvent(newMyHeaderFooter()); String title = "凉州词"; String content = "黄河远上白云间,一片孤城万仞山。羌笛何须怨杨柳,春风不度玉门关。"; document.open(); Font font = newXMLWorkerFontProvider().getFont("宋体"); for (int i = 0; i <100; i++) { document.add(newParagraph(title, font)); document.add(new Paragraph(content,font)); document.add(new Paragraph("\n")); } document.close(); writer.close(); } public static void main(String[]args) throws Exception { create(); } } /** * iText5中并没有之前版本HeaderFooter对象设置页眉和页脚<br> * 不过,可以利用PdfPageEventHelper来完成页眉页脚的设置工作。<br> * 就是在页面完成但写入内容之前触发事件,插入页眉、页脚、水印等。<br> * * @author zhangwd * @version 1.0 * */ class MyHeaderFooter extends PdfPageEventHelper { Font font = new XMLWorkerFontProvider().getFont("宋体", 12, BaseColor.RED); // 总页数 PdfTemplate totalPage; // 打开文档时,创建一个总页数的模版 public void onOpenDocument(PdfWriter writer,Document document) { PdfContentByte cb =writer.getDirectContent(); totalPage = cb.createTemplate(30, 16); } // 一页加载完成触发,写入页眉和页脚 public void onEndPage(PdfWriter writer, Documentdocument) { PdfPTable table = new PdfPTable(3); try { table.setTotalWidth(PageSize.A4.getWidth() - 100); table.setWidths(new int[] { 24, 24, 3}); table.setLockedWidth(true); table.getDefaultCell().setFixedHeight(-10); table.getDefaultCell().setBorder(Rectangle.BOTTOM); table.addCell(new Paragraph("我是文字", font));// 可以直接使用addCell(str),不过不能指定字体,中文无法显示 table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_RIGHT); table.addCell(new Paragraph("第" + writer.getPageNumber() + "页/", font)); // 总页数 PdfPCell cell = new PdfPCell(Image.getInstance(totalPage)); cell.setBorder(Rectangle.BOTTOM); table.addCell(cell); // 将页眉写到document中,位置可以指定,指定到下面就是页脚 table.writeSelectedRows(0, -1, 50,PageSize.A4.getHeight() - 20, writer.getDirectContent()); } catch (Exception de) { throw new ExceptionConverter(de); } } // 全部完成后,将总页数的pdf模版写到指定位置 public void onCloseDocument(PdfWriter writer,Document document) { String text = "总" + (writer.getPageNumber() - 1) + "页"; ColumnText.showTextAligned(totalPage, Element.ALIGN_LEFT, new Paragraph(text,font), 2, 2, 0); } }4.html to pdf
結果は悪くありませんが、要件は満たしていますが、より複雑で動的に作成されます。表や内容が煩雑であり、ユーザーの文書の内容や形式が変更されると、プログラムを変更する必要があります。
そこで、より良い方法について話し合いました。Xie Guoqing さんの協力に感謝します。
まず HTML を作成し、それを PDF に変換します。デモは次のとおりです。
import java.io.ByteArrayInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import com.itextpdf.text.Document; import com.itextpdf.text.pdf.PdfWriter; import com.itextpdf.tool.xml.XMLWorkerHelper; /** * html转pdf * * @author zhangwd * @version 1.0 * */ public class PdfDemo_4 { public static void create() throws Exception { // html中字体非常郁闷 // 1. html中不指定字体,则默认使用英文字体,中文会不显示。 // 2. html中指定的字体必须是英文名称,如宋体:font-family:SimSun; // 3. html中不能指定自定义字体,必须指定itext支持的字体,还好itext支持字体比较多,常见操作系统带的都支持 // 4. 暂没有找到如何html中支持自定义字体方法,网上都是修改源码实现默认字体中文,也很重要 StringBuilder html = newStringBuilder(); html.append("<html>"); html.append("<bodystyle='font-size:20px;font-family:SimSun;'>"); html.append("<table width='19cm'border='1' cellpadding='0' cellspacing='0'>"); html.append("<tr>"); html.append("<td colspan='2'>凉州词</td>"); html.append("</tr>"); html.append("<tr>"); html.append("<td>黄河远上白云间,一片孤城万仞山。</td>"); html.append("<td>羌笛何须怨杨柳,春风不度玉门关。</td>"); html.append("</tr>"); html.append("</table>"); html.append("</body>"); html.append("</html>"); InputStream is = newByteArrayInputStream(html.toString().getBytes()); OutputStream os = newFileOutputStream("c:/demo.4.pdf"); Document document = new Document(); PdfWriter writer = PdfWriter.getInstance(document,os); document.open(); // 将html转pdf XMLWorkerHelper.getInstance().parseXHtml(writer,document, is); document.close(); } public static void main(String[]args) throws Exception { create(); } }</span>XmlWorker は、現在、公式の iText バージョンでも使用されています。 iText バージョンでは、XHTML から PDF への変換について話すことができ、すべてではありませんが、ほとんどのスタイルとタグをサポートします。
現在、この方法を使用し、HTML ドキュメントを作成し、使用時に HTML 内のマーク ビットを動的に置き換えてから、PDF を生成します。
XHTML を使用して PDF に変換する場合の注意点:
1. HTML でフォントが指定されていない場合は、デフォルトで英語フォントが使用され、中国語フォントは使用されません。インターネット上の多くの人は、ソース コードを変更してデフォルトのフォントを使用することを認識しています。中国語を使用する方法もありますが、それはより面倒なようです。
2. HTML で指定するフォントは英語名である必要があります。
たとえば、Song 王朝: font-family: SimSun; 正しい
4. HTML でカスタム フォントをサポートする方法はまだ見つかっていません。
5. PDF への画像の追加も非常に簡単です。例:
8cc3d76663f400bd453b07b85dd45376 エラーなど、タグは完全に終了する必要があります。076402276aae5dbec7f672f8f4e5cc81 でなければなりません。5. その他
たとえば、いくつかのテンプレート