java之数据填充PDF模板
声明:由于业务场景需要,所以根据一个网友的完成的。
1、既然要使用PDF模板填充,那么就需要制作PDF模板,可以使用Adobe Acrobat DC,下载地址:https://carrot.ctfile.com/dir/11269771-27158812-194d66/29433907/ (使用特别破解版),安装步骤就省略了。
2、开始制作模板
a)使用wps制作一个表格,并转为PDF文件保存
b)使用Adobe Acrobat DC打开保存的PDF文件,然后搜索 "准备表单" ,点击 ”准备表单“,然后出来表单域
3、程序部分
a)依赖
<dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.10</version> </dependency> <!-- itextpdf 依赖包start --> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.5.10</version> </dependency> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itext-asian</artifactId> <version>5.2.0</version> </dependency> <!-- itextpdf 依赖包end --> <!--pdf 转图片 start --> <dependency> <groupId>org.apache.pdfbox</groupId> <artifactId>pdfbox</artifactId> <version>2.0.11</version> </dependency> <dependency> <groupId>net.coobird</groupId> <artifactId>thumbnailator</artifactId> <version>0.4.2</version> </dependency> <!--pdf 转图片 end -->
b)工具类 ImageThumbUtils,该类主要是用于将pdf转为图片,如果不需要可以不添加
package com.yangwj.demo.controller; import net.coobird.thumbnailator.Thumbnails; import net.coobird.thumbnailator.geometry.Positions; import javax.imageio.ImageIO; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; /** * 图片缩略、裁剪、添加水印。 */ 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 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"); } }
c)实现数据填充PDF模板
package com.yangwj.demo.controller; 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 { HashMap map = new HashMap<String, String>(); map.put("name","杨杰"); map.put("sex","男"); map.put("age","27"); map.put("phone","15521331"); map.put("email","812406fdf@qq.com"); map.put("idCard","4305223243434332"); map.put("hobby","跑步"); map.put("time","2019年5月22日"); // String path = PdfUtils.class.getResource("/template").getPath(); // System.out.println("path:"+path); // String sourceFile = path + File.separator + "test.pdf"; String sourceFile = "C:\\Users\\yangwj\\Desktop\\test.pdf"; String targetFile = "C:\\Users\\yangwj\\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)); } 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转图片 */ 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、针对复选框的填充
只需要在相应的字段(现金付费)设置值为"On"。
5、针对属性值太长,可以对填充框进行换行
本文来自博客园,作者:小白啊小白,Fighting,转载请注明原文链接:https://www.cnblogs.com/ywjfx/p/10908316.html