itextpdf generates pdf based on pdf form template filling
Template creation
Example: Create a template using adobe acrobat tools
Take excel to generate a form template as an example
1. Create a form excel
2. Create a new PDF form template
Open the pdf tool: File -> Create -> Create Form
Select the created excel import
Edit imported form
After importing, the left side is the field name, and the right side is the content of the form field, that is, the form placeholder, which can be edited by double-clicking
The name is the key obtained when itext is read
Depend on jar package
<dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.5.13</version> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.3.5</version> </dependency>
Implementation code
Form pdf field configuration information entity class
import com.itextpdf.text.pdf.BaseFont; import com.test.utils.pdf.PdfCreateUtil; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.util.Optional; @Data @ApiModel("Form pdf field configuration information") public class FormPdfFieldConfig {<!-- --> @ApiModelProperty("font size, default 14") private float fontSize = 14f; @ApiModelProperty("font style") private BaseFont baseFont; @ApiModelProperty("Paragraph line spacing in the cell, the default is 1.5 times") private float cellLineLeading = 1.5f; @ApiModelProperty("Image location x-axis coordinates") private float xPos = -1f; @ApiModelProperty("Y-axis coordinates of image position") private float yPos = -1f; @ApiModelProperty("image width") private float width = -1f; @ApiModelProperty("picture height") private float height = -1f; public BaseFont getBaseFont() {<!-- --> baseFont = Optional.ofNullable(baseFont).orElse(PdfCreateUtil.getDefaultBaseFont()); return baseFont; } }
Form pdf parameter information entity class
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.util.Optional; @Data @ApiModel("Form pdf parameter information") public class FormPdfParamInfo {<!-- --> @ApiModelProperty("Field filling type - adaptive text filling") public static final String FIELD_FILL_TYPE_ADAPTIVE = "adaptive"; @ApiModelProperty("Field filling type - QR code filling") public static final String FIELD_FILL_TYPE_QR_IMAGE = "qrImage"; @ApiModelProperty("field key") private String fieldKey; @ApiModelProperty("String field value") private String stringValue; @ApiModelProperty("picture content") private String imageContent; @ApiModelProperty("field filling type") private String fieldFillType = FIELD_FILL_TYPE_ADAPTIVE; @ApiModelProperty("field configuration information") private FormPdfFieldConfig fieldConfig; @ApiModelProperty("The pdf page number where the field is located, starting from 1") private int pageNum = 1; public FormPdfFieldConfig getFieldConfig() {<!-- --> fieldConfig = Optional.ofNullable(fieldConfig).orElse(new FormPdfFieldConfig()); return fieldConfig; } }
Form type pdf field processing tool class
import cn.hutool.extra.qrcode.QrCodeUtil; import com.itextpdf.text.*; import com.itextpdf.text.pdf.AcroFields; import com.itextpdf.text.pdf.PdfContentByte; import com.itextpdf.text.pdf.PdfPCell; import com.itextpdf.text.pdf.PdfPTable; import com.test.constants.NumberConst; import com.test.vo.pdf.FormPdfFieldConfig; import com.test.vo.pdf.FormPdfParamInfo; import java.awt.image.BufferedImage; import java.io.IOException; /** * Form type pdf field processing tool class */ public class PdfFormFieldUtil {<!-- --> /** * Adaptive plug value * @param acroFields * @param paramInfo */ public static void setAdaptiveField(AcroFields acroFields, PdfContentByte pdfContentByte, FormPdfParamInfo paramInfo) {<!-- --> PdfPTable pdfPtable = new PdfPTable(NumberConst.NUM_1); Rectangle rectangle = acroFields.getFieldPositions(paramInfo.getFieldKey()).get(NumberConst.NUM_0).position; float totalWidth = rectangle.getRight() - rectangle.getLeft() - 1; pdfPtable.setTotalWidth(totalWidth); getTable(pdfPtable, rectangle, paramInfo); pdfPtable.writeSelectedRows(0, -1, rectangle.getLeft(), rectangle.getTop(), pdfContentByte); } /** * Add QR code/picture (to be verified and optimized) * @param acroFields * @param pdfContentByte * @param paramInfo * @throws DocumentException * @throws IOException */ public static void setQrImage(AcroFields acroFields, PdfContentByte pdfContentByte, FormPdfParamInfo paramInfo) throws DocumentException, IOException {<!-- --> Rectangle rectangle = acroFields.getFieldPositions(paramInfo.getFieldKey()).get(NumberConst.NUM_0).position; FormPdfFieldConfig fieldConfig = paramInfo.getFieldConfig(); BufferedImage bufImg = QrCodeUtil.generate(paramInfo.getImageContent(), 400, 400); Image image = Image.getInstance(bufImg, null); float x = fieldConfig.getXPos()>0 ? fieldConfig.getXPos() : rectangle.getLeft(); float y = fieldConfig.getYPos()>0 ? fieldConfig.getYPos() : rectangle.getBottom(); image.setAbsolutePosition(x, y); float width = fieldConfig.getWidth()>0 ? fieldConfig.getWidth() : rectangle.getWidth(); float height = fieldConfig.getHeight()>0 ? fieldConfig.getHeight() : rectangle.getHeight(); image.scaleToFit(width, height); pdfContentByte.addImage(image); } /** * About the automatic scaling of PDF cell spacing and font size * 2019-02-13 * @param table * @param rectangle * @param paramInfo * @return */ private static void getTable(PdfPTable table, Rectangle rectangle, FormPdfParamInfo paramInfo) {<!-- --> FormPdfFieldConfig fieldConfig = paramInfo.getFieldConfig(); Font cellTitleFont = new Font(fieldConfig.getBaseFont(), fieldConfig.getFontSize(), Font.NORMAL); Paragraph titleTitle = new Paragraph(paramInfo. getStringValue(), cellTitleFont); PdfPCell cell = new PdfPCell(titleTitle); //Cell setting Border cell.setBorderWidth(0); // cell content top margin distance cell.setPaddingTop(-5f); //Cell content multi-line spacing cell.setLeading(0f, fieldConfig.getCellLineLeading()); table. addCell(cell); float i = 0.5f; float j = 0.1f; if(table.getTotalHeight()>rectangle.getHeight()){<!-- --> table.deleteBodyRows(); fieldConfig.setFontSize(fieldConfig.getFontSize()-i); fieldConfig.setCellLineLeading(fieldConfig.getCellLineLeading()-j); getTable(table, rectangle, paramInfo); } } }
pdf generation tool class
import java.io.ByteArrayOutputStream; import java.util.ArrayList; import java.util.Map; import java.util.Optional; @Slf4j public class PdfCreateUtil {<!-- --> private static BaseFont DEFAULT_BASE_FONT = null; /** * Use form type pdf template fill to generate pdf * @param paramMap * @param fileConfig * @return */ public static byte[] createPdfByFormTemplate(Map<String, FormPdfParamInfo> paramMap, PdfFileConfig fileConfig) {<!-- --> try {<!-- --> String basePath = PdfCreateUtil.class.getClassLoader().getResource("").getFile(); //Get the default font BaseFont baseFont = BaseFont.createFont(basePath + Optional.ofNullable(fileConfig.getFontFilePath()).orElse("fontfiles/song.ttf"), BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); DEFAULT_BASE_FONT = baseFont; ArrayList<BaseFont> fontList = new ArrayList<BaseFont>(); fontList. add(baseFont); // get the template PdfReader pdfReader = new PdfReader(basePath + fileConfig.getPdfTempPath()); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); PdfStamper pdfStamper = new PdfStamper(pdfReader, outputStream); AcroFields acroFields = pdfStamper. getAcroFields(); //Set template font acroFields.setSubstitutionFonts(fontList); Map<String, AcroFields.Item> fieldMap = acroFields.getFields(); for (String fieldKey : fieldMap. keySet()) {<!-- --> FormPdfParamInfo paramInfo = paramMap.get(fieldKey); if (paramInfo != null){<!-- --> switch (paramInfo.getFieldFillType()){<!-- --> case FormPdfParamInfo.FIELD_FILL_TYPE_QR_IMAGE: // Fill in the QR code/picture PdfFormFieldUtil.setQrImage(acroFields, pdfStamper.getOverContent(paramInfo.getPageNum()), paramInfo); break; default: // default adaptive padding text PdfFormFieldUtil.setAdaptiveField(acroFields, pdfStamper.getOverContent(paramInfo.getPageNum()), paramInfo); } } } pdfStamper.setFormFlattening(true); pdfStamper. close(); pdfReader. close(); outputStream. close(); return outputStream.toByteArray(); } catch (Exception e) {<!-- --> log.error("pdf generation exception", e); } return null; } public static BaseFont getDefaultBaseFont() {<!-- --> return DEFAULT_BASE_FONT; } }
Usage example (data assembly)
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.test.constant.BusiConstant; import com.test.constants.NumberConst; import com.test.utils.pdf.PdfCreateUtil; import com.test.vo.pdf.FormPdfParamInfo; import com.test.vo.pdf.PdfFileConfig; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import java.util.HashMap; import java.util.Map; import java.util.Optional; public byte[] createPdfByTemplate(String type, JSONObject paramJson) {<!-- --> Map<String, FormPdfParamInfo> paramMap = new HashMap<>(NumberConst.NUM_4); PdfFileConfig fileConfig = new PdfFileConfig(); if (StringUtils.isBlank(type)){<!-- --> log.error("The type parameter is empty"); return null; } if (OtherbusiConstant.ENTERPRISE_TYPE_ENTERPRISE.equals(type)){<!-- --> // type 1 fileConfig.setPdfTempPath("pdftemplate/template1.pdf"); } else if (OtherbusiConstant.ENTERPRISE_TYPE_INDIVIDUAL.equals(type)){<!-- --> // type 2 fileConfig.setPdfTempPath("pdftemplate/template2.pdf"); } if (paramJson == null || paramJson.isEmpty()){<!-- --> log.error("pdf generated parameter data is empty, type=", type); return null; } paramJson.entrySet().forEach( entry -> {<!-- --> FormPdfParamInfo paramInfo = new FormPdfParamInfo(); paramInfo.setFieldKey(entry.getKey()); paramInfo.setStringValue((String) Optional.ofNullable(entry.getValue()).orElse("")); if (BusiConstant.TYPE_FIRST.equals(type)){<!-- --> if (BusiConstant.TYPE_SECOND.contains(entry.getKey())){<!-- --> paramInfo.setPageNum(NumberConst.NUM_2); } } paramMap.put(entry.getKey(), paramInfo); }); return PdfCreateUtil.createPdfByFormTemplate(paramMap, fileConfig); }