刘亚壮的专栏

持之以恒,贵在坚持,每天进步一点点。。。

Java之——Java实现网页截屏功能(图片下载功能)的几种方式(整理)

转载请注明出处:https://blog.csdn.net/l1028386804/article/details/79955398

最近的项目中,需要实现一个将网页中显示的内容导出为图片的功能,故研究了一下可以实现这个功能的各种方式,整理在此,以供以后使用。

前台方式

1. 利用html2canvas实现前台截屏

html2canvas项目的gitHub地址
html2canvas示例

html2canvas可以将HTML代码块进行截取,并生成快照形式的canvas,然后可以利用html5的下载功能提供图片的下载接口,供用户下载。

优点:前台技术,实现比较容易。

缺点:此项目使用了html5的技术,因此在对IE的兼容上,只可以在IE9+的版本上使用。

使用时,需要引用jQuery.js和html2canvas.js。(html2canvas.js可以在github上下载)

具体JavaScript代码如下:

var canvas = function () {
    html2canvas($("#chart"), {
              onrendered: function (canvas) {
                  $("#class11").html(canvas);//将id为“class11”部分的代码转换为canvas
                  var type = 'png';//图片类型为png
                  var imgData = canvas.toDataURL('png');//将图片转换为png类型的流

                  var _fixType = function (type) {
                      type = type.toLowerCase().replace(/jpg/i, 'jpeg');
                      var r = type.match(/png|jpeg|bmp|gif/)[0];
                      return 'image/' + r;
                  };

                  var saveFile = function (data, filename) {
                      var save_link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
                      save_link.href = data;
                      save_link.download = filename;

                      var event = document.createEvent('MouseEvents');
                      event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
                      save_link.dispatchEvent(event);
                  };

                  //下载时的文件名
                  var filename = 'baidufe_' + (new Date()).getTime() + '.' + type;

                  // 下载文件
                  saveFile(imgData, filename);
              }
          });
};

后台方式(java)

1. 利用html2image实现

html2image的地址(google)
html2image是可以识别html标签并将html转换成图片的java项目。

优点:后台转换,故对浏览器的版本基本没有要求。

缺点:对样式的识别不是很好,转换出来的图片比较简单,基本没有可以兼容的样式。

使用方式:maven中引用如下依赖:

<dependency>
  <groupId>com.github.xuwei-k</groupId>
  <artifactId>html2image</artifactId>
  <version>0.1.0</version>
</dependency>

2. 利用DJNativeSwing项目实现

纯java代码实现。使用DJNativeSwing这个项目,构建一个swing浏览器,打开网址,之后截取图片。(需要eclipse的swt库支持)

优点:纯java实现。

缺点:需要多线程的支持,只在控制台方式实现过

使用这个方法,需要引用的maven依赖如下:

<dependency>
    <groupId>com.hynnet</groupId>
    <artifactId>DJNativeSwing</artifactId>
    <version>1.0.0</version>
</dependency>

<dependency>
    <groupId>com.hynnet</groupId>
    <artifactId>DJNativeSwing-SWT</artifactId>
    <version>1.0.0</version>
</dependency>

<dependency>                            
	<groupId>org.eclipse.swt.org.eclipse.swt.win32.win32.x86_64.4.3.swt</groupId>
    <artifactId>org.eclipse.swt.win32.win32.x86_64</artifactId>
    <version>4.3</version>
