java无需第三方依赖服务端生成echarts图片

996 阅读1分钟

使用htmlunit读取带有echarts的页面,调用js生成svg,再调用batik库将svg转换成png图片

resources下准备一个echarts.html

<html>
<meta charset="UTF-8">
<meta http-equiv="content-type" content="text/html; charset=utf-8">

<head>
  <script src="jquery-3.6.0.min.js"></script>
  <script src="echarts.js"></script>
</head>

<body>
<!--准备一个DOM-->
<div id="echartsDemo" style="height:500px;width:1000px"></div>
</body>
<script>
  var echartsDemo= null;
  $(function () {
    // 基于准备好的dom,初始化echarts实例
    echartsDemo = echarts.init(document.getElementById('echartsDemo'), null, {
      renderer: 'svg',
      ssr: true,
      width: 400,
      height: 300
    });

  });
</script>

</html>

注意echarts的配置需要用,渲染模式为svg renderer: 'svg'

同目录下放 github.com/apache/echa… 和Jquery jquery.com/download/

Maven:

<dependencies>
    <dependency>
        <groupId>org.htmlunit</groupId>
        <artifactId>htmlunit</artifactId>
        <version>3.6.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.xmlgraphics</groupId>
        <artifactId>batik-transcoder</artifactId>
        <version>1.14</version>
    </dependency>
    <dependency>
        <groupId>org.apache.xmlgraphics</groupId>
        <artifactId>batik-swing</artifactId>
        <version>1.14</version>
    </dependency>
    <dependency>
        <groupId>org.apache.xmlgraphics</groupId>
        <artifactId>batik-codec</artifactId>
        <version>1.14</version>
    </dependency>
    <dependency>
        <groupId>org.apache.xmlgraphics</groupId>
        <artifactId>xmlgraphics-commons</artifactId>
        <version>2.6</version>
    </dependency>
</dependencies>

代码:

package org.example;

import org.apache.batik.anim.dom.SAXSVGDocumentFactory;
import org.apache.batik.swing.JSVGCanvas;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.apache.batik.util.XMLResourceDescriptor;
import org.htmlunit.WebClient;
import org.htmlunit.html.HtmlPage;
import org.w3c.dom.Document;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.nio.charset.StandardCharsets;

public class Main {
    public static Document parseSVGFromString(String svgString) {
        try {
            String parser = XMLResourceDescriptor.getXMLParserClassName();
            SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory(parser);
            return factory.createDocument(null, new ByteArrayInputStream(svgString.getBytes("UTF-8")));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String getSVGText(String options, int width, int height) {
        try (final WebClient webClient = new WebClient()) {
            ClassLoader classLoader = Main.class.getClassLoader();
            URL resourceUrl = classLoader.getResource("echarts.html");
            URI resourceUri = resourceUrl.toURI();
            final HtmlPage page = webClient.getPage(resourceUri.toURL());
            // 设置图像大小
            page.executeJavaScript("echartsDemo.resize({width:" + width + ",height:" + height + "})");

            page.executeJavaScript("echartsDemo.setOption( " + options + ")");

            return page.executeJavaScript("echartsDemo.renderToSVGString()").getJavaScriptResult().toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void svgToPng(String svgText) {
        try {
            // 创建JSVGCanvas并渲染SVG
            JSVGCanvas canvas = new JSVGCanvas();
            canvas.setDocument(parseSVGFromString(svgText));

            // 创建PNGTranscoder以将SVG转换为PNG
            PNGTranscoder transcoder = new PNGTranscoder();
            TranscoderInput input =
                new TranscoderInput(new ByteArrayInputStream(svgText.getBytes(StandardCharsets.UTF_8)));

            // 设置PNG输出参数
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            TranscoderOutput output = new TranscoderOutput(outputStream);

            // 执行转码并保存图像
            transcoder.transcode(input, output);
            // 可以直接使用byte
            byte[] pngImageData = outputStream.toByteArray();

            // 也可以将图像数据的字节数组输出到文件
            try (FileOutputStream fos = new FileOutputStream("output_image.png")) {
                fos.write(pngImageData);
                System.out.println("PNG 图像数据已成功写入到文件 output_image.png");
            } catch (IOException e) {
                System.err.println("写入文件时出现异常: " + e.getMessage());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        String options =
            "{\n" + "  xAxis: {\n" + "    type: 'category',\n" + "    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']\n" + "  },\n" + "  yAxis: {\n" + "    type: 'value'\n" + "  },\n" + "  series: [\n" + "    {\n" + "      data: [120, 200, 150, 80, 70, 110, 130],\n" + "      type: 'bar',\n" + "      showBackground: true,\n" + "      backgroundStyle: {\n" + "        color: 'rgba(180, 180, 180, 0.2)'\n" + "      }\n" + "    }\n" + "  ]\n" + "}";

        String svgText = getSVGText(options, 500, 500);
        svgToPng(svgText);
    }
}

生成效果

output_image.png

options配置同官方样例:echarts.apache.org/examples/zh…