1、Pdf创建修改
公众号有一个用户在线签名生成合同的功能。当时将用户信息自动填充到合同中,以及用户签名填充到合同中,就有用到这些东西,只是那个时候没有进行总结,这次因为之前生成的合同一直都不具备有法律效率,所以要重新进行开发,依赖第三方具有法律认证的公司,并且添加了盖章的功能。
首先之前自己的写法,往pdf模板中填充内容。创建pdf的模板,用软件Acrobat,选择工具----》准备表单------》选择需要生成的pdf然后创建输入框,并且给每个需要填充的输入框起一个名字。注意这里需要指定字体的类型,否则最后生成的pdf字体不一样。模板准备好后,开始进行代码的开发。
依赖包:
<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>
操作代码:
importjava.io.ByteArrayOutputStream; importjava.io.File; importjava.io.FileInputStream; importjava.io.StringReader; importjava.util.ArrayList; importjava.util.HashMap; importjava.util.Map; importorg.apache.commons.codec.binary.Base64; importorg.eclipse.jdt.internal.compiler.batch.Main; importcom.itextpdf.text.Image; importcom.itextpdf.text.Rectangle; importcom.itextpdf.text.log.SysoCounter; importcom.itextpdf.text.pdf.AcroFields; importcom.itextpdf.text.pdf.BaseFont; importcom.itextpdf.text.pdf.PdfContentByte; importcom.itextpdf.text.pdf.PdfReader; importcom.itextpdf.text.pdf.PdfStamper; importcom.tl.weixin.GlobalVar; importepm.core.webservice.sgcscws.CommonDataServiceProxy; /**** 娴嬭瘯 鍏ュ弬map鐢熸垚* @author MJX**/publicclassPdfMakeTest { // 入参传的一个是 key value 形式的 map 填充的文字内容// 另一个传输的是 签字图片转成的 byte数组//生成 base64 pdf 过户 更改publicStringsendpdfGh(Map<String, String>content, byte[] imgb) { StringstrBase64=null; try { StringfieldName="contractQz"; // filePath 是 模板的路径信息 可以注意下面 被转换成了reader 所以不是具体的位置也可以,可以转成其他的方式 存储最后转成 reader的形式就行StringfilePath=this.getClass().getClassLoader().getResource("/").getPath(); //System.out.println(filePath);// String filePath = "D:\\jmgh.pdf";//PdfReader reader = new PdfReader(new FileInputStream(new File(filePath)));filePath=filePath+content.get("pdfVersion"); PdfReaderreader=newPdfReader(filePath); // 输出流 是为了接 转换的pdf 模板ByteArrayOutputStreambos=newByteArrayOutputStream(); PdfStamperpsf=newPdfStamper(reader, bos); PdfContentByteunder=psf.getUnderContent(1); // 创建字体BaseFontbf=BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", false); ArrayListfontList=newArrayList(); fontList.add(bf); AcroFieldsfields=psf.getAcroFields(); // 设置生成时候的字体fields.setSubstitutionFonts(fontList); // 循环 key value 根据key 查找模板中的隐藏域 然后将value填充for (Stringkey : content.keySet()) { Stringvalue= (String) content.get(key); fields.setField(key, value); } // fields.setField("USER_NO", cons_no);// fields.setField("BASE_TYPE4", "false");// fillData(fields, data(cusdeal));// 以下 是改良的 填充 签名 信息// 因为签名是一个 图片 直接填充的时候 会 有位置不对应的问题// 怀疑是 上面的 PdfContentByte under = psf.getUnderContent(1); 参数获取的是1 的问题// 获取表单中的 所有 隐藏域名字AcroFieldsform=psf.getAcroFields(); //获取 关键字在第几页的 页数intpageNo=form.getFieldPositions(fieldName).get(0).page; // 根据 关键字 获取 签名区域 并定位到 位置的 坐标RectanglesignRect= ((AcroFields.FieldPosition) fields.getFieldPositions(fieldName).get(0)).position; floatx=signRect.getLeft(); floaty=signRect.getBottom(); Imageimage=null; // image = Image.getInstance(signature_url + "/" + cons_no + ".png");// 获取 image 的图片对象image=Image.getInstance(imgb); //设置第几页的添加PdfContentByteunder2=psf.getOverContent(pageNo); // 依据 模板中的 长宽 设置 图片的长宽image.scaleToFit(signRect.getWidth(), signRect.getHeight()); // 设置图片的坐标 并且 under2 添加图片image.setAbsolutePosition(x, y); under2.addImage(image); // 完结psf.setFormFlattening(true); psf.close(); // 因为 上面 将pdf写入到了输出流中 相当于一直在操作流// 所以 这里可以直接将流 进行转换 base64 返回 也可以 转成 本地的 图片 直接操作 bos 输出流就可以strBase64=Base64.encodeBase64String(bos.toByteArray()); // System.out.println(strBase64);bos.close(); } catch (Exceptione) { e.printStackTrace(); } finally { } returnstrBase64; //return rtncode + "," + rtnMsg; } }
以上就是依据模板生成的 pdf,并且是base64形式的可进行传输当然,模板传入也可以动态的传入以上代码可以进行提取,动态可变参数全部提出来。
附带一个转换类,将生成好的base64 转换成pdf文档,验证是否正确。
importjava.io.BufferedInputStream; importjava.io.BufferedOutputStream; importjava.io.ByteArrayInputStream; importjava.io.File; importjava.io.FileOutputStream; importsun.misc.BASE64Decoder; publicclassBaseToPdf { /*** Description: 将base64编码内容转换为Pdf* @param base64编码内容,文件的存储路径(含文件名)* @Author MJX* Create Date: 2029年7月30日 */publicstaticvoidbase64StringToPdf(Stringbase64Content,StringfilePath){ BASE64Decoderdecoder=newBASE64Decoder(); BufferedInputStreambis=null; FileOutputStreamfos=null; BufferedOutputStreambos=null; try { byte[] bytes=decoder.decodeBuffer(base64Content);//base64编码内容转换为字节数组ByteArrayInputStreambyteInputStream=newByteArrayInputStream(bytes); bis=newBufferedInputStream(byteInputStream); Filefile=newFile(filePath); Filepath=file.getParentFile(); if(!path.exists()){ path.mkdirs(); } fos=newFileOutputStream(file); bos=newBufferedOutputStream(fos); byte[] buffer=newbyte[1024]; intlength=bis.read(buffer); while(length!=-1){ bos.write(buffer, 0, length); length=bis.read(buffer); } bos.flush(); } catch (Exceptione) { e.printStackTrace(); }finally{ //closeStream(bis, fos, bos); } } publicstaticvoidmain(String[] args) { Stringkk=""; base64StringToPdf(kk,"E:\\cn25.pdf"); } }
2、PDF转图片
pdf的转图片的原因是展示用。直接给用户展示pdf PC端和安卓(安卓有的可以用,有的可以下载)直接用a标签然后跟pdf的路径就可以,但是在IOS上 没有办法。== 坑了因为做的是移动端的还必须各种兼容。前台使用pdfjs进行渲染,发现小的pdf文档还可以接受,但是大一点的就GG 了。渲染的时间太长,好久都加载不出来。而且没有经过填充的快,但是填充过的pdf文档加载很慢。所以想到了 将pdf 转换成图片的方式,前台拿到图片的数组,然后一张一张的展示图片的base64 这样浏览器直接渲染,速度会大幅度的提升。第三方厂家提供了 pdf 转图片的功能,不知道是传输过程的问题,还是厂家转换的问题。速度太慢。自己百度了一套。pdfbox 阿帕奇的工具,依赖windows的字体库,linux需要自己装字体。
依赖:
<!--pdf压缩信息begin--><dependency><groupId>org.apache.pdfbox</groupId><artifactId>fontbox</artifactId><version>2.0.9</version></dependency><!--https://mvnrepository.com/artifact/org.apache.pdfbox/pdfbox --><dependency><groupId>org.apache.pdfbox</groupId><artifactId>pdfbox</artifactId><version>2.0.9</version></dependency><!--https://mvnrepository.com/artifact/commons-logging/commons-logging --><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency><!--pdf压缩信息end-->
importorg.apache.pdfbox.pdmodel.PDDocument; importorg.apache.pdfbox.rendering.PDFRenderer; importjavax.imageio.ImageIO; importjava.awt.image.BufferedImage; importjava.io.ByteArrayOutputStream; importjava.io.IOException; importjava.util.ArrayList; importjava.util.Base64; importjava.util.List; /*** ChangePdfOne** @author MJX* @date 2020/5/6*/publicclassChangePdfOne { /*** 转换全部的pdf* @param type 图片类型pdfStr:pdf的base64type 是图片类型*/publicstaticListpdf2png(StringpdfStr, Stringtype) { // 将pdf装图片 并且自定义图片得格式大小// File file = new File(fileAddress+"\\"+filename+".pdf");byte[] decode=Base64.getDecoder().decode(pdfStr); try { PDDocumentdoc=PDDocument.load(decode); // PDDocument doc = PDDocument.load(file);PDFRendererrenderer=newPDFRenderer(doc); intpageCount=doc.getNumberOfPages(); ArrayList<String>list=newArrayList<>(); for (inti=0; i<pageCount; i++) { // 控制清晰度 后面的100 值越大越清晰 BufferedImageimage=renderer.renderImageWithDPI(i, 100); // Windows native DPI// BufferedImage srcImage = resize(image, 240, 240);//产生缩略图// ImageIO.write(image, type, new File(fileAddress+"\\"+filename+"_"+(i+1)+"."+type));ByteArrayOutputStreambos=newByteArrayOutputStream(); ImageIO.write(image,type,bos); byte[] bytes=bos.toByteArray(); Stringbase=Base64.getEncoder().encodeToString(bytes); list.add(base); // System.out.println("base = " + base);// File file = new File("D:\\testAnySignEncPackage\\"+ i +"."+"jpg");// FileUtils.writeByteArrayToFile(file, bytes); } returnlist; } catch (IOExceptione) { e.printStackTrace(); } returnnull; } publicstaticvoidmain(String[] args) { pdf2png("","jpg"); } }
生成的图片有乱码的情况,百度发现大多说的都是字体不完全,需要安装字体库。找了好久 最终也没有找到 mstmc.ttf的字体在哪里安装==。