今天,给大家分享一个Java后端利用Phantomjs实现生成图片的功能,同学们使用的时候,可以参考下!

PhantomJS简介

首先,什么是PhantomJS?

根据官网介绍:

PhantomJS is a command-line tool. -- 其实就是一个命令行工具。

PhantomJS的下载地址:

Windows:phantomjs-2.1.1-windows.zip

Linux:phantomjs-2.1.1-linux-x86_64.tar.bz2;phantomjs-2.1.1-linux-i686.tar.bz2

MacOS:phantomjs-2.1.1-macosx.zip

下载下来后,我们看到bin目录下就是可执行文件phantomjs.exe,我们可以将它配置到环境变量中,方便命令使用!

还有一个examples目录,它下面是很多js样例,关于这些样例作用,参考官网解释,给大家做个简单翻译:

1. Basic examples

  • arguments.js:显示传递给脚本的参数
  • countdown.js:打印10秒倒计时
  • echoToFile.js:将命令行参数写入文件
  • fibo.js:列出了斐波那契数列中的前几个数字
  • hello.js:显示著名消息
  • module.js:并universe.js演示模块系统的使用
  • outputEncoding.js:显示各种编码的字符串
  • printenv.js:显示系统的环境变量
  • scandir.js:列出目录及其子目录中的所有文件
  • sleepsort.js:对整数进行排序并根据其值延迟显示
  • version.js:打印出PhantomJS版本号
  • page_events.js:打印出页面事件触发:有助于更好地掌握page.on*回调

    2. Rendering/rasterization
  • colorwheel.js:使用HTML5画布创建色轮
  • rasterize.js:将网页光栅化为图像或PDF
  • render_multi_url.js:将多个网页渲染为图像

    3. Page automation
  • injectme.js:将自身注入到网页上下文中
  • phantomwebintro.js:使用jQuery从phantomjs.org读取.version元素文本
  • unrandomize.js:在页面初始化时修改全局对象
  • waitfor.js:等待直到测试条件为真或发生超时

    4. Network
  • detectniff.js:检测网页是否嗅探用户代理
  • loadspeed.js:计算网站的加载速度
  • netlog.js:转储所有网络请求和响应
  • netsniff.js:以HAR格式捕获网络流量
  • post.js:将HTTP POST请求发送到测试服务器
  • postserver.js:启动Web服务器并向其发送HTTP POST请求
  • server.js:启动Web服务器并向其发送HTTP GET请求
  • serverkeepalive.js:启动Web服务器,以纯文本格式回答
  • simpleserver.js:启动Web服务器,以HTML格式回答

    5. Testing
  • run-jasmine.js:运行基于Jasmine的测试
  • run-qunit.js:运行基于QUnit的测试

    6. Browser
  • features.js:检测浏览器功能使用modernizr.js
  • useragent.js:更改浏览器的用户代理属性

今天,我们根据网页URL生成图片,使用的就是rasterize.js:将网页光栅化为图像或PDF

了解rasterize.js

