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


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

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

    • 不支持iframe
    • 不支持跨域图片
    • 部分浏览器上不支持SVG图片
    • 不支持Flash
    • 不支持古代浏览器和IE9以下
     1 function canvasImg(divName,formName,actionType){ 
     2     html2canvas(divName, {
     3         
     4         onrendered : function(canvas) { 
     5             var myImage = canvas.toDataURL(“image/jpeg”); 
     6             //动态生成input框 
     7             var input1 = document.createElement(‘input’); 
     8             input1.setAttribute(‘type’, ‘hidden’); 
     9             input1.setAttribute(‘name’, ‘canvasImg’); 
    10             input1.setAttribute(‘value’,myImage); 
    11             formName.appendChild(input1); 
    12             formName.actionType.value=actionType; 
    13             formName.submit(); 
    14         } 
    15     }); 
    16 }

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

     1 public static String getImgPath(String data){
     2     //图片输出路径
     3     String imgFilePath = null;
     4     try {
     5         Base64 base64 = new Base64();  
     6         //base64编码解码
     7         byte[] k = base64.decode(data.substring("data:image/jpeg;base64,".length()));  
     8         InputStream is = new ByteArrayInputStream(k);  
     9         String fileName = UUID.randomUUID().toString();  
    10         String pdfFilePath = ShopApplicationResource.shopResource.getString("pdftempfiles.file.root");
    11         imgFilePath = pdfFilePath + fileName + ".jpg";  
    12         double ratio = 1.0;  
    13         BufferedImage image = ImageIO.read(is); 
    14         //设置图片是否缩放 
    15         int newWidth = (int) (image.getWidth() * ratio);  
    16         int newHeight = (int) (image.getHeight() * ratio);  
    17         Image newimage = image.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH);  
    18         BufferedImage tag = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);  
    19         Graphics g = tag.getGraphics();  
    20         g.drawImage(newimage, 0, 0, null);  
    21         g.dispose(); 
    22         //使用io将图片写入文件中 
    23         ImageIO.write(tag, "jpg", new File(imgFilePath));
    24     } catch (IOException e) {
    25         e.printStackTrace();
    26     }  
    27     return imgFilePath;
    28 }

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

     1 public static void covertImgToPdf(String imgPath,HttpServletResponse response,HttpServletRequest request,String pdfFileName){
     2 
     3 Document doc = new Document(PageSize.A4,10,10,10,10);
     4 FileOutputStream os = null;
     5 String pdfFilePath = ShopApplicationResource.shopResource
     6         .getString("pdftempfiles.file.root");
     7 String pafFile = pdfFilePath  + "tempPdf.pdf";
     8 FileInputStream fis =  null;
     9 ServletOutputStream out = null;
    10 try {   
    11     os=new FileOutputStream(pafFile);
    12     PdfWriter pw= PdfWriter.getInstance(doc, os);
    13     pw.setStrictImageSequence(true);
    14 
    15     doc.open();
    16     //设置logo
    17     //String logofile = request.getSession().getServletContext().getRealPath("/bg/images/ht_logo.png");
    18     //com.itextpdf.text.Image logoImg = com.itextpdf.text.Image.getInstance(logofile);
    19     //doc.add(logoImg);
    20     //logoImg.setAlignment(com.itextpdf.text.Image.UNDERLYING);
    21     //logoImg.setAlignment(com.itextpdf.text.Image.LEFT);
    22     //logoImg.scaleToFit(10f,100f);
    23 
    24     com.itextpdf.text.Image img = com.itextpdf.text.Image.getInstance(imgPath);
    25     //居中
    26     img.setAlignment(com.itextpdf.text.Image.MIDDLE);
    27     //自动缩放width*height
    28     img.scaleToFit(PageSize.A4.getWidth(), PageSize.A4.getHeight());
    29     doc.add(img);
    30 
    31     doc.close();
    32     os.flush();
    33     os.close();
    34 
    35     //经pdf文件写入输出流,文件在客户端进行下载
    36      response.setContentType("application/pdf");
    37      String fileName = new String(("pdf"+pdfFileName+".pdf").getBytes("utf-8"), "iso-8859-1");
    38         if (request.getHeader("User-Agent").indexOf("MSIE   5.5") != -1) {
    39             /** MS IE5.5 */
    40             response.setHeader("Content-disposition", "filename="" + fileName + """);
    41         } else {
    42 
    43             /** 非MS IE5.5 */
    44             response.setHeader("Content-disposition", "attachment;filename="" + fileName + """);
    45         }     
    46     File pafFileTemp = new File(pafFile);
    47     fis = new FileInputStream(pafFileTemp);
    48     out = response.getOutputStream();
    49     byte buffer[] =  new byte[1024];
    50     int bytestemp;
    51     while((bytestemp=fis.read(buffer)) != -1){
    52         out.write(buffer, 0, bytestemp);
    53     }
    54     out.close();
    55 
    56     //删除图片
    57   File imgfile = new File(imgPath);
    58   if(imgfile.exists()){
    59      imgfile.delete();
    60    }
    61 
    62  //删除临时PDF
    63   if(pafFileTemp.exists()){
    64       pafFileTemp.delete();
    65    }
    66 
    67 
    68 } catch (Exception e) {
    69     e.printStackTrace();
    70     response.setStatus(HttpServletResponse.SC_OK);
    71 }finally{
    72     if(fis!=null) {
    73         try {
    74             fis.close();
    75         } catch (IOException e) {
    76             e.printStackTrace();
    77         }
    78     }
    79 }
    80 }

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

     1 BufferedImage bi = ImageIO.read(new File(imgPath));
     2     int  destWidth = (int) PageSize.A4.getWidth(); // 切片宽度
     3     int destHeigth = (int) PageSize.A4.getHeight(); // 切片高度
     4     int srcWidth = bi.getWidth();
     5     int srcHeigth = bi.getHeight();
     6     Image image = bi.getScaledInstance(srcWidth, srcHeigth, Image.SCALE_DEFAULT);
     7     int cols  = 0;//切片横向向数量
     8       if (srcHeigth % destHeigth == 0) {
     9           cols  = (int) (srcHeigth / destHeigth);
    10      } else {
    11          cols  = (int) Math.floor(srcHeigth / destHeigth) + 1;
    12      }
    13       //横向循环切图片
    14       for (int i = 0; i < cols ; i++) {
    15           ImageFilter cropFilter;
    16           Image ig;
    17           cropFilter = new CropImageFilter(0, i * destHeigth,srcWidth, destHeigth);
    18           ig = Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(image.getSource(),cropFilter));
    19           BufferedImage tag = new BufferedImage(srcWidth,destHeigth, BufferedImage.TYPE_INT_RGB);
    20           Graphics g = tag.getGraphics();
    21           g.drawImage(ig, 0, 0, null); // 绘制缩小后的图
    22           g.dispose();
    23 
    24          String pdfFilePath = ShopApplicationResource.shopResource.getString("pdftempfiles.file.root");
    25        // 输出为文件
    26          String imgFilePath = pdfFilePath+"temp"+i+".jpg";
    27          ImageIO.write(tag, "JPEG", new File(imgFilePath));
    28          com.itextpdf.text.Image img1 = com.itextpdf.text.Image.getInstance(imgFilePath);
    29         // int percent1 = getPercent2(img1.getHeight(), PageSize.A4.getWidth());
    30         //img1.scalePercent(percent1);
    31         //设置图片宽高
    32          img1.scaleAbsolute(PageSize.A4.getWidth(), img1.getHeight());
    33         //居中
    34          img1.setAlignment(com.itextpdf.text.Image.MIDDLE);
    35         //另起一页
    36          doc.newPage();
    37          doc.add(img1);
    38          File file = new File(imgFilePath);
    39          if(file.exists()){
    40           file.delete();
    41        }
    42       }

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

    原文地址:http://blog.csdn.net/lan_xuan/article/details/49562343

  • 相关阅读:
    超简单留言版
    DirectorySearCh的PropertiesToLoad所有属性
    "Asp.Net Web Api MediaTypeFormatter Error for xwwwformurlencoded data" 解决方法
    关于 NPOI 报 Invalid column index (256). Allowable column range for BIFF8 is (0..255) or ('A'..'IV') 错误的解决办法
    Autofac 的构造函数注入方式
    VirtualBox 内的 Ubuntu Server 虚拟机网络配置
    AngularJS 中设置 AJAX get 请求不缓存的方法
    IIS中使用LocalDB遇到错误:error 50,Local Database Runtime error occurred.的解决办法
    升级 DNX 和 DNVM
    规约模式学习总结
  • 原文地址:https://www.cnblogs.com/qiernonstop/p/6068526.html
Copyright © 2020-2023  润新知