zoukankan      html  css  js  c++  java
  • 使用phantomjs无界浏览器截图

    一、前言:问题的背景

    我之前一直负责一个公众号的项目,老大在别的公众号看到一个功能,可以把自己的盈利记录做一个好看的H5截图分享出去,界面是可以分享出去的,但是如果分享的是一个H5的话,有很多人都懒得点进去,但是如果生成图片的话,把图片分享出去就更加直观也更加吸引人。现在在新媒体盛行的时代,这个应用场景还是很多的,因此今天来介绍一下如何实现。可以关注一下金汇微策略的公众号的最新策略的功能体验,因为我们的公众号只有分析师有这个权限操作。

    二、使用的技术:

    • phantomjs 官网链接
      这个后面我会说windows下和linux下的安装的一些小的区别
    • freemarker
    • bat文件或者.sh文件

    现在可用的技术:
    - html2canvas.js js的实现方案
    但是截图不清晰,同是如果是跨域的图片的话,会无法截图
    - html2image.jar java的生成方案
    实话说,这个jar包的依赖我找了一早上,结果放弃了。同时据网上介绍界面如果复杂的话生成的效果也是不理想
    - DJNativeSwing-SWT.jar java方案
    这种方案是可以行的,亲自试过的,但是可以从上面看到我用的不是这个方案,因为这种采用的是swing的无界浏览器实现的,但是这个线程难以结束,同时无法对动态的页面生成,所以这种方案也被否决掉了
    - phantomjs js的实现方案
    内置webkit,使用无界浏览器的方式截图,基本上能规避上述的所有的缺点。下面着重介绍这种方式

    三、流程:

    • 首先我们依据ftl模板,用freemarker来生成html文件,采用这个步骤的原因是因为,可以生成动态的页面的截图
    • 生成bat文件来执行phantomjs命令,网上很多没有这一步,但是我发现依据网上找到的方案,结果都是无法生成截图的,因为采用绝对路径的方法执行命令是黑白的,所以这里我变通了一下使用批处理文件或者sh脚本来实现
    • java Process 执行bat或者sh文件来执行phantomjs命令来进行截图,这里有个坑,①:生成的截图没有文字,②:文字非常的模糊

      • 这里我也得出一个经验,要找准问题的根源,文字的问题肯定是系统的字体文件有问题,我们的测试服务器为windows server的,我在本地没有问题但是测试服务器有问题,同时正式的服务器linux也是有问题的,
    • 把生成的图上传到素材然后发送客服消息供用户分享

    3.1、所需要的文件:
    • phantomjs.js
    • page.ftl
    • gener.bat|gener.sh

    四、代码

    4.1、使用freemarker生成html界面
    /**
         * 依据ftl模板来生成html,并返回html的名字和(因为不同的人生成的html的数据是不一致的)
         * 并且返回生成的html的名字
         *
         * @return 返回生成的每个人的html
         */
        public static Map<String,String> generHtml(AnalystShare share) throws IOException, TemplateException, InterruptedException {
            Configuration ftlCfg = new Configuration();
            ftlCfg.setEncoding(Locale.getDefault(),"utf-8");
            ftlCfg.setDirectoryForTemplateLoading(new File(Const.FETCH_SCREEN_DIR));
            Template template = ftlCfg.getTemplate(Const.TEMPLATE_NAME,"utf-8");
    
            String generHtmlName = System.currentTimeMillis()+".html";
            String generHtmlPath = Const.FETCH_SCREEN_DIR + generHtmlName;
            File file = new File(generHtmlPath);
            if (!file.exists()) {
                file.createNewFile();
            }
            OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(file),"utf-8");
            PrintWriter printWriter = new PrintWriter(writer);
            Map map = new HashMap<>();
            map.put("share", getFormatShare(share));
            template.setEncoding("utf-8");
            template.process(map, printWriter);
            Thread.sleep(2000);
            printWriter.close();
            Map pathMap = new HashMap<String,String>();
            pathMap.put("generHtmlName",generHtmlName);
            pathMap.put("generHtmlPath",generHtmlPath);
            return pathMap;
        }

    上面有很多点需要注意:
    - ①:乱码的问题
    - ②:把生成的html的名字和全路径返回,在执行phantomjs命令需要html的名字,同时我们生成HTML在完成截图后还是需要删除这个文件的,不然服务器会越积累越多
    - ③:休眠的原因是freemarker生成html的时候需要时间来执行,然后关闭字节流,这个可以依据自己的服务器来进行调节

    4.2、生成bat文件或者sh文件
    /**
         * 创建bat文件并把bat文件的全路径以及img的全路径全部返回回去
         * @param generHtmlName
         * @return
      */
        public static Map<String, String> generBat(String generHtmlName) throws IOException {
            String batFileName = System.currentTimeMillis()+".bat";
            String batFilePath = Const.FETCH_SCREEN_DIR + batFileName;
            String generImgName = System.currentTimeMillis()+".jpg";
            String generImgPath = Const.FETCH_SCREEN_DIR +generImgName;
            File file = new File(batFilePath);
            FileWriter writer = new FileWriter(file);
            writer.write("e:");
            writer.write(System.getProperty("line.separator"));
            writer.write("cd " + Const.FETCH_SCREEN_DIR );
            writer.write(System.getProperty("line.separator"));
            writer.write("phantomjs.exe phantomjs.js " + generHtmlName + " " + generImgName);
            writer.flush();
            writer.close();
            Map map = new HashMap<String, String>();
            map.put("generBatPath", batFilePath);
            map.put("generImgPath", generImgPath);
            map.put("generImgName",generImgName);
            return map;
        }

    上面是生成bat的,sh的命令如下,由于篇幅的原因不在写sh的部分,直接把下面的命令写入到sh文件即可。注意*.html 这个地方要依据你程序生成的HTML的名字为准,上面我是采用毫秒值进行命名的,依据自己的需求进行修改即可,cd的路径也是需要修改的,这里我把所有的文件放在一个目录下。一定要修改成自己实际的文件的名字和目录,下面是我进行本地测试的时候的文件。
    image.png

    cd /data/wwwroot/default/upload/screen/
    ./phantomjs phantomjs.js test.html test.png
    4.2、执行bat|sh文件
     /**
         * 执行bat文件,生成图片
         * @param batPath
         */
        public static void execute(String batPath) throws IOException, InterruptedException {
            Runtime rt = Runtime.getRuntime();
            Process exec = rt.exec(batPath);
            Thread.sleep(5000);
            exec.destroyForcibly();
            exec.destroy();
            return;
        }
    4.3、做善后工作,删除生成的文件
     /***
         * 做完所有的善后的工作,把所有生成的文件delete掉
         * @param htmlPath
         * @param batPath
         * @param imgPath
         */
        public static void destoryAllGenerFile(String htmlPath, String batPath, String imgPath) {
            File file = new File(htmlPath);
            file.deleteOnExit();
            file = new File(batPath);
            file.deleteOnExit();
            file = new File(imgPath);
            file.deleteOnExit();
        }
    4.4、phantomjs.js

    执行phantomjs脚本,生成快照脚本

    /**
     * phantomJs 脚本
     */
    var page = require('webpage').create(), system = require('system'), address, output, size;
    
    if (system.args.length < 3 || system.args.length > 5) {
        phantom.exit(1);
    } else {
        address = system.args[1];
        output = system.args[2];
        //定义宽高
       /* page.viewportSize = {
            width : 1024,
            height : 768
        };*/
        page.open(address, function(status) {
            var bb = page.evaluate(function() {
                return document.getElementsByTagName('html')[0].getBoundingClientRect();
            });
            page.clipRect = {
                top : bb.top,
                left : bb.left,
                width : bb.width,
                height : bb.height
            };
            window.setTimeout(function() {
                page.render(output);
                page.close();
                console.log('渲染成功...');
                console.log(address);
            }, 1000);
        });
    }

    ps:由于ftl文件设计到公司的业务,所以不公开出来,依据这个流程大体是可以生成的。下面说下过程中遇到的问题。
    - 乱码的问题,上面已经介绍过了,
    - 生成图片没有字,在网上搜linux安装字体,把windows上字体复制到linux上面然后执行相关的命令进行安装。如果有问题可以留言。

  • 相关阅读:
    Java并发之CAS与AQS简介
    关系型数据库三范式
    分库分表使用场景及设计方式
    项目部署到tomcat出错(tomcat运行时的JDK版本)
    手写一个简化版Tomcat
    java并发之并发工具
    java并发之停止线程
    class中static总结-静态成员函数和静态成员变量
    45 孩子们的游戏(圆圈中最后剩下的数) + list操作总结+ for_each多记忆容易忘记
    C++ split分割字符串函数
  • 原文地址:https://www.cnblogs.com/fkxuexi/p/10674050.html
Copyright © 2011-2022 走看看