1. 程式人生 > 其它 >通過pdf模板,填充內容,生成pdf檔案---JAVA

通過pdf模板,填充內容,生成pdf檔案---JAVA

1 概述

  我們通常會遇到需要生成某些固定格式,但是內容不同的檔案,那麼我們就可以使用⽤Adobe Acrobat DC來建立pdf模組,然後通過程式碼對模板進行填充,生成pdf檔案

 

2 建立一個pdf模板檔案

2.1 先建立一個word建立我們想要的表單

2.2 把word轉換成pdf,如下圖,建立了這麼一個表單,轉成了pdf

 

 

 

 

3 使⽤Adobe Acrobat DC開啟PDF⽂件,來建立模板

3.1使用Adobe Acrobat DC開啟檔案

3.2 點選右邊的功能準備表單

 

 

3.3 點選上面按鈕-新增文字域

 

3.4 把文字域放到我們要填充的地方

 

 

 3.5 填寫域名稱(後面編碼就是根據域名稱來填入內容的)

 

 

 

 還可以雙擊這個框框開啟設定,設定其他屬性

 

 

3.6 完成所有的文字域

  

 

 

3.7 檔案-另存為-儲存檔案(這個檔案就是我們的模板檔案了)

 

4 編碼

4.1 pdf-圖片工具類

package com.ruoyi.weixin.user.MyTest.Itext;

import net.coobird.thumbnailator.Thumbnails;
import net.coobird.thumbnailator.geometry.Positions;

