java 对PDF的操作(生成,转换,转图片,转base64等)

简介: java 对PDF的操作(生成,转换,转图片,转base64等)

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的字体在哪里安装==。


目录
相关文章
|
12天前
|
分布式计算 DataWorks Java
DataWorks操作报错合集之在使用MaxCompute的Java SDK创建函数时,出现找不到文件资源的情况,是BUG吗
DataWorks是阿里云提供的一站式大数据开发与治理平台,支持数据集成、数据开发、数据服务、数据质量管理、数据安全管理等全流程数据处理。在使用DataWorks过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
26 0
|
12天前
|
Java 测试技术 Python
《手把手教你》系列技巧篇(三十六)-java+ selenium自动化测试-单选和多选按钮操作-番外篇(详解教程)
【4月更文挑战第28天】本文简要介绍了自动化测试的实战应用,通过一个在线问卷调查(&lt;https://www.sojump.com/m/2792226.aspx/&gt;)为例,展示了如何遍历并点击问卷中的选项。测试思路包括找到单选和多选按钮的共性以定位元素,然后使用for循环进行点击操作。代码设计方面,提供了Java+Selenium的示例代码,通过WebDriver实现自动答题。运行代码后,可以看到控制台输出和浏览器的相应动作。文章最后做了简单的小结,强调了本次实践是对之前单选多选操作的巩固。
24 0
|
2天前
|
Java API
Java操作elasticsearch
Java操作elasticsearch
7 0
|
2天前
|
NoSQL Java Redis
在Java中操作Redis
在Java中操作Redis
6 0
|
2天前
|
SQL Java 关系型数据库
【JAVA基础篇教学】第十六篇:Java连接和操作MySQL数据库
【JAVA基础篇教学】第十六篇:Java连接和操作MySQL数据库
|
2天前
|
Oracle 关系型数据库 Java
java操作多数据源将oracle数据同步达梦数据库
java操作多数据源将oracle数据同步达梦数据库
|
2天前
|
Java Android开发
java利用xml-rpc协议操作wordpress博客
java利用xml-rpc协议操作wordpress博客
|
3天前
|
SQL Java 数据库连接
Java数据库编程实践:连接与操作数据库
Java数据库编程实践:连接与操作数据库
9 0
|
10天前
|
XML 前端开发 Oracle
16:JSP简介、注释与Scriptlet、Page指令元素、Include操作、内置对象、四种属性-Java Web
16:JSP简介、注释与Scriptlet、Page指令元素、Include操作、内置对象、四种属性-Java Web
13 2
|
12天前
|
存储 NoSQL 安全
java 中通过 Lettuce 来操作 Redis
java 中通过 Lettuce 来操作 Redis
java 中通过 Lettuce 来操作 Redis