欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java利用Phantomjs实现生成图片的功能

程序员文章站 2022-03-17 21:06:29
今天,给大家分享一个java后端利用phantomjs实现生成图片的功能,同学们使用的时候,可以参考下!phantomjs简介首先,什么是phantomjs?根据官网介绍:phantomjs is a...

今天,给大家分享一个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的处理有错误,这里已修正!):

"use strict";
var page = require('webpage').create(),
  system = require('system'),
  address, output, size;

if (system.args.length < 3 || system.args.length > 5) {
  console.log('usage: rasterize.js url filename [paperwidth*paperheight|paperformat] [zoom]');
  console.log(' paper (pdf output) examples: "5in*7.5in", "10cm*20cm", "a4", "letter"');
  console.log(' image (png/jpg output) examples: "1920px" entire page, window width 1920px');
  console.log('                  "800px*600px" window, clipped to 800x600');
  phantom.exit(1);
} else {
  address = system.args[1];
  output = system.args[2];
  page.viewportsize = { width: 800, height: 200 };
  if (system.args.length > 3 && system.args[2].substr(-4) === ".pdf") {
    size = system.args[3].split('*');
    page.papersize = size.length === 2 ? { width: size[0], height: size[1], margin: '0px' }
                      : { format: system.args[3], orientation: 'portrait', margin: '1cm' };
  } else if (system.args.length > 3 && system.args[3].substr(-2) === "px") {
    size = system.args[3].split('*');
    if (size.length === 2) {
      var pagewidth = parseint(size[0].substr(0,size[0].indexof("px")), 10);
      var pageheight = parseint(size[1].substr(0,size[1].indexof("px")), 10);
      page.viewportsize = { width: pagewidth, height: pageheight };
      page.cliprect = { top: 0, left: 0, width: pagewidth, height: pageheight };
    } else {
      var pagewidth = parseint(system.args[3].substr(0,system.args[3].indexof("px")), 10);
      var pageheight = parseint(pagewidth * 3/4, 10); // it's as good an assumption as any
      page.viewportsize = { width: pagewidth, height: pageheight };
    }
  }
  if (system.args.length > 4) {
    page.zoomfactor = system.args[4];
  }
  page.open(address, function (status) {
    if (status !== 'success') {
      console.log('unable to load the address!');
      phantom.exit(1);
    } else {
      window.settimeout(function () {
        page.render(output);
        phantom.exit();
      }, 200);
    }
  });
}

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

使用方法

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

Java利用Phantomjs实现生成图片的功能

然后,我们创建phantom的使用工具类phantomtools.class:

package test;

import lombok.extern.slf4j.slf4j;
import org.apache.commons.io.fileutils;
import org.apache.commons.io.ioutils;
import org.apache.commons.lang3.stringutils;

import java.io.file;
import java.io.fileinputstream;
import java.io.ioexception;
import java.util.uuid;

/**
 * 网页转图片处理类,使用外部cmd
 *
 * @author lekkoli
 */
@slf4j
public class phantomtools {

  /**
   * 可执行文件phantomjs.exe路径
   */
  private final string phantomjspath;
  /**
   * 快照图生成js路径
   */
  private final string rasterizepath;
  /**
   * 临时图片前缀
   */
  private static final string file_prefix = "tig-ae-";
  /**
   * 临时图片后缀
   */
  private static final string file_suffix = ".jpg";

  /**
   * 构造参数
   * 获取phantomjs路径
   */
  public phantomtools() {
    string bootpath = new file(this.getclass().getresource("/").getpath()).getpath();
    phantomjspath = string.join(file.separator, bootpath, "phantomjs-2.1.1-windows", "bin", "phantomjs");
    rasterizepath = string.join(file.separator, bootpath, "phantomjs-2.1.1-windows", "examples", "rasterize.js");
  }

  /**
   * url 中需要转义的字符
   * 1. + url 中+号表示空格 %2b
   * 2. 空格 url中的空格可以用+号或者编码 %20
   * 3. / 分隔目录和子目录 %2f
   * 4. ? 分隔实际的 url 和参数 %3f
   * 5. % 指定特殊字符 %25
   * 6. # 表示书签 %23
   * 7. & url 中指定的参数间的分隔符 %26
   * 8. = url 中指定参数的值 %3d
   *
   * @param url 需要转义的url
   * @return 转义后的url
   */
  public string parseurl(string url) {
    string parsedurl = stringutils.replace(url, "&", "%26");
    log.info("[解析后的url:{}]", parsedurl);
    return parsedurl;
  }

  /**
   * 根据url生成指定filename的字节数组
   *
   * @param url 请求url
   * @return 图片字节数组
   */
  public byte[] create(string url) {
    return create(url, null);
  }

  /**
   * 根据url生成指定filename的字节数组
   *
   * @param url 请求url
   * @param size 指定图片尺寸,例如:1000px*800px
   * @return 图片字节数组
   */
  public byte[] create(string url, string size) {
    // 服务器文件存放地址
    string filepath = fileutils.gettempdirectorypath() + file_prefix + uuid.randomuuid().tostring() + file_suffix;
    try {
      // 执行快照命令
      string command = string.join(stringutils.space, phantomjspath, rasterizepath, url, filepath, size);
      log.info("[执行命令:{}]", command);
      // 执行命令操作
      process process = runtime.getruntime().exec(command);
      // 一直挂起,直到子进程执行结束,返回值0表示正常退出
      if (process.waitfor() != 0) {
        log.error("[执行本地command命令失败] [command:{}]", command);
        return new byte[0];
      }
      // 判断生成的图片是否存在
      file file = fileutils.getfile(filepath);
      if (!file.exists()) {
        log.error("[本地文件\"{}\"不存在]", file.getname());
        return new byte[0];
      }
      // 将快照图片生成字节数组
      byte[] bytes = ioutils.tobytearray(new fileinputstream(file));
      log.info("[图片生成结束] [图片大小:{}kb]", bytes.length / 1024);
      return bytes;
    } catch (ioexception | interruptedexception e) {
      log.error("[图片生成失败]", e);
    } finally {
      fileutils.deletequietly(fileutils.getfile(filepath));
    }
    return new byte[0];
  }
}

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

其中,process对象底层调用的其实就是processbuilder

public process exec(string[] cmdarray, string[] envp, file dir)
  throws ioexception {
  return new processbuilder(cmdarray)
    .environment(envp)
    .directory(dir)
    .start();
}

processbuilder会调用processimpl的许多底层native方法完成url访问与图片生成。

测试方法:

public static void main(string[] arg) throws ioexception {
  string url = "https://www.cnblogs.com/ason-wxs/";
  phantomtools phantomtools = new phantomtools();
  string parsedurl = phantomtools.parseurl(url);
  byte[] byteimg = phantomtools.create(parsedurl);
  file descfile = new file(fileutils.gettempdirectorypath() + "test.png");
  fileutils.touch(descfile);
  fileutils.writebytearraytofile(descfile, byteimg);
}

测试结果我就不贴出来了,无非将我的博客首页生成图片保存到指定文件test.png中。

好了,希望上面对phantomjs的介绍对你今后工作有所帮助!

以上就是java利用phantomjs实现生成图片的功能的详细内容,更多关于java 生成图片的资料请关注其它相关文章!