import javax.imageio.ImageIO;
import java.io.
*; /** * @Classname ImageThumbUtil * @Description TODO * @Date 2022/5/6 0006 下午 4:34 * @Created by jcc */ public class ImageThumbUtils { /** * 縮圖⽚,圖⽚質量為源圖的80% * * @param originalImgPath 源圖⽚儲存路徑 * @param w 圖⽚壓縮後的寬度 * @param h 圖⽚壓縮後的⾼度 * @param targetImgPath 縮圖的存放路徑
*/ public static void thumbImage(String originalImgPath, int w, int h, String targetImgPath) throws Exception { thumbImage(new FileInputStream(originalImgPath), w, h, targetImgPath, 0.8); } /** * 縮圖⽚,圖⽚質量為源圖的80% * * @param originalImgData 源圖⽚位元組數 * @param w 圖⽚壓縮後的寬度 * @param h 圖⽚壓縮後的⾼度 * @param targetImgPath 縮圖的存放路徑 */ public static void thumbImage(byte[] originalImgData, int w, int h, String targetImgPath) throws Exception { thumbImage(new ByteArrayInputStream(originalImgData), w, h, targetImgPath, 0.8); } /** * 按⽐例壓縮⽂件 * * @param originalImgData 源⽂件 * @param compressQalitiy 壓縮⽐例 * @param targetImgPath ⽬標路徑 */ public static void thumbImage(byte[] originalImgData, double compressQalitiy, String targetImgPath) throws Exception { Thumbnails.of(new ByteArrayInputStream(originalImgData)).scale(1f).outputQuality(compressQalitiy).toFile(targetImgPath); } /** * 按⽐例壓縮⽂件 * * @param originalImgData 源⽂件 * @param compressQalitiy 壓縮⽐例 */ public static OutputStream thumbImage(byte[] originalImgData, double compressQalitiy) throws Exception { OutputStream os = new ByteArrayOutputStream(); Thumbnails.of(new ByteArrayInputStream(originalImgData)).scale(1f).outputQuality(compressQalitiy).toOutputStream(os); return os; } /** * 按尺⼨⽐例縮略 * * @param originalInputSteam 源圖輸⼊流 * @param w 縮略寬 * @param h 縮略⾼ * @param targetImgPath 縮圖儲存路徑 * @param compressQalitiy 縮略質量⽐例,0~1之間的數 */ public static void thumbImage(InputStream originalInputSteam, int w, int h, String targetImgPath, double compressQalitiy) throws Exception { thumbImage(originalInputSteam, w, h, targetImgPath, compressQalitiy, true); } /** * @param originalImgInputSteam 源圖⽚輸⼊流 * @param w 圖⽚壓縮後的寬度 * @param h 圖⽚壓縮後的⾼度 * @param targetImgPath 縮圖的存放路徑 * @param compressQalitiy 壓縮⽐例,0~1之間的double數字 * @param keepAspectRatio 是否保持等⽐例壓縮,是true,不是false */ public static void thumbImage(InputStream originalImgInputSteam, int w, int h, String targetImgPath, double compressQalitiy, boolean keepAspectRatio) throws Exception { Thumbnails.of(originalImgInputSteam).size(w, h).outputQuality(Double.valueOf(compressQalitiy)).keepAspectRatio(true).toFile(targetImgPath); } /** * 圖⽚裁剪 * * @param originalImgPath 源圖⽚路徑 * @param targetImgPath 新圖⽚路徑 * @param position 位置 0正中間,1中間左邊,2中間右邊,3底部中間,4底部左邊,5底部右邊,6頂部中間,7頂部左邊,8頂部右邊, * 其他為預設正中間 * @param w 裁剪寬度 * @param h 裁剪⾼度 * @throws Exception */ public static void crop(String originalImgPath, int position, int w, int h, String targetImgPath) throws Exception { Thumbnails.of(originalImgPath).sourceRegion(getPositions(position), w, h).size(w, h).outputQuality(1).toFile(targetImgPath); } /** * 給圖⽚新增⽔印 * * @param originalImgPath 將被新增⽔印圖⽚ 路徑 * @param targetImgPath 含有⽔印的新圖⽚路徑 * @param watermarkImgPath ⽔印圖⽚ * @param position 位置 0正中間,1中間左邊,2中間右邊,3底部中間,4底部左邊,5底部右邊,6頂部中間,7頂部左邊,8頂部右邊, * 其他為預設正中間 * @param opacity 不透明度,取0~1之間的float數字,0完全透明,1完全不透明 * @throws Exception */ public static void watermark(String originalImgPath, String watermarkImgPath, int position, float opacity, String targetImgPath) throws Exception { Thumbnails.of(originalImgPath).watermark(getPositions(position), ImageIO.read(new File(watermarkImgPath)), opacity).scale(1.0) .outputQuality(1).toFile(targetImgPath); } private static Positions getPositions(int position) { Positions p = Positions.CENTER; switch (position) { case 0: { p = Positions.CENTER; break; } case 1: { p = Positions.CENTER_LEFT; break; } case 2: { p = Positions.CENTER_RIGHT; break; } case 3: { p = Positions.BOTTOM_CENTER; break; } case 4: { p = Positions.BOTTOM_LEFT; break; } case 5: { p = Positions.BOTTOM_RIGHT; break; } case 6: { p = Positions.TOP_CENTER; break; } case 7: { p = Positions.TOP_LEFT; break; } case 8: { p = Positions.TOP_RIGHT; break; } default: { p = Positions.CENTER; break; } } return p; } public static void main(String[] args) throws Exception { thumbImage("d:/pdf/1.jpg", 600, 600, "d:/pdf/2.jpg"); crop("d:/pdf/1.jpg", 7, 200, 300, "d:/pdf/2.jpg"); watermark("d:/pdf/1.jpg", "d:/pdf/2.jpg", 7, 1, "d:/pdf/3.jpg"); } }

 

4.2 根據模板,填充內容,生成pdf檔案工具類

 

/**
 * @Classname PdfUtils
 * @Description TODO
 * @Date 2022/5/6 0006 下午 4:40
 * @Created by jcc
 */
import com.itextpdf.text.Document;
import com.itextpdf.text.pdf.*;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.*;
import java.util.List;
/**
 * Description: PdfUtils <br>
 * 依賴的包:itextpdf itext-asian
 * commons-io,commons-codec
 * @author mk
 * @Date 2018-11-2 14:32 <br>
 * @Param
 * @return
 */
public class PdfUtils {

