Itextpdf + Adobe Acrobat DC填充模板生成pdf快速入门
Itextpdf + Adobe Acrobat DC填充模板生成pdf快速入门
生成pdf有很多种方法,如通过freemarker,或 使用itextpdf。本文将使用itextpdf生成pdf
1.下载Adobe Acrobat DC 并安装
从官网http://get.adobe.com/cn/reader/otherversions/下载
或者下载绿色版本
安装完之后又如下图标:
2.将word文件通过Adobe Acrobat DC生成pdf模板
如需要填充的是姓名和身份信息,如设置属性为realName 和idNo
3.运行结果如下
4.添加依赖
1 <dependency> 2 <groupId>commons-io</groupId> 3 <artifactId>commons-io</artifactId> 4 <version>2.4</version> 5 </dependency> 6 7 <dependency> 8 <groupId>commons-codec</groupId> 9 <artifactId>commons-codec</artifactId> 10 <version>1.10</version> 11 </dependency> 12 13 <!-- <dependency> 14 <groupId>commons-collections</groupId> 15 <artifactId>commons-collections</artifactId> 16 <version>3.2.1</version> 17 </dependency>--> 18 19 <!-- itextpdf 依赖包start --> 20 <dependency> 21 <groupId>com.itextpdf</groupId> 22 <artifactId>itextpdf</artifactId> 23 <version>5.5.10</version> 24 </dependency> 25 26 <dependency> 27 <groupId>com.itextpdf</groupId> 28 <artifactId>itext-asian</artifactId> 29 <version>5.2.0</version> 30 </dependency> 31 <!-- itextpdf 依赖包end --> 32 33 <!--pdf 转图片 start --> 34 <dependency> 35 <groupId>org.apache.pdfbox</groupId> 36 <artifactId>pdfbox</artifactId> 37 <version>2.0.11</version> 38 </dependency> 39 40 <dependency> 41 <groupId>net.coobird</groupId> 42 <artifactId>thumbnailator</artifactId> 43 <version>0.4.2</version> 44 </dependency> 45 <!--pdf 转图片 end -->
5.填充代码
PdfUtils 如下:
1 /** 2 * Project Name:mk-project <br> 3 * Package Name:com.suns.pdf <br> 4 * 5 * @author mk <br> 6 * Date:2018-11-2 14:32 <br> 7 */ 8 9 package com.suns.pdf; 10 11 import com.itextpdf.text.Document; 12 import com.itextpdf.text.pdf.*; 13 import org.apache.commons.io.FileUtils; 14 import org.apache.commons.io.IOUtils; 15 import org.apache.pdfbox.pdmodel.PDDocument; 16 import org.apache.pdfbox.rendering.PDFRenderer; 17 18 import javax.imageio.ImageIO; 19 import java.awt.*; 20 import java.awt.image.BufferedImage; 21 import java.io.*; 22 import java.util.*; 23 import java.util.List; 24 25 /** 26 * Description: PdfUtils <br> 27 * 依赖的包:itextpdf itext-asian 28 * commons-io,commons-codec 29 * @author mk 30 * @Date 2018-11-2 14:32 <br> 31 * @Param 32 * @return 33 */ 34 public class PdfUtils { 35 36 37 public static void main(String[] args) throws IOException { 38 HashMap map = new HashMap<String, String>(); 39 map.put("realName","对应pdf中的表单名为realName"); 40 map.put("idNo","对应pdf中的表单名为idNo"); 41 // String path = PdfUtils.class.getResource("/template").getPath(); 42 // System.out.println("path:"+path); 43 // String sourceFile = path + File.separator + "test.pdf"; 44 String sourceFile = "d:/pdf/test.pdf"; 45 String targetFile = "d:/pdf/test_fill.pdf"; 46 String imageFilePath = "d:/pdf/test_fill.jpg"; 47 48 // genPdf(map,sourceFile,targetFile); 49 50 // System.out.println("获取pdf表单中的fieldNames:"+getTemplateFileFieldNames(sourceFile)); 51 // System.out.println("读取文件数组:"+fileBuff(sourceFile)); 52 // System.out.println("pdf转图片:"+pdf2Img(new File(targetFile),imageFilePath)); 53 } 54 55 private static void genPdf(HashMap map, String sourceFile, String targetFile) throws IOException { 56 File templateFile = new File(sourceFile); 57 fillParam(map, FileUtils.readFileToByteArray(templateFile), targetFile); 58 } 59 60 /** 61 * Description: 使用map中的参数填充pdf,map中的key和pdf表单中的field对应 <br> 62 * @author mk 63 * @Date 2018-11-2 15:21 <br> 64 * @Param 65 * @return 66 */ 67 public static void fillParam(Map<String, String> fieldValueMap, byte[] file, String contractFileName) { 68 FileOutputStream fos = null; 69 try { 70 fos = new FileOutputStream(contractFileName); 71 PdfReader reader = null; 72 PdfStamper stamper = null; 73 BaseFont base = null; 74 try { 75 reader = new PdfReader(file); 76 stamper = new PdfStamper(reader, fos); 77 stamper.setFormFlattening(true); 78 base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); 79 AcroFields acroFields = stamper.getAcroFields(); 80 for (String key : acroFields.getFields().keySet()) { 81 acroFields.setFieldProperty(key, "textfont", base, null); 82 acroFields.setFieldProperty(key, "textsize", new Float(9), null); 83 } 84 if (fieldValueMap != null) { 85 for (String fieldName : fieldValueMap.keySet()) { 86 acroFields.setField(fieldName, fieldValueMap.get(fieldName)); 87 } 88 } 89 } catch (Exception e) { 90 e.printStackTrace(); 91 } finally { 92 if (stamper != null) { 93 try { 94 stamper.close(); 95 } catch (Exception e) { 96 e.printStackTrace(); 97 } 98 } 99 if (reader != null) { 100 reader.close(); 101 } 102 } 103 104 } catch (Exception e) { 105 System.out.println("填充参数异常"); 106 e.printStackTrace(); 107 } finally { 108 IOUtils.closeQuietly(fos); 109 } 110 } 111 112 /** 113 * Description: 获取pdf表单中的fieldNames<br> 114 * @author mk 115 * @Date 2018-11-2 15:21 <br> 116 * @Param 117 * @return 118 */ 119 public static Set<String> getTemplateFileFieldNames(String pdfFileName) { 120 Set<String> fieldNames = new TreeSet<String>(); 121 PdfReader reader = null; 122 try { 123 reader = new PdfReader(pdfFileName); 124 Set<String> keys = reader.getAcroFields().getFields().keySet(); 125 for (String key : keys) { 126 int lastIndexOf = key.lastIndexOf("."); 127 int lastIndexOf2 = key.lastIndexOf("["); 128 fieldNames.add(key.substring(lastIndexOf != -1 ? lastIndexOf + 1 : 0, lastIndexOf2 != -1 ? lastIndexOf2 : key.length())); 129 } 130 } catch (IOException e) { 131 e.printStackTrace(); 132 } finally { 133 if (reader != null) { 134 reader.close(); 135 } 136 } 137 138 return fieldNames; 139 } 140 141 142 /** 143 * Description: 读取文件数组<br> 144 * @author mk 145 * @Date 2018-11-2 15:21 <br> 146 * @Param 147 * @return 148 */ 149 public static byte[] fileBuff(String filePath) throws IOException { 150 File file = new File(filePath); 151 long fileSize = file.length(); 152 if (fileSize > Integer.MAX_VALUE) { 153 //System.out.println("file too big..."); 154 return null; 155 } 156 FileInputStream fi = new FileInputStream(file); 157 byte[] file_buff = new byte[(int) fileSize]; 158 int offset = 0; 159 int numRead = 0; 160 while (offset < file_buff.length && (numRead = fi.read(file_buff, offset, file_buff.length - offset)) >= 0) { 161 offset += numRead; 162 } 163 // 确保所有数据均被读取 164 if (offset != file_buff.length) { 165 throw new IOException("Could not completely read file " + file.getName()); 166 } 167 fi.close(); 168 return file_buff; 169 } 170 171 /** 172 * Description: 合并pdf <br> 173 * @author mk 174 * @Date 2018-11-2 15:21 <br> 175 * @Param 176 * @return 177 */ 178 public static void mergePdfFiles(String[] files, String savepath) { 179 Document document = null; 180 try { 181 document = new Document(); //默认A4大小 182 PdfCopy copy = new PdfCopy(document, new FileOutputStream(savepath)); 183 document.open(); 184 for (int i = 0; i < files.length; i++) { 185 PdfReader reader = null; 186 try { 187 reader = new PdfReader(files[i]); 188 int n = reader.getNumberOfPages(); 189 for (int j = 1; j <= n; j++) { 190 document.newPage(); 191 PdfImportedPage page = copy.getImportedPage(reader, j); 192 copy.addPage(page); 193 } 194 } finally { 195 if (reader != null) { 196 reader.close(); 197 } 198 } 199 } 200 } catch (Exception e) { 201 e.printStackTrace(); 202 } finally { 203 //关闭PDF文档流,OutputStream文件输出流也将在PDF文档流关闭方法内部关闭 204 if (document != null) { 205 document.close(); 206 } 207 208 } 209 } 210 211 212 213 /** 214 * pdf转图片 215 * @param file pdf 216 * @return 217 */ 218 public static boolean pdf2Img(File file,String imageFilePath) { 219 try { 220 //生成图片保存 221 byte[] data = pdfToPic(PDDocument.load(file)); 222 File imageFile = new File(imageFilePath); 223 ImageThumbUtils.thumbImage(data, 1, imageFilePath); //按比例压缩图片 224 System.out.println("pdf转图片文件地址:" + imageFilePath); 225 return true; 226 } catch (Exception e) { 227 System.out.println("pdf转图片异常:"); 228 e.printStackTrace(); 229 } 230 231 return false; 232 } 233 234 /** 235 * pdf转图片 236 */ 237 private static byte[] pdfToPic(PDDocument pdDocument) { 238 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 239 List<BufferedImage> piclist = new ArrayList<BufferedImage>(); 240 try { 241 PDFRenderer renderer = new PDFRenderer(pdDocument); 242 for (int i = 0; i < pdDocument.getNumberOfPages(); i++) {// 243 // 0 表示第一页,300 表示转换 dpi,越大转换后越清晰,相对转换速度越慢 244 BufferedImage image = renderer.renderImageWithDPI(i, 108); 245 piclist.add(image); 246 } 247 // 总高度 总宽度 临时的高度 , 或保存偏移高度 临时的高度,主要保存每个高度 248 int height = 0, width = 0, _height = 0, __height = 0, 249 // 图片的数量 250 picNum = piclist.size(); 251 // 保存每个文件的高度 252 int[] heightArray = new int[picNum]; 253 // 保存图片流 254 BufferedImage buffer = null; 255 // 保存所有的图片的RGB 256 List<int[]> imgRGB = new ArrayList<int[]>(); 257 // 保存一张图片中的RGB数据 258 int[] _imgRGB; 259 for (int i = 0; i < picNum; i++) { 260 buffer = piclist.get(i); 261 heightArray[i] = _height = buffer.getHeight();// 图片高度 262 if (i == 0) { 263 // 图片宽度 264 width = buffer.getWidth(); 265 } 266 // 获取总高度 267 height += _height; 268 // 从图片中读取RGB 269 _imgRGB = new int[width * _height]; 270 _imgRGB = buffer.getRGB(0, 0, width, _height, _imgRGB, 0, width); 271 imgRGB.add(_imgRGB); 272 } 273 274 // 设置偏移高度为0 275 _height = 0; 276 // 生成新图片 277 BufferedImage imageResult = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 278 int[] lineRGB = new int[8 * width]; 279 int c = new Color(128, 128, 128).getRGB(); 280 for (int i = 0; i < lineRGB.length; i++) { 281 lineRGB[i] = c; 282 } 283 for (int i = 0; i < picNum; i++) { 284 __height = heightArray[i]; 285 // 计算偏移高度 286 if (i != 0) 287 _height += __height; 288 imageResult.setRGB(0, _height, width, __height, imgRGB.get(i), 0, width); // 写入流中 289 290 // 模拟页分隔 291 if (i > 0) { 292 imageResult.setRGB(0, _height + 2, width, 8, lineRGB, 0, width); 293 } 294 } 295 // 写流 296 ImageIO.write(imageResult, "jpg", baos); 297 } catch (Exception e) { 298 System.out.println("pdf转图片异常:"); 299 e.printStackTrace(); 300 } finally { 301 IOUtils.closeQuietly(baos); 302 try { 303 pdDocument.close(); 304 } catch (Exception ignore) { 305 } 306 } 307 308 return baos.toByteArray(); 309 } 310 }
ImageThumbUtils如下:
1 /** 2 * @Project: hehenian-biz-common 3 * @Package com.hehenian.biz.common.filesaving.utils 4 * @Title: ImageThumbUtils.java 5 * @Description: TODO 6 * @author: zhangyunhua 7 * @date 2015年1月20日 下午3:57:59 8 * @Copyright: HEHENIAN Co.,Ltd. All rights reserved. 9 * @version V1.0 10 */ 11 package com.suns.pdf; 12 13 import net.coobird.thumbnailator.Thumbnails; 14 import net.coobird.thumbnailator.geometry.Positions; 15 16 import javax.imageio.ImageIO; 17 import java.io.ByteArrayInputStream; 18 import java.io.File; 19 import java.io.FileInputStream; 20 import java.io.InputStream; 21 22 /** 23 * 图片缩略、裁剪、添加水印。 24 */ 25 public class ImageThumbUtils { 26 27 /** 28 * 缩略图片,图片质量为源图的80% 29 * 30 * @param originalImgPath 31 * 源图片存储路径 32 * @param w 33 * 图片压缩后的宽度 34 * @param h 35 * 图片压缩后的高度 36 * @param targetImgPath 37 * 缩略图的存放路径 38 */ 39 public static void thumbImage(String originalImgPath, int w, int h, String targetImgPath) throws Exception { 40 thumbImage(new FileInputStream(originalImgPath), w, h, targetImgPath, 0.8); 41 } 42 43 /** 44 * 缩略图片,图片质量为源图的80% 45 * 46 * @param originalImgData 47 * 源图片字节数 48 * @param w 49 * 图片压缩后的宽度 50 * @param h 51 * 图片压缩后的高度 52 * @param targetImgPath 53 * 缩略图的存放路径 54 */ 55 public static void thumbImage(byte[] originalImgData, int w, int h, String targetImgPath) throws Exception { 56 thumbImage(new ByteArrayInputStream(originalImgData), w, h, targetImgPath, 0.8); 57 } 58 59 /** 60 * 按比例压缩文件 61 * @param originalImgData 源文件 62 * @param compressQalitiy 压缩比例 63 * @param targetImgPath 目标路径 64 */ 65 public static void thumbImage(byte[] originalImgData, double compressQalitiy, String targetImgPath) throws Exception { 66 Thumbnails.of(new ByteArrayInputStream(originalImgData)).scale(1f).outputQuality(compressQalitiy).toFile(targetImgPath); 67 } 68 69 /** 70 * 按尺寸比例缩略 71 * 72 * @param originalInputSteam 73 * 源图输入流 74 * @param w 75 * 缩略宽 76 * @param h 77 * 缩略高 78 * @param targetImgPath 79 * 缩略图存储路径 80 * @param compressQalitiy 81 * 缩略质量比例,0~1之间的数 82 */ 83 public static void thumbImage(InputStream originalInputSteam, int w, int h, String targetImgPath, double compressQalitiy) throws Exception { 84 thumbImage(originalInputSteam, w, h, targetImgPath, compressQalitiy, true); 85 } 86 87 /** 88 * 89 * @param originalImgInputSteam 90 * 源图片输入流 91 * @param w 92 * 图片压缩后的宽度 93 * @param h 94 * 图片压缩后的高度 95 * @param targetImgPath 96 * 缩略图的存放路径 97 * @param compressQalitiy 98 * 压缩比例,0~1之间的double数字 99 * @param keepAspectRatio 100 * 是否保持等比例压缩,是true,不是false 101 */ 102 public static void thumbImage(InputStream originalImgInputSteam, int w, int h, String targetImgPath, double compressQalitiy, 103 boolean keepAspectRatio) throws Exception { 104 Thumbnails.of(originalImgInputSteam).size(w, h).outputQuality(Double.valueOf(compressQalitiy)).keepAspectRatio(true).toFile(targetImgPath); 105 } 106 107 /** 108 * 图片裁剪 109 * 110 * @param originalImgPath 111 * 源图片路径 112 * @param targetImgPath 113 * 新图片路径 114 * @param position 115 * 位置 0正中间,1中间左边,2中间右边,3底部中间,4底部左边,5底部右边,6顶部中间,7顶部左边,8顶部右边, 116 * 其他为默认正中间 117 * @param w 118 * 裁剪宽度 119 * @param h 120 * 裁剪高度 121 * @throws Exception 122 */ 123 public static void crop(String originalImgPath, int position, int w, int h, String targetImgPath) throws Exception { 124 Thumbnails.of(originalImgPath).sourceRegion(getPositions(position), w, h).size(w, h).outputQuality(1).toFile(targetImgPath); 125 } 126 127 /** 128 * 给图片添加水印 129 * 130 * @param originalImgPath 131 * 将被添加水印图片 路径 132 * @param targetImgPath 133 * 含有水印的新图片路径 134 * @param watermarkImgPath 135 * 水印图片 136 * @param position 137 * 位置 0正中间,1中间左边,2中间右边,3底部中间,4底部左边,5底部右边,6顶部中间,7顶部左边,8顶部右边, 138 * 其他为默认正中间 139 * @param opacity 140 * 不透明度,取0~1之间的float数字,0完全透明,1完全不透明 141 * @throws Exception 142 */ 143 public static void watermark(String originalImgPath, String watermarkImgPath, int position, float opacity, String targetImgPath) 144 throws Exception { 145 Thumbnails.of(originalImgPath).watermark(getPositions(position), ImageIO.read(new File(watermarkImgPath)), opacity).scale(1.0) 146 .outputQuality(1).toFile(targetImgPath); 147 } 148 149 private static Positions getPositions(int position) { 150 Positions p = Positions.CENTER; 151 switch (position) { 152 case 0: { 153 p = Positions.CENTER; 154 break; 155 } 156 case 1: { 157 p = Positions.CENTER_LEFT; 158 break; 159 } 160 case 2: { 161 p = Positions.CENTER_RIGHT; 162 break; 163 } 164 case 3: { 165 p = Positions.BOTTOM_CENTER; 166 break; 167 } 168 case 4: { 169 p = Positions.BOTTOM_LEFT; 170 break; 171 } 172 case 5: { 173 p = Positions.BOTTOM_RIGHT; 174 break; 175 } 176 case 6: { 177 p = Positions.TOP_CENTER; 178 break; 179 } 180 case 7: { 181 p = Positions.TOP_LEFT; 182 break; 183 } 184 case 8: { 185 p = Positions.TOP_RIGHT; 186 break; 187 } 188 default: { 189 p = Positions.CENTER; 190 break; 191 } 192 } 193 return p; 194 } 195 196 public static void main(String[] args) throws Exception { 197 thumbImage("d:/pdf/1.jpg", 600, 600, "d:/pdf/2.jpg"); 198 crop("d:/pdf/1.jpg", 7, 200, 300, "d:/pdf/2.jpg"); 199 watermark("d:/pdf/1.jpg", "d:/pdf/2.jpg", 7, 1, "d:/pdf/3.jpg"); 200 } 201 }