</dependency>
实现代码如下(引用自http://blog.csdn.net/buddyuu/article/details/52699997):
public class PrintScreen4DJNativeSwingUtils extends JPanel {

    private static final long serialVersionUID = 1L;
    // 行分隔符
    final static public String LS = System.getProperty("line.separator", "/n");
    // 文件分割符
    final static public String FS = System.getProperty("file.separator", "//");
    // 当网页超出目标大小时 截取
    final static public int maxWidth = 2000;
    final static public int maxHeight = 1400;

    /**
     * @param file
     *            预生成的图片全路径
     * @param url
     *            网页地址
     * @param width
     *            打开网页宽度 ,0 = 全屏
     * @param height
     *            打开网页高度 ,0 = 全屏
     * @return boolean
     */
    public PrintScreen4DJNativeSwingUtils(final String file, final String url, final String WithResult) {
        super(new BorderLayout());
        JPanel webBrowserPanel = new JPanel(new BorderLayout());
        final JWebBrowser webBrowser = new JWebBrowser(null);
        webBrowser.setBarsVisible(false);
        webBrowser.navigate(url);
        webBrowserPanel.add(webBrowser, BorderLayout.CENTER);
        add(webBrowserPanel, BorderLayout.CENTER);
        JPanel panel = new JPanel(new FlowLayout());
        webBrowser.addWebBrowserListener(new WebBrowserAdapter() {
            // 监听加载进度
            public void loadingProgressChanged(WebBrowserEvent e) {
                // 当加载完毕时
                if (e.getWebBrowser().getLoadingProgress() == 100) {
                    String result = (String) webBrowser.executeJavascriptWithResult(WithResult);
                    int index = result == null ? -1 : result.indexOf(":");
                    NativeComponent nativeComponent = webBrowser.getNativeComponent();
                    Dimension originalSize = nativeComponent.getSize();
                    Dimension imageSize = new Dimension(Integer.parseInt(result.substring(0, index)),
                            Integer.parseInt(result.substring(index + 1)));
                    imageSize.width = Math.max(originalSize.width, imageSize.width + 50);
                    imageSize.height = Math.max(originalSize.height, imageSize.height + 50);
                    nativeComponent.setSize(imageSize);
                    BufferedImage image = new BufferedImage(imageSize.width, imageSize.height,
                            BufferedImage.TYPE_INT_RGB);
                    nativeComponent.paintComponent(image);
                    nativeComponent.setSize(originalSize);
                    // 当网页超出目标大小时
                    if (imageSize.width > maxWidth || imageSize.height > maxHeight) {
                        // 截图部分图形
                        image = image.getSubimage(0, 0, maxWidth, maxHeight);
                        // 此部分为使用缩略图
                        /*
                         * int width = image.getWidth(), height = image
                         * .getHeight(); AffineTransform tx = new
                         * AffineTransform(); tx.scale((double) maxWidth /
                         * width, (double) maxHeight / height);
                         * AffineTransformOp op = new AffineTransformOp(tx,
                         * AffineTransformOp.TYPE_NEAREST_NEIGHBOR); //缩小 image
                         * = op.filter(image, null);
                         */
                    }
                    try {
                        // 输出图像
                        ImageIO.write(image, "jpg", new File(file));
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                    // 退出操作
                    System.exit(0);
                }
            }
        });
        add(panel, BorderLayout.SOUTH);

    }

    // 以javascript脚本获得网页全屏后大小
    public static String getScreenWidthHeight() {

        StringBuffer jsDimension = new StringBuffer();
        jsDimension.append("var width = 0;").append(LS);
        jsDimension.append("var height = 0;").append(LS);
        jsDimension.append("if(document.documentElement) {").append(LS);
        jsDimension.append("  width = Math.max(width, document.documentElement.scrollWidth);").append(LS);
        jsDimension.append("  height = Math.max(height, document.documentElement.scrollHeight);").append(LS);
        jsDimension.append("}").append(LS);
        jsDimension.append("if(self.innerWidth) {").append(LS);
        jsDimension.append("  width = Math.max(width, self.innerWidth);").append(LS);
        jsDimension.append("  height = Math.max(height, self.innerHeight);").append(LS);
        jsDimension.append("}").append(LS);
        jsDimension.append("if(document.body.scrollWidth) {").append(LS);
        jsDimension.append("  width = Math.max(width, document.body.scrollWidth);").append(LS);
        jsDimension.append("  height = Math.max(height, document.body.scrollHeight);").append(LS);
        jsDimension.append("}").append(LS);
        jsDimension.append("return width + ':' + height;");

        return jsDimension.toString();
    }

    public static boolean printUrlScreen2jpg(final String file, final String url, final int width, final int height) {

        NativeInterface.open();
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                String withResult = "var width = " + width + ";var height = " + height + ";return width +':' + height;";
                if (width == 0 || height == 0)
                    withResult = getScreenWidthHeight();

                JFrame frame = new JFrame("网页截图");
                // 加载指定页面,最大保存为640x480的截图
                frame.getContentPane().add(new PrintScreen4DJNativeSwingUtils(file, url, withResult),
                        BorderLayout.CENTER);
                frame.setSize(640, 480);
                // 仅初始化,但不显示
                frame.invalidate();

                frame.pack();
                frame.setVisible(false);
            }
        });
        NativeInterface.runEventPump();

        return true;
    }

    public static void main(String[] args) {  

        PrintScreen4DJNativeSwingUtils.printUrlScreen2jpg("1122.jpg", "https://www.baidu.com", 1400, 900);

    }
}