    public static void main(String[] args) throws IOException {
      //注意,這裡構建map,key和value都要是String HashMap map
= new HashMap<String, String>();
     //姓名 map.put(
"customerAsex", "陳曉"); // 年齡 map.put("customerAage", "13"); // String path = PdfUtils.class.getResource("/template").getPath(); // System.out.println("path:"+path); // String sourceFile = path + File.separator + "test.pdf"; //模板檔案 String sourceFile = "C:\\Users\\Administrator\\Desktop\\muban.pdf"; //生成的pdf檔案(自己隨便定義) String targetFile = "C:\\Users\\Administrator\\Desktop\\test_fill.pdf"; genPdf(map,sourceFile,targetFile); // System.out.println("獲取pdf表單中的fieldNames:"+getTemplateFileFieldNames(sourceFile)); // System.out.println("讀取⽂件陣列:"+fileBuff(sourceFile)); // System.out.println("pdf轉圖⽚:"+pdf2Img(new File(targetFile),imageFilePath)); } /* * * @Description TOOD * @param map 我們要填充的內容,key是pdf模板文字域的名稱,value是要填充內容 * @param sourceFile 模板檔案路徑 * @param targetFile 生成的pdf檔案路徑 * @return void * @date 2022/5/6 0006 下午 5:39 * @author jcc */ private static void genPdf(HashMap map, String sourceFile, String targetFile) throws IOException { File templateFile = new File(sourceFile); fillParam(map, FileUtils.readFileToByteArray(templateFile), targetFile); } /** * Description: 使⽤map中的引數填充pdf,map中的key和pdf表單中的field對應 <br> * @author mk * @Date 2018-11-2 15:21 <br> * @Param * @return */ public static void fillParam(Map<String, String> fieldValueMap, byte[] file, String contractFileName) { FileOutputStream fos = null; try { fos = new FileOutputStream(contractFileName); PdfReader reader = null; PdfStamper stamper = null; BaseFont base = null; try { reader = new PdfReader(file); stamper = new PdfStamper(reader, fos); stamper.setFormFlattening(true); base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); AcroFields acroFields = stamper.getAcroFields(); for (String key : acroFields.getFields().keySet()) { acroFields.setFieldProperty(key, "textfont", base, null); acroFields.setFieldProperty(key, "textsize", new Float(9), null); } if (fieldValueMap != null) { for (String fieldName : fieldValueMap.keySet()) { acroFields.setField(fieldName, fieldValueMap.get(fieldName)); } } } catch (Exception e) { e.printStackTrace(); } finally { if (stamper != null) { try { stamper.close(); } catch (Exception e) { e.printStackTrace(); } } if (reader != null) { reader.close(); } } } catch (Exception e) { System.out.println("填充引數異常"); e.printStackTrace(); } finally { IOUtils.closeQuietly(fos); } } /** * Description: 獲取pdf表單中的fieldNames<br> * @author mk * @Date 2018-11-2 15:21 <br> * @Param * @return */ public static Set<String> getTemplateFileFieldNames(String pdfFileName) { Set<String> fieldNames = new TreeSet<String>(); PdfReader reader = null; try { reader = new PdfReader(pdfFileName); Set<String> keys = reader.getAcroFields().getFields().keySet(); for (String key : keys) { int lastIndexOf = key.lastIndexOf("."); int lastIndexOf2 = key.lastIndexOf("["); fieldNames.add(key.substring(lastIndexOf != -1 ? lastIndexOf + 1 : 0, lastIndexOf2 != -1 ? lastIndexOf2 : key.length())); } } catch (IOException e) { e.printStackTrace(); } finally { if (reader != null) { reader.close(); } } return fieldNames; } /** * Description: 讀取⽂件陣列<br> * @author mk * @Date 2018-11-2 15:21 <br> * @Param * @return */ public static byte[] fileBuff(String filePath) throws IOException { File file = new File(filePath); long fileSize = file.length(); if (fileSize > Integer.MAX_VALUE) { //System.out.println("file too big..."); return null; } FileInputStream fi = new FileInputStream(file); byte[] file_buff = new byte[(int) fileSize]; int offset = 0; int numRead = 0; while (offset < file_buff.length && (numRead = fi.read(file_buff, offset, file_buff.length - offset)) >= 0) { offset += numRead; } // 確保所有資料均被讀取 if (offset != file_buff.length) { throw new IOException("Could not completely read file " + file.getName()); } fi.close(); return file_buff; } /** * Description: 合併pdf <br> * @author mk * @Date 2018-11-2 15:21 <br> * @Param * @return */ public static void mergePdfFiles(String[] files, String savepath) { Document document = null; try { document = new Document(); //預設A4⼤⼩ PdfCopy copy = new PdfCopy(document, new FileOutputStream(savepath)); document.open(); for (int i = 0; i < files.length; i++) { PdfReader reader = null; try { reader = new PdfReader(files[i]); int n = reader.getNumberOfPages(); for (int j = 1; j <= n; j++) { document.newPage(); PdfImportedPage page = copy.getImportedPage(reader, j); copy.addPage(page); } } finally { if (reader != null) { reader.close(); } } } } catch (Exception e) { e.printStackTrace(); } finally { //關閉PDF⽂檔流,OutputStream⽂件輸出流也將在PDF⽂檔流關閉⽅法內部關閉 if (document != null) { document.close(); } } } /** * pdf轉圖⽚ * @param file pdf * @return */ public static boolean pdf2Img(File file,String imageFilePath) { try { //⽣成圖⽚儲存 byte[] data = pdfToPic(PDDocument.load(file)); File imageFile = new File(imageFilePath); ImageThumbUtils.thumbImage(data, 1, imageFilePath); //按⽐例壓縮圖⽚ System.out.println("pdf轉圖⽚⽂件地址:" + imageFilePath); return true; } catch (Exception e) { System.out.println("pdf轉圖⽚異常:"); e.printStackTrace(); } return false; } /** * pdf轉圖⽚ * pdf轉圖⽚ */ private static byte[] pdfToPic(PDDocument pdDocument) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); List<BufferedImage> piclist = new ArrayList<BufferedImage>(); try { PDFRenderer renderer = new PDFRenderer(pdDocument); for (int i = 0; i < pdDocument.getNumberOfPages(); i++) {// // 0 表⽰第⼀頁,300 表⽰轉換 dpi,越⼤轉換後越清晰,相對轉換速度越慢 BufferedImage image = renderer.renderImageWithDPI(i, 108); piclist.add(image); } // 總⾼度 總寬度 臨時的⾼度 , 或儲存偏移⾼度 臨時的⾼度,主要儲存每個⾼度 int height = 0, width = 0, _height = 0, __height = 0, // 圖⽚的數量 picNum = piclist.size(); // 儲存每個⽂件的⾼度 int[] heightArray = new int[picNum]; // 儲存圖⽚流 BufferedImage buffer = null; // 儲存所有的圖⽚的RGB List<int[]> imgRGB = new ArrayList<int[]>(); // 儲存⼀張圖⽚中的RGB資料 int[] _imgRGB; for (int i = 0; i < picNum; i++) { buffer = piclist.get(i); heightArray[i] = _height = buffer.getHeight();// 圖⽚⾼度 if (i == 0) { // 圖⽚寬度 width = buffer.getWidth(); } // 獲取總⾼度 height += _height; // 從圖⽚中讀取RGB _imgRGB = new int[width * _height]; _imgRGB = buffer.getRGB(0, 0, width, _height, _imgRGB, 0, width); imgRGB.add(_imgRGB); } // 設定偏移⾼度為0 _height = 0; // ⽣成新圖⽚ BufferedImage imageResult = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); int[] lineRGB = new int[8 * width]; int c = new Color(128, 128, 128).getRGB(); for (int i = 0; i < lineRGB.length; i++) { lineRGB[i] = c; } for (int i = 0; i < picNum; i++) { __height = heightArray[i]; // 計算偏移⾼度 if (i != 0) _height += __height; imageResult.setRGB(0, _height, width, __height, imgRGB.get(i), 0, width); // 寫⼊流中 // 模擬頁分隔 if (i > 0) { imageResult.setRGB(0, _height + 2, width, 8, lineRGB, 0, width); } } // 寫流 ImageIO.write(imageResult, "jpg", baos); } catch (Exception e) { System.out.println("pdf轉圖⽚異常:"); e.printStackTrace(); } finally { IOUtils.closeQuietly(baos); try { pdDocument.close(); } catch (Exception ignore) { } } return baos.toByteArray(); } }

 

 

4.3 測試結果

   測試程式碼中,只填了customerAname和customerAage到map中,所以這裡只填入了左邊的某些和年齡