* 利用iText五步创建一个PDF文件:
* 第一步,创建一个 iTextSharp.text.Document对象的实例:Document document = new Document();
* 第二步,为该Document创建一个Writer实例:PdfWriter.getInstance(document, new FileStream("demo.pdf", FileMode.Create));
* 第三步,打开当前Document document.Open();
* 第四步,为当前Document添加内容: document.Add(new Paragraph("Hello World"));
* 第五步,关闭Document document.Close();
主要涉及的类有Document,Paragraph,Font,PdfPTable,PdfPCell。具体涉及的方法参数比较多,需要自己多尝试体会。如果内容是中文的话,需要注意设置下编码,否则内容不显示
/**
* 获取支持中文编码的Font
*
* @param size
* @return
* @throws IOException
* @throws DocumentException
*/
public static Font getPdfChineseFont(int size) throws IOException, DocumentException {
BaseFont bfChinese = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
Font fontChinese = new Font(bfChinese, size, Font.NORMAL);
return fontChinese;
}
依赖的JAR
com.itextpdf
itextpdf
5.5.13
com.itextpdf
itext-asian
5.2.0
com.itextpdf.tool
xmlworker
5.5.13
org.icepdf.os
icepdf-core
6.1.2
1 ItemxtPdf生成pdf的demo
package org.springblade.modules.lecoffee.utils;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import org.apache.commons.io.FileUtils;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@Component
public class ItextPdfUtilsDemo {
/**
* 利用iText五步创建一个PDF文件:
* 第一步,创建一个 iTextSharp.text.Document对象的实例:Document document = new Document();
* 第二步,为该Document创建一个Writer实例:PdfWriter.getInstance(document, new FileStream("demo.pdf", FileMode.Create));
* 第三步,打开当前Document document.Open();
* 第四步,为当前Document添加内容: document.Add(new Paragraph("Hello World"));
* 第五步,关闭Document document.Close();
*/
public static void createPdf2() throws Exception {
// 基本设置
FileOutputStream fos = new FileOutputStream("D:\\F\\down\\demo.pdf");
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, fos);
writer.setViewerPreferences(PdfWriter.PageModeUseThumbs);
//设置纸张大小
document.setPageSize(PageSize.A4);
document.open();
document = setHeaderPic(document, "C:\\uploadFiles\\logo.jpg");
setHeader(document);
//手动新页面
document.newPage();
// table 列宽--这里是四列
float[] widths = {131, 233, 92, 69};
PdfPTable table = new PdfPTable(widths);
// A4的595减去两个边距35*2
table.setTotalWidth(525);
// 固定table的宽度
table.setLockedWidth(true);
table.setHorizontalAlignment(Element.ALIGN_CENTER);
String[] colArr = {"套餐类型", "套餐明细", "费用", "数量"};
String[][] datas = {{"套餐1", "明细1", "费用1", "数量1"}, {"套餐2", "明细2", "费用2", "数量2"}, {"套餐3", "明细3", "费用3", "数量3"}};
/**
* table基本组成是cell
* addCell(PdfCell cell) 方法会将一个个的cell依次加入到table中,添加到最后一列后会自动换行
*/
for (int i = 0; i < colArr.length; i++) {
PdfPCell pdfCell = new PdfPCell(); //表格的单元格
pdfCell.setMinimumHeight(30);//设置表格行高
pdfCell.setHorizontalAlignment(Element.ALIGN_CENTER);
pdfCell.setVerticalAlignment(Element.ALIGN_MIDDLE);
//左右侧边框不显示
pdfCell.disableBorderSide(PdfPCell.LEFT);
pdfCell.disableBorderSide(PdfPCell.RIGHT);
// 设置边框样式,粗细,背景色
// pdfCell.setBorder(PdfPCell.TOP);
pdfCell.setBorderWidth(1);
pdfCell.setBorderColor(new BaseColor(200, 200, 200));
// 背景色
// pdfCell.setBackgroundColor(new BaseColor(68,114,196));
//文本样式
Font font = getPdfChineseFont(12);
font.setSize(12);
font.setStyle(Font.BOLD);
Paragraph paragraph = new Paragraph(colArr[i], font);
pdfCell.setPhrase(paragraph);
table.addCell(pdfCell);
}
for (int i = 0; i < datas.length; i++) {
for (int j = 0; j < datas[i].length; j++) {
PdfPCell pdfCell = new PdfPCell();
pdfCell.setHorizontalAlignment(Element.ALIGN_CENTER);
pdfCell.setVerticalAlignment(Element.ALIGN_MIDDLE);
pdfCell.setBackgroundColor(new BaseColor(0xdd7e6b));
pdfCell.setBorderWidthTop(0.1f);
pdfCell.setBorderWidthBottom(0.1f);
pdfCell.setBorderWidthLeft(0.1f);
pdfCell.setBorderWidthRight(0.1f);
pdfCell.setBorderColorBottom(new BaseColor(0x674ea7));
pdfCell.setBorderColorLeft(new BaseColor(0x674ea7));
pdfCell.setBorderColorRight(new BaseColor(0x674ea7));
pdfCell.setBorderColorTop(new BaseColor(0x674ea7));
Font font = getPdfChineseFont(12);
Paragraph paragraph = new Paragraph(datas[i][j], font);
pdfCell.setPhrase(paragraph);
table.addCell(pdfCell);
}
}
//添加图片,添加的图片需要提供本地地址
byte[] bt = FileUtils.readFileToByteArray(new File("D:\\F\\down/back.jpg"));
PdfPCell pdfCell = new PdfPCell();
pdfCell.setImage(Image.getInstance(bt));//插入图片
table.addCell(pdfCell);
table.addCell(new PdfPCell());
table.addCell(new PdfPCell());
table.addCell(new PdfPCell());
// 合并单元格
PdfPCell pdfCell2 = new PdfPCell();
pdfCell2.setMinimumHeight(30);
pdfCell2.setHorizontalAlignment(Element.ALIGN_CENTER);
pdfCell2.setVerticalAlignment(Element.ALIGN_MIDDLE);
Font font = getPdfChineseFont(12);
pdfCell2.setRowspan(1);
pdfCell2.setColspan(4);
// pdfCell2.setBorder(pdfCell2.BOTTOM+PdfPCell.LEFT);
pdfCell2.setBorderWidth(2);
pdfCell2.setHorizontalAlignment(Element.ALIGN_RIGHT);
Paragraph paragraph = new Paragraph("总价:4896 元\n仅首次", font);
pdfCell2.setPhrase(paragraph);
table.addCell(pdfCell2);
document.add(table);
document.close();
}
public static Document setHeaderPic(Document document, String mImgPath) throws Exception {
Image tImgCover = Image.getInstance(mImgPath );
/* 设置图片的位置 */
tImgCover.setAbsolutePosition(440, 772);
/* 设置图片的大小 */
tImgCover.scaleAbsolute(80, 39);
document.add(tImgCover);
return document;
}
public static Document setHeader(Document document) throws Exception {
Paragraph title = new Paragraph();
Font fontTile = getPdfChineseFont(16);
fontTile.setStyle(Font.BOLD);
title.setFont(fontTile);
title.add("\n\n\n\n雨巷");
title.setAlignment(Paragraph.ALIGN_CENTER);
document.add(title);
Paragraph content = new Paragraph();
Font fontContent = getPdfChineseFont(12);
content.setFont(fontContent);
content.add("撑着油纸伞,独自 \n" +
"彷徨在悠长、悠长 \n" +
"又寂寥的雨巷 \n" +
"我希望逢着 \n" +
"一个丁香一样地 \n" +
"结着愁怨的姑娘 ");
content.setAlignment(Paragraph.ALIGN_CENTER);
document.add(content);
return document;
}
public static void main(String[] args) throws Exception {
createPdf2();
}
/**
* 获取支持中文编码的Font
*
* @param size
* @return
* @throws IOException
* @throws DocumentException
*/
public static Font getPdfChineseFont(int size) throws IOException, DocumentException {
BaseFont bfChinese = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
Font fontChinese = new Font(bfChinese, size, Font.NORMAL);
return fontChinese;
}
}
结果:
2 html 生成pdf,有几个注意的点。
2.1 标签语法比较严格,不能有不完整的标签"
2.2 不能引用外部样式和js,所有的代码最好在body标签内;
2.3 有些语法单位不支持或者不起作用。
2.4 不同的标签在生成pdf后处理方式可能不一致比如
hello
和生成pdf后间距等会有出入;整体来说,hmtl转pdf的优点就是代码相对简单,但是对于样式要求严格的场景也会比较麻烦,会有不小的出入。
1个小建议:html转pdf,最好一开始先调用一下document.newPage()这个方法,这样会避免生成的pdf第一页的间距与后面不一致的情况。然后 img标签最好设置一下高度和宽度,且图片的协议最好是https。
package org.springblade.modules.lecoffee.utils;
import com.itextpdf.text.Document;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import lombok.extern.log4j.Log4j;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
@Log4j
@Component
public class Html2PdfPageDemo extends XMLWorkerFontProvider {
public static void htmlToPDFPage(List htmlString, String pdfPath) throws Exception {
System.out.println(htmlString);
Document document = new Document(PageSize.A4);
PdfWriter pdfWriter = PdfWriter.getInstance(document, new FileOutputStream(pdfPath));
document.open();
document.setMargins(0, 0, 0, 0);
document.addAuthor("big");
document.addCreator("q");
document.addSubject("subject");
document.addCreationDate();
document.addTitle("主题");
XMLWorkerHelper worker = XMLWorkerHelper.getInstance();
InputStream inputStream = null;
document.newPage();
worker.parseXHtml(pdfWriter, document, new ByteArrayInputStream(pageHome.getBytes("UTF-8")), inputStream, Charset.forName("UTF-8"), new AsianFontProvider());
for (String html : htmlString) {
document.newPage();
worker.parseXHtml(pdfWriter, document, new ByteArrayInputStream(html.getBytes("UTF-8")), inputStream, Charset.forName("UTF-8"), new AsianFontProvider());
}
document.close();
}
static String pageHome ="\t\n" +
"\t\t\n" +
"\t\t\n" +
"\t\t\t
\n" +
"\t\t\n" +
"\t\t
\n" +
"\t\t
\n" +
"\t\t\n" +
"\t\t\t\n" +
"\t\t\t\tAre you ok? \n" +
"\t\t\t\t
\n" +
"\t\t\t\tHow are you \n" +
"\t\t\t\t
\n" +
"\t\t\t\tfine thank you\n" +
"\t\t\t\n" +
"\t\t\n" +
"\t";
static String pageTable = "\t\n" +
"\t\t\n" +
"\t\t\n" +
"\t\t\t
\n" +
"\t\t\n" +
"\t\t\n" +
"\t\t\t#planName#
\n" +
"\t\t\t
\n" +
"\t\t\t\n" +
"\t\t\t\t\n" +
"\t\t\t\t\t\n" +
"\t\t\t\t\t\t\n" +
"\t\t\t\t\t\t\t套餐类型 \n" +
"\t\t\t\t\t\t\t 套餐明细 \n" +
"\t\t\t\t\t\t\t费用 \n" +
"\t\t\t\t\t\t\t数量 \n" +
"\t\t\t\t\t\t \n" +
"\t\t\t\t\t\t\n" +
"\t\t\t\t\t\t\t\n" +
"\t\t\t\t\t\t\t\t
\n" +
"\t\t\t\t\t\t\t\t#mealName#\n" +
"\t\t\t\t\t\t\t \n" +
"\t\t\t\t\t\t\t\n" +
"\t\t\t\t\t\t\t\t#mealDetail#\n" +
"\t\t\t\t\t\t\t \n" +
"\t\t\t\t\t\t\t#mealPrice#元/月(套) \n" +
"\t\t\t\t\t\t\t#mealAmount# \n" +
"\t\t\t\t\t\t \n" +
"\t\t\t\t\t\t\n" +
"\t\t\t\t\t\t\t#packageName# \n" +
"\t\t\t\t\t\t\t\n" +
"\t\t\t\t\t\t\t\t#packageDetail#\n" +
"\t\t\t\t\t\t\t \n" +
"\t\t\t\t\t\t\t#packagePrice#元/包 \n" +
"\t\t\t\t\t\t\t#packageAmount# \n" +
"\t\t\t\t\t\t \n" +
"\t\t\t\t\t\t\n" +
"\t\t\t\t\t\t\t\n" +
"\t\t\t\t\t\t\t\t合计:#total#元\n" +
"\t\t\t\t\t\t\t \n" +
"\t\t\t\t\t\t \n" +
"\t\t\t\t\t\n" +
"\t\t\t\t
\n" +
"\t\t\t\n" +
"\t\t\n" +
"\t";
public static void main(String[] args) throws Exception {
System.out.println("hehehe");
ListhtmlList = new ArrayList<>();
htmlList.add(pageTable);
htmlToPDFPage(htmlList, "D:\\F\\down\\html2Pdf.pdf");
System.out.println("hehehe");
}
}
将生成的pdf和,html在浏览器的效果相比较的话,table的效果差距还是比较明显的
3 pdf转图片,试了好几版,发现这版效果比较满意。当然,图片是针对pdf的每一页的内容生成。
package org.springblade.modules.lecoffee.utils;
import org.icepdf.core.pobjects.Document;
import org.icepdf.core.util.GraphicsRenderingHints;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.IOException;
public class PDFToImage {
public static void pdf2Pic(String pdfPath, String path, String fileName) throws Exception {
Document document = new Document();
document.setFile(pdfPath);
//缩放比例
float scale = 2.5f;
//旋转角度
float rotation = 0f;
for (int i = 0; i < document.getNumberOfPages(); i++) {
BufferedImage image = (BufferedImage)
document.getPageImage(i, GraphicsRenderingHints.SCREEN, org.icepdf.core.pobjects.Page.BOUNDARY_CROPBOX, rotation, scale);
RenderedImage rendImage = image;
try {
File fileDir = new File(path);
if (!fileDir.exists()) {
fileDir.mkdirs();
}
String imgName = fileName + i + ".png";
File file = new File(path + imgName);
ImageIO.write(rendImage, "png", file);
} catch (IOException e) {
e.printStackTrace();
}
image.flush();
}
document.dispose();
}
public static void main(String[] args) throws Exception {
String filePath = "D:\\F\\down\\demo.pdf";
pdf2Pic(filePath, "D:\\F\\down\\demo\\", "12857584447386337291_");
}
}
结果:
生成的效果还不错
4 关于乱码:
通过ItemxtPdf生成pdf和用pdf转img这两步,对于中文有时候会出现乱码。一般是由于代码的字体在系统找不到导致的,
linux系统下字体会放在/usr/share/fonts 这个目录下。如果目录不存在,一般需要重新安装下字体;
yum -y install fontconfig #安装字体库:
fc-cache -fv #刷新字体库,使新添加、安装的字体生效
windows系统的话,字体一般在这个文件夹下 C:\Windows\Fonts
5 自定义字体
如果想自定义字体,可以先把相应的字体文件放置到对应的目录下调用即可。需要修改下获取字体的代码
public static Font getPdfChineseFontNew(int size) throws Exception {
//默认linux字体位置
String fontUrl = "/usr/share/fonts" + File.separator + "SimHei.ttf";
//获取系统类型
String os = System.getProperties().getProperty("os.name");
if (os.startsWith("win") || os.startsWith("Win")) {
fontUrl = "C:\\Windows\\Fonts" + File.separator + "SimHei.ttf";
}
BaseFont baseFont;
try {
baseFont = BaseFont.createFont(fontUrl, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
} catch (Exception e) {
//默认宋体
e.printStackTrace();
baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
}
return new Font(baseFont, size, Font.NORMAL, BaseColor.BLACK);
}