我们来看一下rasterize.js的内容(源文件对size的处理有错误,这里已修正!):

  1. "use strict";
  2. var page = require('webpage').create(),
  3. system = require('system'),
  4. address, output, size;
  5. if (system.args.length < 3 || system.args.length > 5) {
  6. console.log('Usage: rasterize.js URL filename [paperwidth*paperheight|paperformat] [zoom]');
  7. console.log(' paper (pdf output) examples: "5in*7.5in", "10cm*20cm", "A4", "Letter"');
  8. console.log(' image (png/jpg output) examples: "1920px" entire page, window width 1920px');
  9. console.log(' "800px*600px" window, clipped to 800x600');
  10. phantom.exit(1);
  11. } else {
  12. address = system.args[1];
  13. output = system.args[2];
  14. page.viewportSize = { width: 800, height: 200 };
  15. if (system.args.length > 3 && system.args[2].substr(-4) === ".pdf") {
  16. size = system.args[3].split('*');
  17. page.paperSize = size.length === 2 ? { width: size[0], height: size[1], margin: '0px' }
  18. : { format: system.args[3], orientation: 'portrait', margin: '1cm' };
  19. } else if (system.args.length > 3 && system.args[3].substr(-2) === "px") {
  20. size = system.args[3].split('*');
  21. if (size.length === 2) {
  22. var pageWidth = parseInt(size[0].substr(0,size[0].indexOf("px")), 10);
  23. var pageHeight = parseInt(size[1].substr(0,size[1].indexOf("px")), 10);
  24. page.viewportSize = { width: pageWidth, height: pageHeight };
  25. page.clipRect = { top: 0, left: 0, width: pageWidth, height: pageHeight };
  26. } else {
  27. var pageWidth = parseInt(system.args[3].substr(0,system.args[3].indexOf("px")), 10);
  28. var pageHeight = parseInt(pageWidth * 3/4, 10); // it's as good an assumption as any
  29. page.viewportSize = { width: pageWidth, height: pageHeight };
  30. }
  31. }
  32. if (system.args.length > 4) {
  33. page.zoomFactor = system.args[4];
  34. }
  35. page.open(address, function (status) {
  36. if (status !== 'success') {
  37. console.log('Unable to load the address!');
  38. phantom.exit(1);
  39. } else {
  40. window.setTimeout(function () {
  41. page.render(output);
  42. phantom.exit();
  43. }, 200);
  44. }
  45. });
  46. }

有过终端开发的人,对这段命令理解起来都不会太难,这里我就不多说了,后面,我们重点介绍它的使用!

使用方法

首先,我们将Phantom的包引入工程,放在resources目录下。因为我们要保证本地windows开发与服务器linux环境开发打包后都能运行,所以,我们将windows和linux两个包都引入。

然后,我们创建Phantom的使用工具类PhantomTools.class

  1. package test;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.apache.commons.io.FileUtils;
  4. import org.apache.commons.io.IOUtils;
  5. import org.apache.commons.lang3.StringUtils;
  6. import java.io.File;
  7. import java.io.FileInputStream;
  8. import java.io.IOException;
  9. import java.util.UUID;
  10. /**
  11. * 网页转图片处理类,使用外部CMD
  12. *
  13. * @author lekkoli
  14. */
  15. @Slf4j
  16. public class PhantomTools {
  17. /**
  18. * 可执行文件phantomjs.exe路径
  19. */
  20. private final String phantomjsPath;
  21. /**
  22. * 快照图生成JS路径
  23. */
  24. private final String rasterizePath;
  25. /**
  26. * 临时图片前缀
  27. */
  28. private static final String FILE_PREFIX = "TIG-AE-";
  29. /**
  30. * 临时图片后缀
  31. */
  32. private static final String FILE_SUFFIX = ".jpg";
  33. /**
  34. * 构造参数
  35. * 获取phantomjs路径
  36. */
  37. public PhantomTools() {
  38. String bootPath = new File(this.getClass().getResource("/").getPath()).getPath();
  39. phantomjsPath = String.join(File.separator, bootPath, "phantomjs-2.1.1-windows", "bin", "phantomjs");
  40. rasterizePath = String.join(File.separator, bootPath, "phantomjs-2.1.1-windows", "examples", "rasterize.js");
  41. }
  42. /**
  43. * url 中需要转义的字符
  44. * 1. + URL 中+号表示空格 %2B
  45. * 2. 空格 URL中的空格可以用+号或者编码 %20
  46. * 3. / 分隔目录和子目录 %2F
  47. * 4. ? 分隔实际的 URL 和参数 %3F
  48. * 5. % 指定特殊字符 %25
  49. * 6. # 表示书签 %23
  50. * 7. & URL 中指定的参数间的分隔符 %26
  51. * 8. = URL 中指定参数的值 %3D
  52. *
  53. * @param url 需要转义的URL
  54. * @return 转义后的URL
  55. */
  56. public String parseUrl(String url) {
  57. String parsedUrl = StringUtils.replace(url, "&", "%26");
  58. log.info("[解析后的URL:{}]", parsedUrl);
  59. return parsedUrl;
  60. }
  61. /**
  62. * 根据URL生成指定fileName的字节数组
  63. *
  64. * @param url 请求URL
  65. * @return 图片字节数组
  66. */
  67. public byte[] create(String url) {
  68. return create(url, null);
  69. }
  70. /**
  71. * 根据URL生成指定fileName的字节数组
  72. *
  73. * @param url 请求URL
  74. * @param size 指定图片尺寸,例如:1000px*800px
  75. * @return 图片字节数组
  76. */
  77. public byte[] create(String url, String size) {
  78. // 服务器文件存放地址
  79. String filePath = FileUtils.getTempDirectoryPath() + FILE_PREFIX + UUID.randomUUID().toString() + FILE_SUFFIX;
  80. try {
  81. // 执行快照命令
  82. String command = String.join(StringUtils.SPACE, phantomjsPath, rasterizePath, url, filePath, size);
  83. log.info("[执行命令:{}]", command);
  84. // 执行命令操作
  85. Process process = Runtime.getRuntime().exec(command);
  86. // 一直挂起,直到子进程执行结束,返回值0表示正常退出
  87. if (process.waitFor() != 0) {
  88. log.error("[执行本地Command命令失败] [Command:{}]", command);
  89. return new byte[0];
  90. }
  91. // 判断生成的图片是否存在
  92. File file = FileUtils.getFile(filePath);
  93. if (!file.exists()) {
  94. log.error("[本地文件\"{}\"不存在]", file.getName());
  95. return new byte[0];
  96. }
  97. // 将快照图片生成字节数组
  98. byte[] bytes = IOUtils.toByteArray(new FileInputStream(file));
  99. log.info("[图片生成结束] [图片大小:{}KB]", bytes.length / 1024);
  100. return bytes;
  101. } catch (IOException | InterruptedException e) {
  102. log.error("[图片生成失败]", e);
  103. } finally {
  104. FileUtils.deleteQuietly(FileUtils.getFile(filePath));
  105. }
  106. return new byte[0];
  107. }
  108. }

