zoukankan      html  css  js  c++  java
  • 使用html2canvas实现网页截图,并嵌入到PDF

    使用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页中,直到切完所有。这种方式肯定不是很好的,只是适用了业务的需要,就没有进行深入研究学习。如果大家有更好的方法,请一定要记得告诉我!

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

  • 相关阅读:
    FMDB线程安全
    FMDB的使用
    iOS【手机验证码】判断手机号是否合法
    UIScrollView UIScrollViewDelegate
    iOS苹果开发者常用网站
    < meta http-equiv = "X-UA-Compatible" content = "IE=edge,chrome=1" />
    CSS布局口诀
    css垂直居中
    在js中使用createElement创建HTML对象和元素
    jQuery-对Radio/CheckBox的操作集合
  • 原文地址:https://www.cnblogs.com/lanxuan826/p/9873708.html
Copyright © 2011-2022 走看看