首页 > 编程语言 >[java] html转图片方案

[java] html转图片方案

时间:2022-10-24 10:58:47浏览次数:79  
标签:java String html fileName HTML new pngFileName 图片

纯java项目后端进行HTML转图片

公司有个需求是在小程序将订单信息按一定样式整理后转成图片。客户点击按钮下载后可以将图片保存,并可以直接在微信群里分享。

由于时间紧迫的关系,这里前后端并行尝试方案,前端通过canvas方案手动绘制,后端则由我这边进行摸索。

 

原本想把各种尝试过的方案都记录下来,但是完成后现在一查,原来已经有人尝试过了,这里就直接他的上图。

图片来自https://blog.csdn.net/xuechangchun007/article/details/120936431

 

图中说明过的html2img及cssbox都尝试过,但是样式或多或少都有问题,因为这些存Java实现的基本都是通过g2d模拟绘制来生成图片,其样式和直接在浏览器上看到的肯定会存在差异。

另外我还尝试过github上的开源项目openhtmltopdf,结果都差不多。

需要没有差异的话,就必须使用类似selenium这种无头浏览器,模拟用户查看网站并截图的方案。

 

基于wkhtmltox

虽然我最先考虑过的是selenium,但是由同事推荐,最终我选择了基于wkhtmltox这个方案,这里记录下。

wkhtmltopdf核心点是使用webkit浏览器进行,基本上也是模拟用户在浏览器查看图片并截图保存的方案。

  • window按照只需要https://wkhtmltopdf.org/downloads.html下载对应的window包

然后使用命令调用即可,如下载在D:/1/,那么进入到D:/1/wkhtmltox/bin/目录,打开命令行执行

// 格式
// wkhtmltoimage程序地址 来源地址 保存地址
.\wkhtmltoimage.exe http://baidu.com 1.png

即可将将百度截图为图片保存到当前目录:

 

 

 

 对于一个html文件也是一样,若将Html文件移入到bin目录,那么

.\wkhtmltoimage.exe 1.html 1.png
  • 部署到linux需要根据服务器的系统版本下载对应的包并在服务器上安装即可

 方法可参考https://www.cnblogs.com/agang-php/p/14966285.html

 

编码部分

根据需求,我的方案是

  • 创建对应样式的html模板
  • 通过freemarker填充参数,获取html字符串。
  • 保存字符串为html文件到临时文件目录
  • 调用wkhtmltoimage生成图片到本地临时目录
  • 读取图片为byte数组
  • 删除临时文件

 

其中html字符串转图片部分代码可以参考如下

import java.io.File;
import java.io.FileWriter;
import java.nio.file.Files;

import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import lombok.extern.slf4j.Slf4j;

/**
 * HTML转图片的默认实现,采用wkhtmltox实现
 * <p>
 * wkhtmltox基于webkit浏览器将HTML转为图片,需要一个程序来执行,对于window来说是一个无需安装的exe
 * 对于linux来说需要进行安装
 * 
 */
@Slf4j
@Service
public class Html2ImageBizImpl implements Html2ImageBiz {

    /**
     * wkhtmltox的使用命令,对window来讲是exe的地址,对于linux是安装的命令地址(如/usr/local/bin/wkhtmltoimg)
     */
    private String wkcmd;
    /**
     * 用于存放临时文件的文件夹,由于wkhtmltox为系统插件独立进程,只能作为文件操作后再按流进行读取
     */
    private String tmpFilePath;

    @Override
    public byte[] stringToPng(String htmlString) {
        if (EmptyUtil.isEmpty(wkcmd)) {
            throw new UnsupportedOperationException("未配置wkhtmltox的使用命令参数,功能不可用");
        }
        if (EmptyUtil.isEmpty(tmpFilePath)) {
            throw new UnsupportedOperationException("未配置HTML转图片的临时文件目录,功能不可用");
        }
        Assert.hasLength(htmlString, "参数错误,HTML文件没有内容");

        String htmlFileName = null;
        String pngFileName = null;
        try {
            // 存HTML文件
            htmlFileName = saveHtml2File(htmlString);
            // 转为PNG,获取其文件名
            pngFileName = html2Png(htmlFileName);
            // 将PNG读取为bytes
            return readFile2ByteArray(pngFileName);

        } finally {
            // 删除临时文件
            if (htmlFileName != null) {
                removeTmpFile(htmlFileName);
            }
            if (pngFileName != null) {
                removeTmpFile(pngFileName);
            }
        }
    }

