今天,給大家分享一個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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
"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兩個包都引入。
然后,我們創建Phantom的使用工具類PhantomTools.class:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
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
。
1
2
3
4
5
6
7
|
public Process exec(String[] cmdarray, String[] envp, File dir) throws IOException { return new ProcessBuilder(cmdarray) .environment(envp) .directory(dir) .start(); } |
ProcessBuilder
會調用ProcessImpl
的許多底層native方法完成URL訪問與圖片生成。
測試方法:
1
2
3
4
5
6
7
8
9
|
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 生成圖片的資料請關注服務器之家其它相關文章!
原文鏈接:https://www.cnblogs.com/ason-wxs/p/13411271.html