基于微信公眾號開發(fā)網(wǎng)站關(guān)鍵詞優(yōu)化建議
目錄
環(huán)境配置
快速使用
代碼實現(xiàn)
添加圖片
封裝
項目需求:獲取列表數(shù)據(jù)之后直接將數(shù)據(jù)生成一個pdf。因此需要使用到?itext?對pdf進行直接操作。
環(huán)境配置
需要為pdf添加文字域,因此需要安裝Adobe Acrobat
準備一個空的PDF文件,如果有現(xiàn)成的模板更好
依賴配置,我們使用itext的7版本
<dependency><groupId>com.itextpdf</groupId><artifactId>itext7-core</artifactId><version>7.2.3</version><type>pom</type></dependency>
快速使用
使用Adobe Acrobat Pro DC打開空PDF,使用 文字域 工具為PDF添加文字域,要注意為每個文字域命名。
如果你有現(xiàn)成的模板PDF,直接使用識別域可以識別空白區(qū)域然后自動生成文字域,但是一般都不太準確
如果你的單個數(shù)據(jù)很多的話,可以在屬性中設(shè)置多行?
設(shè)置完文字域之后記得保存。
代碼實現(xiàn)
@SpringBootTest
class StickerApplicationTests {private static final String TEMP_PATH = "C:\\Users\\An1ong\\Desktop\\Stickers.pdf";//生成PDF的位置private static final String DEST_PATH = "C:\\Users\\An1ong\\Desktop\\StickersOut.pdf";//本地上字體的路徑private static final String FONT_PATH = "";@Autowiredprivate StickerService stickerService;@Testvoid contextLoads() throws IOException {//創(chuàng)建一個新的PDF文件,并寫入數(shù)據(jù)PdfReader reader = new PdfReader(TEMP_PATH);// 創(chuàng)建一個 PdfWriter 對象以寫入新的PDFPdfWriter writer = new PdfWriter(DEST_PATH);// 創(chuàng)建一個 PdfDocument 對象PdfDocument pdfDoc = new PdfDocument(reader, writer);// 獲取 PDF 表單PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, false);//獲得數(shù)據(jù),準備填充List<Sticker> stickerList = stickerService.list(10);//文本填充for(int i = 0; i < stickerList.size();i++){Sticker sticker = stickerList.get(i);// 生成自定義序號,格式為 "001"、"002"、"003"String customId = String.format("%03d", i + 1);String idFieldName = "id" + (i + 1);String nameFieldName = "name" + (i + 1);PdfFormField idField = form.getField(idFieldName);if (idField != null) {idField.setValue(customId);}PdfFormField nameField = form.getField(nameFieldName);if (nameField != null) {nameField.setValue(sticker.getStickerName());}}//消除掉表單域form.flattenFields();//關(guān)閉流pdfDoc.close();}
}
行數(shù)也不算少,但里面的邏輯其實很簡單。這是一個Springboot的單元測試,我調(diào)用service中的方法獲取了一個裝著對象的列表。
用PdfReader讀取你要套寫的模板,用PdfWriter將數(shù)據(jù)寫入模板。創(chuàng)建出一個PdfDocument對象并將這兩個參數(shù)傳入就可以開始對PDF操作了。
注意,這個過程不會直接在原PDF上操作,而是生成一個新的PDF進行操作,程序結(jié)束后原PDF模版還是空白的。
?PdfAcroFrom獲取PDF表單,然后PdfFormField獲取其中的文字域,最后使用for循環(huán)動態(tài)的將數(shù)據(jù)套打在模板上就完成了。
最終會生成一個新的文件
最終效果:
之所以要在最后調(diào)用form.flattenFields消除掉表單域是因為如果不消除表單域的話就會變成這樣。
更新......
添加圖片
現(xiàn)在又有新的需求,除了自定義序號和文本之外,還要每個的后面添加圖片。
添加文本域
代碼實現(xiàn)
PdfFormField imgField = form.getField(imgFieldName);if (imgField != null){List<PdfWidgetAnnotation> widgets = imgField.getWidgets();PdfWidgetAnnotation widget = widgets.get(0);float x1 = widget.getRectangle().getAsNumber(0).floatValue();float y1 = widget.getRectangle().getAsNumber(1).floatValue();float x2 = widget.getRectangle().getAsNumber(2).floatValue();float y2 = widget.getRectangle().getAsNumber(3).floatValue();float fieldWidth = x2 - x1;float fieldHeight = y2 - y1;Image image = img.scaleToFit(fieldWidth,fieldHeight);image.setFixedPosition(x1,y1);Document document = new Document(pdfDoc);document.add(image);}
由于文本域是放置文本的,不能直接放置一個圖片上去。所以我們實現(xiàn)的思路是,在放置圖片的位置一個文本域,然后根據(jù)文本域的坐標將圖片移過去,這就是這段代碼的思路。
可以得到文本域左下角坐標和右上角坐標 ,通過簡單的數(shù)學(xué)計算得到這塊矩形的長和寬,然后使用scaleToFit就可以讓圖片的長和寬與文字域矩形的長寬一樣了。
封裝
我們可以把這個在單元測試中的程序封裝成工具類重復(fù)使用
package com.wal.sticker.util;import com.itextpdf.forms.PdfAcroForm;
import com.itextpdf.forms.fields.PdfFormField;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.annot.PdfWidgetAnnotation;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Image;
import com.wal.sticker.pojo.Sticker;import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;public class PdfPrintUtil {// private static final String TEMP_PATH = "C:\\Users\\An1ong\\Desktop\\Stickers.pdf";
//
// private static final String DEST_PATH = "C:\\Users\\An1ong\\Desktop\\StickersOut.pdf";public static void printPDF(String DEST_PATH,List<Sticker> stickerList) throws IOException, URISyntaxException {String TEMP_PATH = getResourcePath("templates/background.pdf");String IMG_PATH = getResourcePath("static/img/buttonImg.png");//創(chuàng)建一個新的PDF文件,并寫入數(shù)據(jù)PdfReader reader = new PdfReader(TEMP_PATH);// 創(chuàng)建一個 PdfWriter 對象以寫入新的PDFPdfWriter writer = new PdfWriter(DEST_PATH);// 創(chuàng)建一個 PdfDocument 對象PdfDocument pdfDoc = new PdfDocument(reader, writer);// 獲取 PDF 表單PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, false);// 加載圖片Image img = new Image(ImageDataFactory.create(IMG_PATH));//文本和圖片填充for(int i = 0; i < stickerList.size();i++){Sticker sticker = stickerList.get(i);// 生成自定義序號,格式為 "001"、"002"、"003"String customId = String.format("%03d", i + 1);String idFieldName = "id" + (i + 1);String nameFieldName = "text" + (i + 1);String imgFieldName = "img" + (i + 1);PdfFormField idField = form.getField(idFieldName);if (idField != null) {idField.setValue(customId);}PdfFormField nameField = form.getField(nameFieldName);if (nameField != null) {nameField.setValue(sticker.getStickerName());}// 添加圖像PdfFormField imgField = form.getField(imgFieldName);if (imgField != null){List<PdfWidgetAnnotation> widgets = imgField.getWidgets();PdfWidgetAnnotation widget = widgets.get(0);float x1 = widget.getRectangle().getAsNumber(0).floatValue();float y1 = widget.getRectangle().getAsNumber(1).floatValue();float x2 = widget.getRectangle().getAsNumber(2).floatValue();float y2 = widget.getRectangle().getAsNumber(3).floatValue();float fieldWidth = x2 - x1;float fieldHeight = y2 - y1;Image image = img.scaleToFit(fieldWidth,fieldHeight);
//
// float scaledWidth = image.getImageScaledWidth();
// float scaledHeight = image.getImageScaledHeight();
//
// float centerX = x1 + (fieldWidth / 2) - (scaledWidth / 2);
// float centerY = x2 + (fieldHeight / 2) - (scaledHeight / 2);image.setFixedPosition(x1,y1);Document document = new Document(pdfDoc);document.add(image);}}//消除掉表單域
// form.flattenFields();//關(guān)閉流pdfDoc.close();}private static String getResourcePath(String fileName) throws URISyntaxException {ClassLoader classLoader = PdfPrintUtil.class.getClassLoader();Path path = Paths.get(classLoader.getResource(fileName).toURI());return path.toString();}}