    /**
     * 将HTML内容写入文件
     * 
     * @param htmlString HTML文件内容
     */
    private String saveHtml2File(String htmlString) {
        String fileName = getRandomFileName(".html");
        try (FileWriter fileWriter = new FileWriter(new File(fileName))) {
            fileWriter.write(htmlString);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        log.info("保存HTML成功: {}", fileName);
        return fileName;
    }

    /**
     * 使用wkhtmltox将HTML转为PNG(都在硬盘上操作
     * 
     * @param htmlFileName HTML文件路径
     */
    private String html2Png(String htmlFileName) {
        String pngFileName = getRandomFileName(".png");

        StringBuilder cmd = new StringBuilder();
        cmd.append(wkcmd);
        cmd.append(" ");
        cmd.append(htmlFileName);
        cmd.append(" ");
        cmd.append(pngFileName);
        try {
            Process proc = Runtime.getRuntime().exec(cmd.toString());
            proc.getInputStream();
            proc.waitFor();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        log.info("转PNG成功: {}, {}", htmlFileName, pngFileName);
        return pngFileName;
    }

    /**
     * 读取文件二进制数组
     * 
     * @param fileName
     */
    private byte[] readFile2ByteArray(String fileName) {
        File file = new File(fileName);
        try {
            return Files.readAllBytes(file.toPath());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 删除临时文件
     * 
     * @param fileName 文件名
     */
    private void removeTmpFile(String fileName) {
        Assert.hasLength(fileName, "临时文件参数为空");
        File file = new File(fileName);
        if (file.isDirectory()) {
            throw new IllegalArgumentException("不能删除文件夹");
        }
        try {
            Files.delete(file.toPath());
            log.info("删除临时文件成功:{}", fileName);
        } catch (Exception e) {
            log.warn("删除临时文件失败", e);
        }
    }

    /**
     * 构建随机的文件地址(采用IdGenerator)
     * 
     * @param suffix 如.html
     */
    private String getRandomFileName(String suffix) {
        return tmpFilePath + "/" + "h2p" + IdGenerator.nextId() + suffix;
    }
}

这里的wkcmd和tmpFilePath是两个通过可配置的参数,如通过spring的@Value注入或者直接写死。

另外由于部分代码类如IdGenerator,用到了公司项目的包,这里删去引用。直接保存的话,需要替换为近似的方法。


 

END;

 

标签:java,String,html,fileName,HTML,new,pngFileName,图片
From: https://www.cnblogs.com/syui-terra/p/16820743.html

相关文章

  • Java方法
    Java方法方法的定义方法包括一个方法头和一个方法体,修饰符返回值类型方法名(参数类型参数名){...方法体...return返回值;}值传递和引用传递值传......
  • .Net对接Java接口加密不通过?
    前言  相信又不少小伙伴在对接第三方接口时遇到过这种情况:参数、排序、加密方式都按照接口文档进行处理了,可就是签名不通过,然后开始怀疑是不是参数漏了?参与加密的参数不......
  • JavaScript语法注释&数据类型和JavaScript语法变量
    JavaScript语法注释&数据类型注释:1.单行注释://注释内容2.多行注释:/*注释内容*/数据类型:1.原始数据类型(基本数据类型)1.number:数字。整数/小数/NaN(not......
  • HTML标签中文本标签和练习
    HTML标签-文本标签<b>:文本加粗<!--b文本加粗--><b>1、段落标签段落标签段落标签段落标签段落标签段落</b>运行结果: <i>:文本斜体<!--i文本斜体--><i......
  • 608 Javascript_语法_—元运算符 and 609 Javascript_语法_算数&比较运算符
    Javascript_语法_—元运算符一元运算符:只有一个运算数的运算符       ++,--,+(正号),-(符号)       ++(--),自增,自减           ++(--)先自增或......
  • 通过网络URL地址下载图片到本地文件夹
    说明:功能:某平台通过识别算法技术把工程机械进行识别(如:挖掘机、塔吊、安全帽、吊车等),然后通过地址下载原图和识别后的图片分别放在本地文件夹(yuantu和shibiehou文件夹);代码......
  • 【XML】Java创建XML文档
    packageexample01;importorg.w3c.dom.Document;importorg.w3c.dom.Element;importjavax.xml.parsers.DocumentBuilder;importjavax.xml.parsers.DocumentBuilde......
  • 面试HTML CSS基础
    01.如何将下面的代码修改的更有语义化?<div><div>这是一个标题</div><div>这是一段文字</div><div><div>列表1</div><div>列表2</div></div></div......
  • JavaScript发展史和JavaScript语法与html结合方式
    JavaScript发展史JavaScript发展史:1.1992年,Nombase公司,开发出第一门客户端脚本语言,专门用于表单的校验。命名为:C--,后来更名为:ScriptEase2.1995年,Netscape(网景)......
  • JavaScript简介
    JavaScript简介概念:一门客户端脚本语言运行在客户端浏览器中的。每一个浏览器都有javascript的解析引擎脚本语言:不需要编译,直接就可以被浏览器解析执行了功能:......