(1) Requirement description
Build PDF template and realize dynamic insertion of some data. It is mainly divided into three components: ordinary text, check box, QR code and dynamic insertion of pictures
(2) Make template
Because the commonly used software of pdf doesn't support editing, we first use WPS to edit in the form of Word to make the same style as the customer's needs, and then save it directly as The form of pdf is shown in the figure below:
After building the PDF, we need to use Adobe Acrobat DC software to edit the text field. The software download is not repeated
Open the test PDF with Adobe Acrobat DC, click the preparation form, and the following describes the basic use of the software. The value field at No. 1 is the built value field, which can be customized, dragged and modified. Some customized components can be added to No. 2, such as text, radio box, button, etc. No. 3 shows the domain object of the current PDF
Configure the data source domain name, which is the property of dynamic insertion value matching later. The text component can be directly used for image insertion, as long as the domain name matches
The check box is explained separately. During the development, I found that there are many statements On the network. In fact, the selection of the check box is not clear. Specifically, it is OK to set On, Yes, Yes or other, and the default value of PDF is also different. This needs to be specially edited by Adobe Acrobat DC, and the style can be set in the option, The exported value is the On you selected in the code later. When you set On to the corresponding field value, it means to confirm the selection. This needs special attention, otherwise there is a problem that cannot be selected and no solution can be found
(3) Code development
Import dependency, itextpdf is the main editing dependency, and iText Asian is the dependency of Asian fonts
<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>
PDF operation code
public static byte[] createSimplePdf(Map<String, Map<String, String>> dataMap, String templatePath) { PdfReader reader; ByteArrayOutputStream bos; PdfStamper stamper; ByteArrayOutputStream out = null; try { //Get file stream reader = new PdfReader(templatePath); bos = new ByteArrayOutputStream(); stamper = new PdfStamper(reader, bos); AcroFields form = stamper.getAcroFields(); //Traversal setting for (Map.Entry<String, Map<String, String>> data : dataMap.entrySet()) { String fieldType = data.getKey(); if ("simple".equals(fieldType)) { for (Map.Entry<String, String> dataValue : data.getValue().entrySet()) { //Support Chinese BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); form.setFieldProperty(data.getKey(), "textfont", bfChinese, null); //saveAppearance needs to be set to true, form.setField(dataValue.getKey(), dataValue.getValue(), true); } } else if ("image".equals(fieldType)) { //Processing picture type fields for (Map.Entry<String, String> dataValue : data.getValue().entrySet()) { int pageNo = form.getFieldPositions(dataValue.getKey()).get(0).page; Rectangle signRect = form.getFieldPositions(dataValue.getKey()).get(0).position; float x = signRect.getLeft(); float y = signRect.getBottom(); // Read pictures Image image = PngImage.getImage(dataValue.getValue()); // Get the page of the operation PdfContentByte under = stamper.getOverContent(pageNo); // Scale the picture according to the size of the field image.scaleToFit(signRect.getWidth(), signRect.getHeight()); // Add picture image.setAbsolutePosition(x, y); under.addImage(image); stamper.setFormFlattening(true); } } } //Non editable stamper.setFormFlattening(true); out = new ByteArrayOutputStream(); Document doc = new Document(); PdfCopy copy = new PdfCopy(doc, out); stamper.close(); doc.open(); PdfImportedPage importPage = copy.getImportedPage(new PdfReader(bos.toByteArray()), 1); copy.addPage(importPage); doc.close(); out.close(); } catch (IOException | DocumentException e) { e.printStackTrace(); } assert out != null; return out.toByteArray(); }
Test code
public static void main(String[] args) throws IOException { Map<String, Map<String, String>> dataSet = new HashMap<>(3); String imgPath = "D:\\img.png"; Map<String, String> map1 = new HashMap<>(2); map1.put("name", "Hello World"); map1.put("flag", "On"); Map<String, String> map2 = new HashMap<>(2); map2.put("img", imgPath); dataSet.put("simple", map1); dataSet.put("image", map2); byte[] simplePdf = PdfUtil.createSimplePdf(dataSet, "D:\\test.pdf"); File file = new File("target.pdf"); FileOutputStream fileOutputStream = new FileOutputStream(file); fileOutputStream.write(simplePdf); fileOutputStream.close(); }
Generated PDF results
explain:
1: In order to facilitate the operation of Map directly, it is recommended to replace the actual development with entity class
2: At present, only text, check box and picture types are encountered. The operation of text check box is the same, and the picture is slightly different
3: The saveAppearance must be set to true during check box operation, otherwise it will not take effect