Java pdf工具
一、依赖
<dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.5.13</version>
</dependency>
<dependency><groupId>com.itextpdf</groupId><artifactId>itext-asian</artifactId><version>5.2.0</version>
</dependency>
<dependency><groupId>org.apache.pdfbox</groupId><artifactId>pdfbox</artifactId><version>2.0.24</version>
</dependency>
二、枚举
- 内容显示方式
public enum CellAlign {LEFT(0),CENTER(1),RIGHT(2),TOP(4),MIDDLE(5),BOTTOM(6);private Integer align;private CellAlign(Integer align) {this.align = align;}public Integer getAlign() {return this.align;}
}
- 数据类型
public enum DataType {TEXT,IMAGE;
}
- 文字样式
public enum TextAttr {TEXTFONT,TEXTCOLOR,TEXTSIZE,BGCOLOR,BORDERCOLOR,;
}
三、异常
public class PdfException extends Exception {private static final long serialVersionUID = 1L;public PdfException(String message) {super(message);}public PdfException(Throwable cause) {super(cause);}public PdfException(String message, Throwable cause) {super(message, cause);}
}
四、相关配置类
方式一:
使用 Adobe Acrobat DC 制作 pdf 模版,根据制作 pdf 模板生成 pdf 使用到的类
- 模版配置
import org.springframework.core.io.ClassPathResource;import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;public class PdfTemplate {/*** pdf 名称*/private String title;/*** pdf 模板*/private InputStream template;/*** 需要填入 pdf 文件中的数据*/private Map<String, PdfData> values;/*** 用于获取 pdf 文件中某些字段的位置信息*/private Map<String, Position> positions;public PdfTemplate() {}public PdfTemplate(String title, InputStream template) {this.title = title;this.template = template;}public PdfTemplate(String title, String templatePath) {this.title = title;try {this.template = new ClassPathResource(templatePath).getInputStream();} catch (IOException e) {throw new RuntimeException(e);}}public PdfTemplate addValue(String key,PdfData value){if(this.values == null){this.values = new HashMap<>();}this.values.put(key,value);return this;}public PdfTemplate addPositions(String key,Position value){if(this.positions == null){this.positions = new HashMap<>();}this.positions.put(key,value);return this;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public InputStream getTemplate() {return template;}public void setTemplate(InputStream template) {this.template = template;}public Map<String, PdfData> getValues() {return values;}public void setValues(Map<String, PdfData> values) {this.values = values;}public Map<String, Position> getPositions() {return positions;}public void setPositions(Map<String, Position> positions) {this.positions = positions;}
}
- 数据信息类
import com.itextpdf.text.Image;
import com.kuroshiro.pdf.enums.DataType;
import com.kuroshiro.pdf.enums.TextAttr;import java.util.HashMap;
import java.util.Map;public class PdfData {private DataType type = DataType.TEXT;/*** pdf 对应 key 需要填入的值*/private String value;/*** pdf 对应 key 需要填入的值*/private Image image;/*** 设置字体样式。有效的属性名称是:* textfont - 设置文本字体。该条目的值是一个 BaseFont。* textcolor - 设置文本颜色。该条目的值是一个 BaseColor。* textsize - 设置文本大小。该表项的值为 Float 类型。* bgcolor - 设置背景颜色。该条目的值是一个 BaseColor。如果为null则删除背景。* bordercolor - 设置边框颜色。该条目的值是一个 BaseColor。如果为null则删除边框。*/private Map<TextAttr, Object> textStyles;public PdfData(String value) {this.value = value;}public PdfData(Image image) {this.type = DataType.IMAGE;this.image = image;}public PdfData addTextStyle(TextAttr key,Object value){if(this.textStyles == null){this.textStyles = new HashMap<>();}this.textStyles.put(key,value);return this;}public String getValue() {return value;}public void setValue(String value) {this.value = value;}public DataType getType() {return type;}public void setType(DataType type) {this.type = type;}public Image getImage() {return image;}public void setImage(Image image) {this.image = image;}public Map<TextAttr, Object> getTextStyles() {return textStyles;}public void setTextStyles(Map<TextAttr, Object> textStyles) {this.textStyles = textStyles;}
}
- 位置信息类
import java.math.BigDecimal;
import java.util.Objects;public class Position {private BigDecimal page;private BigDecimal positionX;private BigDecimal positionY;public Position() {}public Position(BigDecimal page, BigDecimal positionX, BigDecimal positionY) {this.page = page;this.positionX = positionX;this.positionY = positionY;}public Position(int page, int positionX, int positionY) {this.page = BigDecimal.valueOf((long)page);this.positionX = BigDecimal.valueOf((long)positionX);this.positionY = BigDecimal.valueOf((long)positionY);}public boolean equals(Object o) {if (this == o) {return true;} else if (o != null && this.getClass() == o.getClass()) {Position postion = (Position)o;return Objects.equals(this.page.intValue(), postion.page.intValue()) && Objects.equals(this.positionX.intValue(), postion.positionX.intValue()) && Objects.equals(this.positionY.intValue(), postion.positionY.intValue());} else {return false;}}public int hashCode() {return Objects.hash(new Object[]{this.page, this.positionX, this.positionY});}public BigDecimal getPage() {return page;}public void setPage(BigDecimal page) {this.page = page;}public BigDecimal getPositionX() {return positionX;}public void setPositionX(BigDecimal positionX) {this.positionX = positionX;}public BigDecimal getPositionY() {return positionY;}public void setPositionY(BigDecimal positionY) {this.positionY = positionY;}
}
方式二:
创建简单的 table 形式的 pdf
- Table 配置
import java.util.ArrayList;
import java.util.List;public class PdfTable {/*** 标题*/private String title;/*** 标题字体大小*/private Float fontSize = 21.0F;/*** table 列数*/private int columns = 1;/*** table cell 信息*/private List<PdfTableCell> cells;/*** 标题是否需要边框*/private boolean haveBorder = false;/*** 列宽比例*/private float[] columnWidths;public PdfTable(String title) {this.title = title;}public PdfTable(String title, boolean haveBorder) {this.title = title;this.haveBorder = haveBorder;}public PdfTable(String title,int columns) {this.title = title;this.columns = columns<1?1:columns;}public PdfTable(String title,int columns, boolean haveBorder) {this.title = title;this.columns = columns<1?1:columns;this.haveBorder = haveBorder;}public PdfTable(String title, Float fontSize, int columns) {this.title = title;this.fontSize = fontSize;this.columns = columns<1?1:columns;}public PdfTable(String title, Float fontSize, int columns, boolean haveBorder) {this.title = title;this.fontSize = fontSize;this.columns = columns<1?1:columns;this.haveBorder = haveBorder;}public PdfTable addCell(PdfTableCell cell){if(cells == null){cells = new ArrayList(){{add(cell);}};}else{cells.add(cell);}return this;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public Float getFontSize() {return fontSize;}public void setFontSize(Float fontSize) {this.fontSize = fontSize;}public int getColumns() {return columns;}public void setColumns(int columns) {this.columns = columns;}public List<PdfTableCell> getCells() {return cells;}public void setCells(List<PdfTableCell> cells) {this.cells = cells;}public boolean isHaveBorder() {return haveBorder;}public void setHaveBorder(boolean haveBorder) {this.haveBorder = haveBorder;}public float[] getColumnWidths() {return columnWidths;}public void setColumnWidths(float[] columnWidths) {this.columnWidths = columnWidths;}
}
- Cell 配置
import com.itextpdf.text.Image;
import com.kuroshiro.pdf.enums.CellAlign;
import com.kuroshiro.pdf.enums.DataType;public class PdfTableCell {private DataType type;private Image image;private String info;private Float fontSize = 16.0F;private CellAlign horizontalAlign = CellAlign.CENTER;private CellAlign verticalAlign = CellAlign.MIDDLE;private int colspan = 1;private boolean haveBorder = true;public PdfTableCell(String info) {this.type = DataType.TEXT;this.info = info;}public PdfTableCell(String info,Float fontSize) {this.type = DataType.TEXT;;this.info = info;this.fontSize = fontSize;}public PdfTableCell(String info,int colspan) {this.type = DataType.TEXT;this.info = info;this.colspan = colspan<1?1:colspan;}public PdfTableCell(String info,int colspan,Float fontSize) {this.type = DataType.TEXT;;this.info = info;this.fontSize = fontSize;this.colspan = colspan<1?1:colspan;}public PdfTableCell(String info,int colspan,boolean haveBorder,Float fontSize, CellAlign horizontalAlign, CellAlign verticalAlign) {this.type = DataType.TEXT;;this.info = info;this.fontSize = fontSize==null?16F:fontSize;this.horizontalAlign = horizontalAlign==null?CellAlign.CENTER:horizontalAlign;this.verticalAlign = verticalAlign==null?CellAlign.MIDDLE:verticalAlign;this.colspan = colspan<1?1:colspan;this.haveBorder = haveBorder;}public PdfTableCell(Image image) {this.type = DataType.IMAGE;this.image = image;}public PdfTableCell(Image image,int colspan) {this.type = DataType.IMAGE;this.image = image;this.colspan = colspan<1?1:colspan;}public PdfTableCell(Image image,int colspan,boolean haveBorder) {this.type = DataType.IMAGE;this.image = image;this.colspan = colspan<1?1:colspan;this.haveBorder = haveBorder;}public Float getFontSize() {return fontSize;}public void setFontSize(Float fontSize) {this.fontSize = fontSize;}public DataType getType() {return type;}public void setType(DataType type) {this.type = type;}public Image getImage() {return image;}public void setImage(Image image) {this.image = image;}public String getInfo() {return info;}public void setInfo(String info) {this.info = info;}public CellAlign getHorizontalAlign() {return horizontalAlign;}public void setHorizontalAlign(CellAlign horizontalAlign) {this.horizontalAlign = horizontalAlign;}public CellAlign getVerticalAlign() {return verticalAlign;}public void setVerticalAlign(CellAlign verticalAlign) {this.verticalAlign = verticalAlign;}public int getColspan() {return colspan;}public void setColspan(int colspan) {this.colspan = colspan;}public boolean isHaveBorder() {return haveBorder;}public void setHaveBorder(boolean haveBorder) {this.haveBorder = haveBorder;}
}
五、工具类
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import com.kuroshiro.pdf.enums.DataType;
import com.kuroshiro.pdf.enums.TextAttr;
import com.kuroshiro.pdf.exception.PdfException;
import com.kuroshiro.pdf.model.*;
import com.kuroshiro.pdf.model.PdfTemplate;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import javax.imageio.stream.MemoryCacheImageOutputStream;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;/*** pdf 生成工具*/
public class PDFUtils {private static Charset charset;public PDFUtils() {}/*** 计算某个数据在某个位置范围内显示的位置信息** 一个位置需要显示多个数据时计算每个数据的位置** @param positionx 位置范围的 x 坐标* @param positiony 位置范围的 y 坐标* @param index 需要计算的数据下标* @param width 每个数据占用的宽度* @param height 每个数据占用的高度* @param lineCount 该位置一行能够显示的数据个数* @return*/public static Position calcPosition(BigDecimal positionx, BigDecimal positiony, int index, BigDecimal width, BigDecimal height, int lineCount) {int j = 0;if (index != 0 && index % lineCount == 0) {++j;}Position postionresult = new Position();int px = index % lineCount;postionresult.setPositionX(positionx.add((new BigDecimal(px)).multiply(width)));postionresult.setPositionY(positiony.add((new BigDecimal(j)).multiply(height)));return postionresult;}/*** 根据pdf模版创建pdf* @param pdfTemplate* @return* @throws PdfException*/public static byte[] createPdfByTemplate(PdfTemplate pdfTemplate) throws PdfException {ByteArrayOutputStream os = new ByteArrayOutputStream();byte[] res;try {BaseFont simsun_font = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);PdfReader reader = new PdfReader(pdfTemplate.getTemplate());PdfStamper stamper = new PdfStamper(reader, os);AcroFields form = stamper.getAcroFields();if(pdfTemplate.getValues() != null && !pdfTemplate.getValues().isEmpty()){for(String valueKey:pdfTemplate.getValues().keySet()){int type = form.getFieldType(valueKey);/*** FIELD_TYPE_NONE 0 无效字段或字段不存在* FIELD_TYPE_PUSHBUTTON 1 按钮(PushButton)* FIELD_TYPE_CHECKBOX 2 复选框(Checkbox)* FIELD_TYPE_RADIOBUTTON 3 单选按钮(RadioButton)* FIELD_TYPE_TEXT 4 文本框(Text Field)* FIELD_TYPE_LIST 5 下拉列表(List Field)* FIELD_TYPE_COMBO 6 组合框(Combo Box)* FIELD_TYPE_SIGNATURE 7 数字签名(Signature Field)*/if (type != AcroFields.FIELD_TYPE_NONE) {PdfData pdfData = pdfTemplate.getValues().get(valueKey);if(DataType.IMAGE.equals(pdfData.getType())){int pageNo = form.getFieldPositions(valueKey).get(0).page;Rectangle signRect = form.getFieldPositions(valueKey).get(0).position;float x = signRect.getLeft();float y = signRect.getBottom();//读取图片Image image = pdfData.getImage();//获取图片页面PdfContentByte under = stamper.getOverContent(pageNo);//图片大小自适应image.scaleToFit(signRect.getWidth(), signRect.getHeight());//添加图片image.setAbsolutePosition(x, y);under.addImage(image);continue;}switch (type) {case AcroFields.FIELD_TYPE_CHECKBOX:/*** 设置字段属性只读* inst[] 当表单字段由多个控件(如跨页的单选框)组成时,指定操作哪个实例。* 常见用法:* null:操作所有实例。* new int[]{0}:操作第一个实例(索引从 0 开始)。*/form.setFieldProperty(valueKey, "setfflags", PdfFormField.FF_READ_ONLY, null);form.setField(valueKey, pdfData.getValue().toString());break;case AcroFields.FIELD_TYPE_TEXT:form.setFieldProperty(valueKey, "textfont", simsun_font, null);if (pdfData.getTextStyles() != null && !pdfData.getTextStyles().isEmpty()) {for(TextAttr attrKey : pdfData.getTextStyles().keySet()) {/*** 设置字段属性。有效的属性名称是:* textfont - 设置文本字体。该条目的值是一个BaseFont。* textcolor - 设置文本颜色。该条目的值是一个BaseColor。* textsize - 设置文本大小。该表项的值为Float类型。* bgcolor - 设置背景颜色。该条目的值是一个BaseColor。如果为null则删除背景。* bordercolor - 设置边框颜色。该条目的值是一个BaseColor。如果为null则删除边框。*/form.setFieldProperty(valueKey, attrKey.name(), pdfData.getTextStyles().get(attrKey), null);}}form.setField(valueKey, pdfData.getValue().toString());break;case AcroFields.FIELD_TYPE_SIGNATURE:AcroFields.Item item = form.getFieldItem(valueKey);// 获取该字段的第一个控件(PdfDictionary),表单字段可能有多个控件(如多页表单)PdfDictionary widget = item.getWidget(0);// 提取控件的坐标范围(PdfArray),格式为 [左下角X, 左下角Y, 右上角X, 右上角Y]PdfArray array = widget.getAsArray(PdfName.RECT);Image image = Image.getInstance(Base64.getDecoder().decode(pdfData.getValue()));// 获取字段所在页面的 “最上层画布”(PdfContentByte),用于覆盖内容(不会破坏原有表单字段)PdfContentByte under = stamper.getOverContent(item.getPage(0));image.setAbsolutePosition((float)(new BigDecimal(array.getAsNumber(0).toString())).intValue(), (float)(new BigDecimal(array.getAsNumber(1).toString())).intValue());under.addImage(image);}}}}if (pdfTemplate.getPositions() != null && !pdfTemplate.getPositions().isEmpty()) {for(String key : pdfTemplate.getPositions().keySet()) {if(form.getFieldType(key) != AcroFields.FIELD_TYPE_NONE){AcroFields.Item item = form.getFieldItem(key);PdfDictionary widget = item.getWidget(0);PdfArray array = widget.getAsArray(PdfName.RECT);(pdfTemplate.getPositions().get(key)).setPage(new BigDecimal(item.getPage(0)));(pdfTemplate.getPositions().get(key)).setPositionX(new BigDecimal(array.getAsNumber(0).toString()));(pdfTemplate.getPositions().get(key)).setPositionY(new BigDecimal(array.getAsNumber(1).toString()));}}}stamper.setFormFlattening(true);stamper.close();res = os.toByteArray();} catch (Exception e) {throw new PdfException("根据pdf模板生成pdf异常", e);} finally {if (os != null) {try {os.close();} catch (IOException e) {e.printStackTrace();}}}return res;}/*** 根据pdf模版创建pdf* @param pdfTemplate* @return* @throws PdfException*/public static void createPdfByTemplate(PdfTemplate pdfTemplate, OutputStream out) throws PdfException {Document doc = new Document();try {PdfReader reader = new PdfReader(createPdfByTemplate(pdfTemplate));PdfCopy copy = new PdfCopy(doc, out);doc.open();int page = reader.getNumberOfPages();for(int j = 1; j <= page; ++j) {doc.newPage();PdfImportedPage copypage = copy.getImportedPage(reader, j);copy.addPage(copypage);}doc.close();} catch (DocumentException e) {throw new PdfException("根据pdf模板生成pdf异常",e);} catch (IOException e) {throw new PdfException("根据pdf模板生成pdf异常",e);}finally {if (doc != null) {try {doc.close();}catch (Exception e){e.printStackTrace();}}}}/*** 根据模版批量生成 pdf 到一个文件中* @param pdfTemplates 每个 pdf 相关的配置* @return 文件字节数组* @throws PdfException*/public static byte[] createPdfByTemplates(List<PdfTemplate> pdfTemplates) throws PdfException{ByteArrayOutputStream os = new ByteArrayOutputStream();try {List<PdfReader> list = new ArrayList<>();for (PdfTemplate pdfTemplate:pdfTemplates) {list.add(new PdfReader(createPdfByTemplate(pdfTemplate)));}// 将ByteArray字节数组中的流输出到out中(即输出到浏览器)Document doc = new Document();PdfCopy copy = new PdfCopy(doc, os);doc.open();for (PdfReader reader:list) {int page = reader.getNumberOfPages();for(int j = 1; j <= page; ++j) {doc.newPage();PdfImportedPage copypage = copy.getImportedPage(reader, j);copy.addPage(copypage);}}doc.close();return os.toByteArray();}catch (Exception e){throw new PdfException("根据pdf模板生成pdf异常",e);}finally {if (os != null) {try {os.flush();os.close();}catch (Exception e){e.printStackTrace();}}}}/*** 根据模版批量生成 pdf 到一个文件中* @param pdfTemplates 每个 pdf 相关的配置* @param out 文件输出位置*/public static void createPdfByTemplates(List<PdfTemplate> pdfTemplates,OutputStream out){try {List<PdfReader> list = new ArrayList<>();for (PdfTemplate pdfTemplate:pdfTemplates) {list.add(new PdfReader(createPdfByTemplate(pdfTemplate)));}// 将ByteArray字节数组中的流输出到out中(即输出到浏览器)Document doc = new Document();PdfCopy copy = new PdfCopy(doc, out);doc.open();for (PdfReader reader:list) {int page = reader.getNumberOfPages();for(int j = 1; j <= page; ++j) {doc.newPage();PdfImportedPage copypage = copy.getImportedPage(reader, j);copy.addPage(copypage);}}doc.close();}catch (Exception e){e.printStackTrace();}finally {try {if (out != null) {out.flush();out.close();}}catch (Exception e){e.printStackTrace();}}}/*** 创建pdf* @param pdf* @param target* @throws PdfException*/public static void createSimpleTablePDF(PdfTable pdf, OutputStream target) throws PdfException {try {Document document = new Document(PageSize.A4, 50.0F, 50.0F, 50.0F, 50.0F);PdfWriter writer = PdfWriter.getInstance(document, target);document.open();BaseFont simsun_font = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);Font titleFont = new Font(simsun_font, pdf.getFontSize());PdfPTable table = new PdfPTable(pdf.getColumns());if(pdf.getColumnWidths() != null){table.setWidths(pdf.getColumnWidths());}table.setWidthPercentage(100.0F);String title = pdf.getTitle();PdfPCell titlecell = new PdfPCell();titlecell.setColspan(pdf.getColumns());titlecell.setFixedHeight(50);if(!pdf.isHaveBorder()){titlecell.setBorder(0);}// titlecell.setBorderWidth(2.0F);// 水平居中titlecell.setHorizontalAlignment(Element.ALIGN_CENTER);// 垂直居中titlecell.setVerticalAlignment(Element.ALIGN_MIDDLE);titlecell.setPhrase(new Paragraph(title, titleFont));table.addCell(titlecell);for(int i = 0; pdf.getCells() != null && i < pdf.getCells().size(); ++i) {PdfTableCell pdfTableCell = pdf.getCells().get(i);PdfPCell cell = new PdfPCell();if(!pdfTableCell.isHaveBorder()){cell.setBorder(0);}cell.setColspan(pdfTableCell.getColspan());// cell.setBorderWidthTop(i == 0 ? 0.0F : 1.0F);// cell.setBorderWidthBottom(i == pdf.getCells().size() - 1 ? 2.0F : 1.0F);// cell.setBorderWidthLeft(2.0F);// cell.setBorderWidthRight(2.0F);if (pdfTableCell.getType().equals(DataType.IMAGE)) {cell.addElement((pdf.getCells().get(i)).getImage());} else if (pdfTableCell.getType().equals(DataType.TEXT)) {cell.setHorizontalAlignment(pdfTableCell.getHorizontalAlign().getAlign());cell.setVerticalAlignment(pdfTableCell.getVerticalAlign().getAlign());cell.setPhrase(new Paragraph(pdfTableCell.getInfo(), new Font(simsun_font,pdfTableCell.getFontSize())));}table.addCell(cell);}document.add(table);document.close();writer.close();} catch (Exception e) {throw new PdfException("pdf创建失败", e);}}/*** pdf合成* @param pdfs* @param target* @throws PdfException*/public static void mergePdf(List<? extends InputStream> pdfs, OutputStream target) throws PdfException {try {Document targetdocument = new Document();PdfCopy copy = new PdfCopy(targetdocument, target);targetdocument.open();for(int i = 0; i < pdfs.size(); ++i) {PdfReader reader = new PdfReader(pdfs.get(i));int page = reader.getNumberOfPages();for(int j = 1; j <= page; ++j) {targetdocument.newPage();PdfImportedPage copypage = copy.getImportedPage(reader, j);copy.addPage(copypage);}}targetdocument.close();} catch (Exception e) {throw new PdfException("pdf合成异常", e);}}/*** pdf 转图片* @param pdf* @return* @throws PdfException*/public static List<ByteArrayOutputStream> pdfImage(InputStream pdf) throws PdfException {PDDocument document = null;List<ByteArrayOutputStream> res;try {document = PDDocument.load(pdf);// PDFont font = PDType0Font.load(document, PDFUtils.class.getResourceAsStream("/static/fonts/STSong-Light.ttf"), true);PDFRenderer renderer = new PDFRenderer(document);List<ByteArrayOutputStream> oses = new ArrayList();for(int i = 0; i < document.getNumberOfPages(); ++i) {// PDPage page = document.getPage(i);// PDResources resources = page.getResources();// String name = resources.add(font).getName();// page.setResources(resources);BufferedImage image = renderer.renderImageWithDPI(i, 120.0F, ImageType.RGB);ByteArrayOutputStream bos = new ByteArrayOutputStream();ImageOutputStream ios = new MemoryCacheImageOutputStream(bos);ImageWriter jpg_writer = ImageIO.getImageWritersByFormatName("jpg").next();ImageWriteParam jpg_write_param = jpg_writer.getDefaultWriteParam();jpg_write_param.setCompressionMode(2);jpg_write_param.setCompressionQuality(0.7F);jpg_writer.setOutput(ios);IIOImage output_image = new IIOImage(image, null, null);jpg_writer.write(null, output_image, jpg_write_param);jpg_writer.dispose();bos.flush();oses.add(bos);ios.close();}res = oses;} catch (Exception e) {throw new PdfException("pdf转换异常", e);} finally {if (document != null) {try {document.close();} catch (IOException e) {e.printStackTrace();}}}return res;}public static void setCharset(Charset charset) {PDFUtils.charset = charset;}static {charset = StandardCharsets.UTF_8;}
}
六、测试
public class PdfTest {public static void main(String[] args) throws Exception {pdfTemplate();pdfTable();}public static void pdfTemplate() throws Exception {List<PdfTemplate> list = new ArrayList<>();for (int i = 0; i < 3; i++) {PdfTemplate pdfTemplate = new PdfTemplate("测试","/pdfs/xxk.pdf");pdfTemplate.addValue("cyjgmc",new PdfData("从业机构"+i)).addValue("jgmc",new PdfData("从业机构1111"+i)).addValue("name",new PdfData("张三"+i)).addValue("xxklx",(new PdfData("经纪人")).addTextStyle(TextAttr.TEXTCOLOR, BaseColor.RED)).addValue("xxkh",new PdfData("18313226955")).addValue("xxkyxq",new PdfData("2026-12-18 止+i")).addValue("zjz",new PdfData(Image.getInstance("E:\\zjz.jpg"))).addValue("xxkyxq",new PdfData("2026-12-18 止+i"));String content = "http://sys.yn-yf.cn/fdcjj/wx/ryxx/12345";ByteArrayOutputStream outStream = new ByteArrayOutputStream();Resource resource = new cn.hutool.core.io.resource.ClassPathResource("/static/img/15620371964200.png");QRCodeUtil.encode(content,resource.getUrl().getPath(),outStream,true);pdfTemplate.addValue("qrcode", new PdfData(Image.getInstance(outStream.toByteArray())));list.add(pdfTemplate);}PDFUtils.createPdfByTemplates(list,new FileOutputStream("E:\\xxk1.pdf"));}public static void pdfTable() throws Exception {PdfTable pdfTable = new PdfTable("员工信息表",4);pdfTable.setColumnWidths(new float[]{1.0f,2.0f,1.0f,2.0f});// 添加文本单元格pdfTable.addCell(new PdfTableCell( "姓名")).addCell(new PdfTableCell( "测试测试2222")).addCell(new PdfTableCell( "电话")).addCell(new PdfTableCell( "15912153741")).addCell(new PdfTableCell( "地址")).addCell(new PdfTableCell( "15912153741",3)).addCell(new PdfTableCell(Image.getInstance("E:\\zjz.jpg"),3)).addCell(new PdfTableCell( "")).addCell(new PdfTableCell("郑重申明:谨此保证,本表所填报内容及所附证明材料真实、完整",4,false,11.0F, CellAlign.RIGHT,CellAlign.MIDDLE));// 生成 PDF 到文件try (OutputStream os = new FileOutputStream("E:\\xxk2.pdf")) {PDFUtils.createSimpleTablePDF(pdfTable, os);}}
}
结果