开篇语:html
最近工做须要作一个借款合同,公司之前的合同都是经过app端下载,而后经过本地打开pdf文件,而喜欢创新的我,心想着为何不能在线H5预览,正是这个想法,说干就干,实践过程老是艰难的,折腾了3,4天的时间,熬了两个凌晨3,4点,其中的艰辛、以及各中的曲折、压力只有本身能体会,项目上线后内心想着我要写一篇博文,一是总结一下经验,其次就是和你们分享本身这一路走来的的心得体会,欢迎吐槽!,废话很少说,来点干货!java
PDF在线预览实现:jquery
8个实如今线浏览PDF文件的实用插件,笔者选择pdf.js,下面简单介绍8个插件:git
PDFobject能够帮助你在页面直接嵌入pdf文件,有时候有些项目须要动态地嵌入PDF文件。PDFObject为此而设计的,他可以快速和容易的嵌入PDF文件,PDFObject使用JavaScript来产生相同的符合标准的 标记,而后插入 到您的HTML元素的选择。您能够填满整个浏览器窗口,或将PDF格式转换成一个或其余块级元素。github
和 Google Chrome 使用的源自 Foxit 的闭源 PDF 浏览插件不一样,PDF.js 是基于开放的 HTML5 及 JavaScript 技术实现的开源产品。web
pdf.js 是一个主要用于HTML5 平台上在线阅读PDF文档的小插件,基于JavaScript技术编写而成,无需任何本地技术支持。apache
pdf.js是由Mozilla Labs发布的。他们的目标是建立一个通用的,基于标准的网络平台,可以解析和渲染PDF文件,并最终发布一个PDF阅读器扩展,毫无疑问 pdf.js 将被整合入 Gecko 成为 Firefox 的内嵌 PDF 阅读器,可是具体整合时间表还没有肯定浏览器
jsPDF 是一个使用Javascript语言生成PDF的开源库。你能够在Firefox插件,服务端脚本或是浏览器脚本中使用它。客户端Safari 和 iPhone Safari 支持得最好,其次是Opera和Windows下的Firefox 3等。IE暂不支持。。tomcat
jQuery Media Plugin是一款基于jQuery的网页媒体播放器插件,它支持大部分的网络多媒体播放器和多媒体格式,好比:Flash, Windows Media Player, Real Player, Quicktime, MP3,Silverlight, PDF。它根据当前的脚本配置,自动将a标签替换成div,并生成object, embed甚至是iframe代码,至于生成object仍是embed,jQuery Media会根据当前平台自动判别,所以兼容性方面很是出色下面这段代码是jQuery Media生成后的。网络
下图能够导出为PNG或JPG格式的静态图像或嵌入式静态图像,图表或一个彻底互动的功能图
Document Viewer是一个jQuery插件,可让你在网页中直接查看多种文件格式。文档浏览器支持的文件格式:PDF文件,文本文件,代码,图像,音频,视频等。
PDF.js实践篇
第一步 pdf.js源码下载https://github.com/mozilla/pdf.js
源码页有详细编译步奏,最后编译出来,将generic文件copy至tomcat webapps目录下,浏览器输入http://localhost:8080/generic/web/viewer.html,H5预览效果以下,图片压缩了,实际预览效果好不少
(我这里覆盖了webapps\generic\web\compressed.tracemonkey-pldi-09.pdf文件,它自带的是英文文档):
第二步 我集成到项目以插件的形式目录结构以下:
第三步:编写H5文件,这里是将pdf.js viever.html 页面经过Ifram嵌入进来,并经过指定file参数动态传参,实现动态pdf文件预览
loanPdfContract.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"/>
<meta name="apple-mobile-web-app-capable" content="yes"/>
<meta name="apple-mobile-web-app-status-bar-style" content="black"/>
<meta name="format-detection" content="telephone=no,email=no,address=no"/>
<title>借款合同</title>
</head>
<body>
<iframe src="<c:url value="/plugin/pdfjs/generic/web/viewer.html"/>?file=<c:url value="/app/credit/loanApplication/contracts/${fileId}"/>"
width="100%" height="800">
</iframe>
</body>
</html>
第四步:编写Controller方法,
/**
* 16.借款申请[信息确认]《合同及相关协议》-借款合同 H5接口 提供给app端调用
*
* @param userId
* @return
* @since 3.4
*/
@RequestMapping(value ="/app/credit/loanApplication/contracts/loanContract.security")
public Object loanContract(String userId,String borrowCode,String productTypeCode, Model model) {
if (StringUtils.isEmpty(userId) || StringUtils.isEmpty(borrowCode)) {
return "app/credit/canaLoanApplication/404Error";
}
Map<String,String> returnMap = canaApplyLoanService.investmentContractTemplate(userId,borrowCode,productTypeCode);
if( BizCodeType.IS_NO.getCode().equals(returnMap.get("flag"))){
return "app/credit/canaLoanApplication/404Error";
}
model.addAttribute("fileId",returnMap.get("fileId")+".pdf");
return "app/credit/canaLoanApplication/loanPdfContract";
}
第五步:编写Controller方法,注意这个 http head响应头信息设置是HttpStatus.OK,和文件下载HttpStatus.CREATE头信息有差别。
/**
* 查看PDF文件
* @param fileId
* @return
* @throws IOException
*/
@RequestMapping(value = "/app/credit/loanApplication/contracts/{fileId}.pdf", method = RequestMethod.GET)
public ResponseEntity<byte[]> loadContract(@PathVariable String fileId) throws IOException {
byte[] bytes=canaApplyLoanService.downContract(fileId);
final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.valueOf("application/pdf"));
headers.setContentLength(bytes.length);
headers.add(HttpHeaders.ACCEPT_RANGES,"bytes");
return new ResponseEntity<byte[]>(bytes, headers, HttpStatus.OK);
}
结束语 看着这里,PDF文件在线动态预览基本完成,赶快体验吧!
进阶篇:Java实现PDF文件转图片、多个图片合成PDF文件.
前言:
由于笔者这里的PDF文件带有交互式表单域,致使PDF文件没法预览,由于是合同PDF文件,敲章带有签名信息致使PDF预览失败,当时很是迷茫,没有方向,后来和同城金服一架构师朋友聊天中,他给了我提示,“说是签名的问题,须要把PDF转成图片”,对于笔者来讲,有了思路剩下的就是实践的事情。
由于PDF有多页因此会转出多张图片,至于为何要转成图片,仅仅是为了将代签名的交互式表单域给干掉、由于笔者之前作过多张图片合成一张大图,因此当时就想,这个多张图片合成一张PDF文件应该不是问题,对于之前较少玩PDF文件的我来讲,这个想法已经很是大胆了,若是读者的你也对PDF文件了解不深的话,那么本文将很是适合你,带你实战PDF!
我在啰嗦一句,由于这个PDF文件签名致使App端没法查看,由于是第三方合同公司,因此咱们须要他们的签名SDK文件才能预览,
第一篇:带你装B,带你飞!
说了这么多,不来点干货恐怕大家都看不下去了,主流的Pdf与图片互转
1.PDFRenderer: 确实效率最高,可是缺乏字体支持对大多数中文pdf处理不了,这个笔者最开始使用了一下,可是报错后来放弃了。
2.jpedal:这个是商业版本的,它官网的jar下载较慢,最开始原本打算用,好不容易csdn down下一个jar包,一运行提示jar包过时了。
3.pdfbox:笔者最终采用pdfbox,效果还不错。以前网上说它对中文支持很差,可是笔者在pdfbox_2.0.2.jar使用过程当中都没碰见乱码.
第二篇:pdfbox使用
maven配置:
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.2</version>
</dependency>
java代码:
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.image.JPEGFactory;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.rendering.PDFRenderer;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.WritableRaster;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class PdfBoxUtil {
public static void main(String[] args) {
//pdfToImg("D:\\test\\22222.pdf","D:\\test\\22222.PNG");
pdfToImgToPdf("D:\\test\\22222.pdf","D:\\test\\3333.pdf");
}
/**
* pdf转图片
* @param pdfPath
* @param pngPath
*/
public static void pdfToImg(String pdfPath,String pngPath){
//将pdf装图片 而且自定义图片得格式大小
File file = new File(pdfPath);
try {
PDDocument doc = PDDocument.load(file);
PDFRenderer renderer = new PDFRenderer(doc);
int pageCount = doc.getNumberOfPages();
for (int i = 0; i < pageCount; i++) {
BufferedImage image = renderer.renderImageWithDPI(i, 240);
BufferedImage srcImage = resize(image, image.getWidth(), image.getHeight());
ImageIO.write(srcImage, "PNG", new File(pngPath.replace(".",i+".")));
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* pdf转图片而后合成pdf
* @param pdfPath
* @param pdfOutPath
*/
public static void pdfToImgToPdf(String pdfPath,String pdfOutPath){
//将pdf装图片 而且自定义图片得格式大小
File file = new File(pdfPath);
try {
PDDocument doc = PDDocument.load(file);
PDFRenderer renderer = new PDFRenderer(doc);
int pageCount = doc.getNumberOfPages();
List<BufferedImage> images=new ArrayList<BufferedImage>();
for (int i = 0; i < pageCount; i++) {
BufferedImage image = renderer.renderImageWithDPI(i, 240);
BufferedImage srcImage = resize(image, image.getWidth(), image.getHeight());
images.add(srcImage);
}
//合成图片转pdf
createPDFFromImage(pdfOutPath,images);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* pdf转图片而后合成pdf
* @param input
*/
public static byte[] pdfToImgToPdf(byte[] input){
//将pdf装图片 而且自定义图片得格式大小
byte[] bytes=null;
PDDocument doc=null;
try {
doc = PDDocument.load(input);
List<BufferedImage> images=new ArrayList<BufferedImage>();
PDFRenderer renderer = new PDFRenderer(doc);
int pageCount = doc.getNumberOfPages();
for (int i = 0; i < pageCount; i++) {
BufferedImage image = renderer.renderImageWithDPI(i, 240);
BufferedImage srcImage = resize(image, image.getWidth(), image.getHeight());
images.add(srcImage);
}
bytes=createPDFFromImage(images);
} catch (IOException e) {
e.printStackTrace();
}
if(doc!=null){
try {
doc.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return bytes;
}
/**
*图片合成pdf
* @param images
* @throws Exception
*/
public static void createPDFFromImage(String pdfOutPath,List<BufferedImage> images){
PDDocument doc = new PDDocument();
try {
PDPageContentStream contentStream;
PDPage page;
for (BufferedImage image : images) {
page = new PDPage(new PDRectangle(image.getWidth(),image.getHeight()));
doc.addPage(page);
contentStream = new PDPageContentStream(doc,page,PDPageContentStream.AppendMode.APPEND, true);
PDImageXObject pdImageXObject = JPEGFactory.createFromImage(doc,image);
contentStream.drawXObject(pdImageXObject, 0, 0, image.getWidth(),image.getHeight());
contentStream.close();
}
doc.save(pdfOutPath);
}catch (Exception ex){
ex.printStackTrace();
}finally {
if (doc != null) {
try {
doc.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
*图片合成pdf
* @param images
* @throws Exception
*/
public static byte[] createPDFFromImage(List<BufferedImage> images){
byte[] bytes=null;
ByteArrayOutputStream baos=null;
PDDocument doc = new PDDocument();
try {
PDPageContentStream contentStream;
PDPage page;
for (BufferedImage image : images) {
page = new PDPage(new PDRectangle(image.getWidth(),image.getHeight()));
doc.addPage(page);
contentStream = new PDPageContentStream(doc,page,PDPageContentStream.AppendMode.APPEND, true);
PDImageXObject pdImageXObject = JPEGFactory.createFromImage(doc,image);
contentStream.drawXObject(pdImageXObject, 0, 0, image.getWidth(),image.getHeight());
contentStream.close();
}
baos = new ByteArrayOutputStream();
doc.save(baos);
bytes=baos.toByteArray();
}catch (Exception ex){
ex.printStackTrace();
}finally {
if (baos != null) {
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (doc != null) {
try {
doc.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return bytes;
}
/**
* 生成图片
* @param source
* @param targetW
* @param targetH
* @return
*/
private static BufferedImage resize(BufferedImage source, int targetW, int targetH) {
int type = source.getType();
BufferedImage target = null;
double sx = (double) targetW / source.getWidth();
double sy = (double) targetH / source.getHeight();
if (sx > sy) {
sx = sy;
targetW = (int) (sx * source.getWidth());
} else {
sy = sx;
targetH = (int) (sy * source.getHeight());
}
if (type == BufferedImage.TYPE_CUSTOM) {
ColorModel cm = source.getColorModel();
WritableRaster raster = cm.createCompatibleWritableRaster(targetW, targetH);
boolean alphaPremultiplied = cm.isAlphaPremultiplied();
target = new BufferedImage(cm, raster, alphaPremultiplied, null);
} else {
target = new BufferedImage(targetW, targetH, type);
}
Graphics2D g = target.createGraphics();
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g.drawRenderedImage(source, AffineTransform.getScaleInstance(sx, sy));
g.dispose();
return target;
}
}
总结语:
到这里笔者得和你说拜拜了,基本上将我三天研究的所有成果贡献,其中一路艰辛,扛过多少坑,你未必知道,我只能告诉你,大多时候我心里是奔溃的!
备注 pdf.js 我项目中的插件源码可至我百度云提取 连接: http://pan.baidu.com/s/1c2JVe1M 密码: k9sc
要是你在使用过程当中遇到问题,能够给我邮件,515173248@qq.com