上面工具类,通过构造方法初始化了命令包路径,调用parseUrl()方法对URL中含有的&符号做了替换,最核心的命令执行,采用Process对象完成,最后输出到临时目录下的图片文件。这就是phantomjs对Web访问页的图片生成流程。

其中,Process对象底层调用的其实就是ProcessBuilder

  1. public Process exec(String[] cmdarray, String[] envp, File dir)
  2. throws IOException {
  3. return new ProcessBuilder(cmdarray)
  4. .environment(envp)
  5. .directory(dir)
  6. .start();
  7. }

ProcessBuilder会调用ProcessImpl的许多底层native方法完成URL访问与图片生成。

测试方法:

  1. public static void main(String[] arg) throws IOException {
  2. String url = "https://www.cnblogs.com/ason-wxs/";
  3. PhantomTools phantomTools = new PhantomTools();
  4. String parsedUrl = phantomTools.parseUrl(url);
  5. byte[] byteImg = phantomTools.create(parsedUrl);
  6. File descFile = new File(FileUtils.getTempDirectoryPath() + "test.png");
  7. FileUtils.touch(descFile);
  8. FileUtils.writeByteArrayToFile(descFile, byteImg);
  9. }

Phantomjs实现后端生成图片文件的更多相关文章

  1. highcharts 结合phantomjs纯后台生成图片

    highcharts 结合phantomjs纯后台生成图片 highcharts 这个图表展示插件我想大家应该都知道,纯javascript编写,相比那些flash图表插件有很大的优势,至少浏览器不用 ...

  2. highcharts 结合phantomjs纯后台生成图片系列二之php2

    上篇文章中介绍了phantomjs的使用场景,方法. 本篇文章详细介绍使用php,highcharts 结合phantomjs纯后台生成图片.包含一步步详细的php代码 一.highcharts 结合 ...

  3. highcharts 结合phantomjs纯后台生成图片系列二之php

    上篇文章中介绍了phantomjs的使用场景,方法.本篇文章详细介绍使用php,highcharts 结合phantomjs纯后台生成图片. 一.准备: 下载phantomjs解析插件,从 highc ...

  4. Jquery二维码在线生成(不能生成图片文件)

    附件地址:http://files.cnblogs.com/files/harxingxing/jQuery%E4%BA%8C%E7%BB%B4%E7%A0%81%E5%9C%A8%E7%BA%BF% ...

  5. 前端js上传文件 到后端接收文件

    下面是前端js代码: <html> <head> <meta http-equiv="Content-Type" content="text ...

  6. 使用webdriver + phantomjs + pdfkit 生成PDF文件

    实例 #!/usr/bin/python # -*- coding: utf-8 -*- ''' Created on Dec 6, 2013 @author: Jay <smile665@gm ...

  7. 20181013xlVba据成绩条生成图片文件

    Sub CreateGoalPictures() '声明变量 Dim Wb As Workbook Dim Sht As Worksheet Dim Shp As Shape Dim Pic, End ...

  8. Java从后端下载文件到浏览器

    // 注: // 获取项目下文件或者文件流 // File file = new File(this.getClass().getResource("/xls/adminImportUser ...

  9. PHP对图片按照一定比例缩放并生成图片文件

    list($width, $height)=getimagesize($filename);//缩放比例$per=round(400/$width,3); $n_w=$width*$per;$n_h= ...