3. 利用phantomJs实现

phantomJs的GitHub地址
phantomJs官网

phantom利用的是webKit内核,全面支持web而不需浏览器支持,快速,原生支持各种Web标准。

优点:速度快,使用简单。

缺点:需要在项目的服务器端引用exe文件进行截图,并发性能有待考证。

使用这个方式,需要去官网下载最新的phantomJs脚本。官网地址在上面的链接中。

具体代码如下(引用自http://www.cnblogs.com/lekko/p/4796062.html):

/**
 * 网页转图片处理类,使用外部CMD
 */
public class PhantomTools {

    private static final Logger _logger = Logger.getLogger(PhantomTools.class);

    private static final String _tempPath = "D:/data/temp/phantom_";
    private String basePath;
    private static final String _shellCommand1 = "phantomjs ";
    private static final String _shellCommand2 = "rasterize.js ";

    private String _file;
    private String _size;

    /**
     * 构造截图类
     * @param hash 用于临时文件的目录唯一化
     * @param basePath phantomJs所在路径
     */
    public PhantomTools(int hash, String basePath) {
        _file = _tempPath + hash + ".png";
        this.basePath = basePath;
    }

    /**
     * 构造截图类
     * @param hash 用于临时文件的目录唯一化
     * @param size 图片的大小,如800px*600px(此时高度会裁切),或800px(此时 高度最少=宽度*9/16,高度不裁切)
     * @param basePath phantomJs所在路径
     */
    public PhantomTools(int hash, String size, String basePath) {
        _file = _tempPath + hash + ".png";
        if (size != null)
            _size = " " + size;
        this.basePath = basePath;
    }

    /**
     * 将目标网页转为图片字节流
     * @param url 目标网页地址
     * @return 字节流
     */
    public byte[] getByteImg(String url) throws IOException {
        BufferedInputStream in = null;
        ByteArrayOutputStream out = null;
        File file = null;
        byte[] ret = null;
        try {
            if (exeCmd(basePath + _shellCommand1 + basePath + _shellCommand2 + url + " " + _file + (_size != null ? _size : ""))) {
                file = new File(_file);
                if (file.exists()) {
                    out = new ByteArrayOutputStream();
                    byte[] b = new byte[5120];
                    in = new BufferedInputStream(new FileInputStream(file));
                    int n;
                    while ((n = in.read(b, 0, 5120)) != -1) {
                        out.write(b, 0, n);
                    }
                    file.delete();
                    ret = out.toByteArray();
                }
            } else {
                ret = new byte[] {};
            }
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                _logger.error(e);
            }
            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                _logger.error(e);
            }
            if (file != null && file.exists()) {
                file.delete();
            }
        }
        return ret;
    }

    /**
     * 执行CMD命令
     */
    private static boolean exeCmd(String commandStr) {
        BufferedReader br = null;
        try {
            Process p = Runtime.getRuntime().exec(commandStr);
            if (p.waitFor() != 0 && p.exitValue() == 1) {
                return false;
            }
        } catch (Exception e) {
            _logger.error(e);
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (Exception e) {
                    _logger.error(e);
                }
            }
        }
        return true;
    }
}

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/l1028386804/article/details/79955398
文章标签: Java
个人分类: JAVA
所属专栏: Java
上一篇ElasticSearch之——linux下安装及head插件
下一篇Python之——Python 3.6 Socket TypeError: a bytes-like object is required, not 'str' 错误提示
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