使用html2canvas实现网页截图并嵌入到PDF

以前我们只能通过截图工具进行截取图像。这使得在业务生产中,变得越来越不方便。目前的浏览器功能越来越强大,H5也逐渐普及,浏览器也可以实现截图了。这里来聊下之前在工作中用到的html2canvas。这里要感谢写出html2canvas库的小伙伴!

canvans的原理是将dom节点在Canvas里画出来,虽然特殊方便,但是仍有一些限制。如:

  • 不支持iframe
  • 不支持跨域图片
  • 部分浏览器上不支持SVG图片
  • 不支持Flash
  • 不支持古代浏览器和IE9以下

    function canvasImg(divName,formName,actionType){

    html2canvas(divName, {

    onrendered : function(canvas) {

    var myImage = canvas.toDataURL(“image/jpeg”);

    //动态生成input框

    var input1 = document.createElement(‘input’);

    input1.setAttribute(‘type’, ‘hidden’);

    input1.setAttribute(‘name’, ‘canvasImg’);

    input1.setAttribute(‘value’,myImage);

    formName.appendChild(input1);

    formName.actionType.value=actionType;

    formName.submit();

    }

    });

    }

在这里我抽取成了公共JS,divName是$(‘#id’)取需要截图的DOM对象,function(canvas)渲染完成后回调的canvas对象formName是form表单的名字,actionType是action方法名。 我这里是将得到的截图,进行Base64编码,再通过post请求,在后台获取。

public static String getImgPath(String data){
//图片输出路径
String imgFilePath = null;
try {
Base64 base64 = new Base64();
//base64编码解码
byte[] k = base64.decode(data.substring("data:image/jpeg;base64,"
.length()));
InputStream is = new ByteArrayInputStream(k);
String fileName = UUID.randomUUID().toString();
String pdfFilePath = ShopApplicationResource.shopResource
.getString("pdftempfiles.file.root");
imgFilePath = pdfFilePath + fileName + ".jpg";
double ratio = 1.0;
BufferedImage image = ImageIO.read(is);
//设置图片是否缩放
int newWidth = (int) (image.getWidth() * ratio);
int newHeight = (int) (image.getHeight() * ratio);
Image newimage = image.getScaledInstance(newWidth, newHeight,
Image.SCALE_SMOOTH);
BufferedImage tag = new BufferedImage(newWidth, newHeight,
BufferedImage.TYPE_INT_RGB);
Graphics g = tag.getGraphics();
g.drawImage(newimage, 0, 0, null);
g.dispose();
//使用io将图片写入文件中
ImageIO.write(tag, "jpg", new File(imgFilePath));
} catch (IOException e) {
e.printStackTrace();
}
return imgFilePath;
}

data是经过base64编码的图片数据,将图片通过写入文件流中。

public static void covertImgToPdf(String imgPath,HttpServletResponse response,HttpServletRequest request,String pdfFileName){

Document doc = new Document(PageSize.A4,10,10,10,10);
FileOutputStream os = null;
String pdfFilePath = ShopApplicationResource.shopResource
.getString("pdftempfiles.file.root");
String pafFile = pdfFilePath + "tempPdf.pdf";
FileInputStream fis = null;
ServletOutputStream out = null;
try {
os=new FileOutputStream(pafFile);
PdfWriter pw= PdfWriter.getInstance(doc, os);
pw.setStrictImageSequence(true); doc.open();
//设置logo
//String logofile = request.getSession().getServletContext().getRealPath("/bg/images/ht_logo.png");
//com.itextpdf.text.Image logoImg = com.itextpdf.text.Image.getInstance(logofile);
//doc.add(logoImg);
//logoImg.setAlignment(com.itextpdf.text.Image.UNDERLYING);
//logoImg.setAlignment(com.itextpdf.text.Image.LEFT);
//logoImg.scaleToFit(10f,100f); com.itextpdf.text.Image img = com.itextpdf.text.Image.getInstance(imgPath);
//居中
img.setAlignment(com.itextpdf.text.Image.MIDDLE);
//自动缩放width*height
img.scaleToFit(PageSize.A4.getWidth(), PageSize.A4.getHeight());
doc.add(img); doc.close();
os.flush();
os.close(); //经pdf文件写入输出流,文件在客户端进行下载
response.setContentType("application/pdf");
String fileName = new String(("pdf"+pdfFileName+".pdf").getBytes("utf-8"), "iso-8859-1");
if (request.getHeader("User-Agent").indexOf("MSIE 5.5") != -1) {
/** MS IE5.5 */
response.setHeader("Content-disposition", "filename=\"" + fileName + "\"");
} else { /** 非MS IE5.5 */
response.setHeader("Content-disposition", "attachment;filename=\"" + fileName + "\"");
}
File pafFileTemp = new File(pafFile);
fis = new FileInputStream(pafFileTemp);
out = response.getOutputStream();
byte buffer[] = new byte[1024];
int bytestemp;
while((bytestemp=fis.read(buffer)) != -1){
out.write(buffer, 0, bytestemp);
}
out.close(); //删除图片
File imgfile = new File(imgPath);
if(imgfile.exists()){
imgfile.delete();
} //删除临时PDF
if(pafFileTemp.exists()){
pafFileTemp.delete();
} } catch (Exception e) {
e.printStackTrace();
response.setStatus(HttpServletResponse.SC_OK);
}finally{
if(fis!=null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

这里的PDF使用是IText生成。

如果图片过大,则必须进行分页。但是生成的是一张大图,Itext无法进行自动分页。这里分页有两种思想。一是使用虚拟打印机,将图片分页,再进行导出。二就是将大图切成小图,这种方式依赖于图片切分的大小比列。这里我只实现了第二种方式,所以只对第二种做一些讲解。

    BufferedImage bi = ImageIO.read(new File(imgPath));
int destWidth = (int) PageSize.A4.getWidth(); // 切片宽度
int destHeigth = (int) PageSize.A4.getHeight(); // 切片高度
int srcWidth = bi.getWidth();
int srcHeigth = bi.getHeight();
Image image = bi.getScaledInstance(srcWidth, srcHeigth, Image.SCALE_DEFAULT);
int cols = 0;//切片横向向数量
if (srcHeigth % destHeigth == 0) {
cols = (int) (srcHeigth / destHeigth);
} else {
cols = (int) Math.floor(srcHeigth / destHeigth) + 1;
}
//横向循环切图片
for (int i = 0; i < cols ; i++) {
ImageFilter cropFilter;
Image ig;
cropFilter = new CropImageFilter(0, i * destHeigth,srcWidth, destHeigth);
ig = Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(image.getSource(),cropFilter));
BufferedImage tag = new BufferedImage(srcWidth,destHeigth, BufferedImage.TYPE_INT_RGB);
Graphics g = tag.getGraphics();
g.drawImage(ig, 0, 0, null); // 绘制缩小后的图
g.dispose(); String pdfFilePath = ShopApplicationResource.shopResource.getString("pdftempfiles.file.root");
// 输出为文件
String imgFilePath = pdfFilePath+"temp"+i+".jpg";
ImageIO.write(tag, "JPEG", new File(imgFilePath));
com.itextpdf.text.Image img1 = com.itextpdf.text.Image.getInstance(imgFilePath);
// int percent1 = getPercent2(img1.getHeight(), PageSize.A4.getWidth());
//img1.scalePercent(percent1);
//设置图片宽高
img1.scaleAbsolute(PageSize.A4.getWidth(), img1.getHeight());
//居中
img1.setAlignment(com.itextpdf.text.Image.MIDDLE);
//另起一页
doc.newPage();
doc.add(img1);
File file = new File(imgFilePath);
if(file.exists()){
file.delete();
}
}

这里的思路是:我这里只是将图片适应A4纸,所以只进行横向切片,每次按比例切出一张图片,就放入一张PDF页中,直到切完所有。这种方式肯定不是很好的,只是适用了业务的需要,就没有进行深入研究学习。如果大家有更好的方法,请一定要记得告诉我!

注:本人很少写博客,语言表述方面可能欠佳,请大家海涵!

使用html2canvas实现网页截图,并嵌入到PDF的更多相关文章

  1. 使用html2canvas实现网页截图并嵌入到PDF

    以前我们只能通过截图工具进行截取图像.这使得在业务生产中,变得越来越不方便.目前的浏览器功能越来越强大,H5也逐渐普及,浏览器也可以实现截图了.这里来聊下之前在工作中用到的html2canvas.这里 ...

  2. html2canvas.js网页截图功能

    需求:将网页生成图片,用户自行长按图片进行保存图片,再分享朋友圈.其中,都可识别图中的二维码.(二维码过小会识别不出) 首先,先来科普一下微信网页识别二维码原理:截屏识别,当客户端发现用户在网页的im ...

  3. html2canvas - 实现网页截图(+下载截图) 功能

    实现:html2canvas + canvas.toDataURL 首先,引入依赖插件: import { html2canvas } from './html2canvas'; html2canva ...

  4. html2canvas 将网页截图为图片,上传base64 到服务端

    await html2canvas(getById("winyh"), { height:500, allowTaint: true, useCORS: true, }).then ...

  5. html2canvas 网页截图 下载 上传

    利用html2canvas插件 对网页截图 并下载和上传图片. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//E ...

  6. html2canvas实现浏览器截图的原理(包含源码分析的通用方法)

    DevUI是一支兼具设计视角和工程视角的团队,服务于华为云DevCloud平台和华为内部数个中后台系统,服务于设计师和前端工程师. 官方网站:devui.design Ng组件库:ng-devui(欢 ...

  7. 使用PhantomJS实现网页截图服务

    这是上半年遇到的一个小需求,想实现网页的抓取,并保存为图片.研究了不少工具,效果都不理想,不是显示太差了(Canvas.Html2Image.Cobra),就是性能不怎么样(如SWT的Brower). ...

  8. iPhone 收藏网址[添加到书签] 和 [添加到主屏幕] 显示自定义图标,而不是网页截图

    iPhone 收藏网址[添加到书签] 和 [添加到主屏幕] 显示自定义图标,而不是网页截图: <!-- Safari浏览器[添加到书签] --> <link rel="sh ...

  9. 网页中动态嵌入PDF文件/在线预览PDF内容https://www.cnblogs.com/xgyy/p/6119459.html

    #网页中动态嵌入PDF文件/在线预览PDF内容# 摘要:在web开发时我们有时会需要在线预览PDF内容,在线嵌入pdf文件: 问题1:如何网页中嵌入PDF: 在网页中: 常用的几种PDF预览代码片段如 ...

随机推荐

  1. HDU6031:Innumerable Ancestors(二分+倍增数组)

    传送门 题意 n个点的图,有n-1条无向边,m个询问,每次询问 给出两个集合a和b,找到a的一个元素x,b的一个元素y,使得x和y的lca深度最大 分析 这道题如果直接暴力做,复杂度为O(mk1k2* ...

  2. Codeforces630C【水题】

    题意: 有一种数只会有7或者8构成,给一个n,问你前n位上有多少个这样的数. 思路: 对于一个 i 位,有2^i个数,然后前n项和就是2^(n+1)-2; 复习一下等比数列求和,等差数列求和吧; ①: ...

  3. bzoj 4044: [Cerc2014] Virus synthesis【回文自动机+dp】

    建回文自动机,注意到一个回文串是可以通过一个长度小于等于这个串长度的一半的回文串添上一些字符然后复制得到的,也就是在自动机上向fa走,相当于treedp 每次都走显然会T,记录一个up,指向祖先中最下 ...

  4. bzoj 2882: 工艺【SAM】

    看上去比较SA,但是在学SAM所以就用SAM来做-- 把串复制一遍接在后面,对这个新串求SAM(这里的儿子节点要用map转移),然后从根节点每次都向最小的转移走,这样走n次转移的串就是答案 #incl ...

  5. python 导入.py

    转自: https://blog.csdn.net/winycg/article/details/78512300 在同一个文件夹下调用函数:A.py文件: def add(x,y): print(' ...

  6. 洛谷 P1589 泥泞路

    题目描述 暴雨过后,FJ的农场到镇上的公路上有一些泥泞路,他有若干块长度为L的木板可以铺在这些泥泞路上,问他至少需要多少块木板,才能把所有的泥泞路覆盖住. 输入输出格式 输入格式: 第一行为正整数n( ...

  7. sql mysql和sqlserver存在就更新,不存在就插入的写法(转)

    转自:http://hi.baidu.com/tidy0608/item/ff930fe2436f2601560f1dd9 sqlsever数据存在就更新,不存在就插入的两种方法 两种经常使用的方法: ...

  8. 跟我一起玩Win32开发(16):ListView的多个视图

    在上一个例子中,我们只用到了ListView的Report视图,也就是详细视图.本文我们再把上一篇文章中所用的例子进行一下扩展,例子源码可以到俺的资源区下载. 我们为ListView中显示的数据加上图 ...

  9. git for mac

    Git 使用 1.下载完成后打开终端,使用git --version或者which git命令查看安装版本,有就是安装成功了. 2.创建一个全球用户名.全球邮箱 git config --global ...

  10. 题解报告:poj 1113 Wall(凸包)

    Description Once upon a time there was a greedy King who ordered his chief Architect to build a wall ...