随机推荐

  1. HBuilder生成证书

    一.安装jdk https://www.oracle.com/java/technologies/javase-downloads.html 二.打开CMD命令到JDK安装目录bin文件夹下 执行命令 ...

  2. .Net Core微服务入门全纪录(八)——Docker Compose与容器网络

    Tips:本篇已加入系列文章阅读目录,可点击查看更多相关文章. 前言 上一篇[.Net Core微服务入门全纪录(七)--IdentityServer4-授权认证]中使用IdentityServer4 ...

  3. (一)学习了解OrchardCore笔记——开篇:基于asp.net core的OrchardCore

    想深入了解OrchadCore源码许久了,但是读源码的时候遇到很多问题而网上的参考资料太少了(几乎都是OrchadCms不带OrchardCore的),现在解决得差不多了,做下笔记方便自己查看,有错误 ...

  4. Maven 专题(七):常用命令

    mvn archetype:generate : 反向生成项目的骨架 mvn clean: 清除各个模块target目录及里面的内容 mvn compile: 静态编译,根据xx.java生成xx.c ...

  5. 数据可视化之DAX篇(七) Power BI中用DAX生成的表如何添加索引列?

    ​https://zhuanlan.zhihu.com/p/74732578 来源于知识星球中一个星友的问题,使用DAX在PowerBI中新建了一个表,如何为这个表添加索引列呢? 假如数据模型中只有一 ...

  6. BFC 生成 特性 解决的问题

    BFC( 块级格式化上下文 ) 块级格式化上下文,它是指一个独立的块级渲染区域, 只有 Block­level BOX 参与,该区域拥有一套 渲染规则来约束块级盒子的布局,且与区域外部无关. 如何生成 ...

  7. Docker搭建部署Node项目

    前段时间做了个node全栈项目,服务端技术栈是 nginx + koa + postgresql.其中在centos上搭建环境和部署都挺费周折,部署测试服务器,接着上线的时候又部署生产环境服务器.这中 ...

  8. 问题:IE11下window.history.go(-1)返回404

    解决方法: 在后面添加return false,如: onclick="javascript:window.history.go(-1);return false" 这个问题在IE ...

  9. Ethical Hacking - GAINING ACCESS(16)

    CLIENT SIDE ATTACKS - Social Engineering Social Engineering Information gathering Tool: Maltego Gath ...

  10. Python Ethical Hacking - The Lab and Needed Software

    The Lab and Needed Software Attacker Machine - Kali Linux https://www.kali.org/ 1. Install the softw ...