前言

java将html转图片等方案,仅适合很简单的页面,对CSS的支持有限,效果不理想。
如:

<dependency>
    <groupId>com.github.xuwei-k</groupId>
    <artifactId>html2image</artifactId>
    <version>0.1.0</version>
</dependency>
<dependency>
    <groupId>org.xhtmlrenderer</groupId>
    <artifactId>flying-saucer-core</artifactId>
    <version>9.1.16</version>
</dependency>
<dependency>
    <groupId>net.sf.cssbox</groupId>
    <artifactId>cssbox</artifactId>
    <version>5.0.0</version>
</dependency>

成熟方案一

https://blog.csdn.net/weixin_41118077/article/details/119934868
java方案,效果也还可以,样式支持较全

<dependency>
            <groupId>com.openhtmltopdf</groupId>
            <artifactId>openhtmltopdf-core</artifactId>
            <version>1.0.9</version>
        </dependency>
        <dependency>
            <groupId>com.openhtmltopdf</groupId>
            <artifactId>openhtmltopdf-java2d</artifactId>
            <version>1.0.9</version>
        </dependency>

成熟方案二

wkhtmltopdf和wkhtmltoimage是开源(LGPLv3)命令行工具,使用Qt WebKit渲染引擎将HTML渲染为PDF和各种图像格式。它们完全“无头”运行,并且不需要显示器或显示服务。
开发语言:C++
https://wkhtmltopdf.org/

成熟方案三

Doctron,它是基于Docker、无状态、简单、快速、高质量的文档转换服务。目前支持将html转为pdf、图片(使用chrome(Chromium)浏览器内核,保证转换质量)。支持PDF添加水印。
开发语言:go
开源项目地址:https://github.com/lampnick/doctron

对比

渲染内核不同:Chromium > Qt WebKit(不支持ES6) (样式特性支持程度)
速度对比:C++ > go
图片质量:wkhtmltoX > Doctron

- png jpg_100 jpg_50
wkhtml 24.7M 1.8M 338K
doctron 2.2M 1.7M 302K

部署便利: Doctron > wkhtmltoX

  • png比jpeg清晰度更高
  • wkhtml的png确实非常清楚,但是体积太大,慎重考虑

补充可选方案

补充一:rayin

https://gitee.com/Rayin/rayin

补充二:cutycapt

https://www.cnblogs.com/tdalcn/p/8466122.html
https://www.likecs.com/show-733340.html

由于Doctron截较长页面时超时(docker部署可复现,已提github issue,但本地启动项目没这个问题,可能是环境原因折腾两天未果决定换方案),wkhtmltoX样式支持不太好个别样式错乱了(还有一个原因是产出的结果图有白边,可能是bug),最终选择了cutycapt方案。

转长图服务的备选方案

1.服务:nginx/openresty代理某个目录,生成的图片放里面,请求来了就调用下命令生成图片,响应回去url,谁调用,谁自己处理文件,决定是一次性的还是上传oss。

2.安全:只允许生产和测试服务器ip访问,防火墙或lua处理

3.垃圾处理:系统的定时任务
https://www.cnblogs.com/xiao-xue-di/p/14689388.html

nginx性能好,无需java环境,节省服务器资源,不用写代码


lua获取get请求参数
https://blog.csdn.net/xiejunna/article/details/75098266
lua获取post请求参数
https://www.cnblogs.com/cherylgi/p/16428883.html
lua调用命令行生成图片
https://blog.csdn.net/Outbreak_Jinx/article/details/90722210

前端方式

<script src="https://cdn.bootcdn.net/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/downloadjs/1.4.8/download.min.js"></script>
<script>
    // 使用html2canvas 转换html为canvas
    function downloadForJS() {
        html2canvas(document.querySelector(".container"), {
            scale: 2
        }).then(function (canvas) {
            var imgUri = canvas.toDataURL().replace("image/png", "image/octet-stream"); // 获取生成的图片的url  
            var box = document.querySelector(".container");
            download(imgUri, 'my-node666.jpg');
        })
    }
</script>

当心跨域问题,让图片链接不跨域或者将url替换为base64

@Test
    public void url2base64() {
        String html = FileUtil.readUtf8String("D:\\example\\refactor\\test.html");
        Pattern pattern = Pattern.compile("https?://.*\\.(png|jpe?g)", Pattern.MULTILINE);
        List<String> all = ReUtil.findAll(pattern, html, 0);
        Set<String> distinct = new HashSet<>(all);
        Map<String, String> map = distinct.parallelStream().collect(Collectors.toMap(s -> s, s -> imgToBase64Short(s)));
        for (Map.Entry<String, String> entry : map.entrySet()) {
            html = StrUtil.replace(html, entry.getKey(), entry.getValue());
        }
        FileUtil.writeUtf8String(html, "testB64.html");
    }

public static String imgToBase64Short(String path) {
        try {
            return ImgUtil.toBase64DataUri(ImgUtil.getImage(new URL(path)),"png");
        } catch (MalformedURLException e) {
            e.printStackTrace();
            return path;
        }
    }