1. 程式人生 > 其它 >springboot使用xhtmlrenderer將html轉圖片 支援img標籤、css

springboot使用xhtmlrenderer將html轉圖片 支援img標籤、css

技術標籤:htmljavafreemarkerspring

springboot使用xhtmlrenderer將html轉圖片 支援img標籤、css

需要實現的需求

目前需要實現一個需求,通過填充現有模板來生成圖片。之前模板使用圖片,但修改起來不夠靈活,現在改用html。結合freemarker填充資料,然後使用xhtmlrenderer轉成圖片。但遇到img標籤不起作用的問題,查了很多部落格,受這篇啟發xhtmlrenderer 將html轉換成pdf,完美css,帶圖片

,這篇博主是轉pdf,我是轉為圖片,處理上大同小異,本質還是自定義了一個xhtmlrenderer的替換元素工廠解決問題。下面我們按部就班。

引入依賴

<!-- freemarker處理html模板 填充資料-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!-- xhtmlrenderer將html轉為圖片-->
<dependency> <groupId>org.xhtmlrenderer</groupId> <artifactId>core-renderer</artifactId> <version>R8</version> </dependency>

html模板放置位置和獲取方法

html模板我放在這裡
html模板存放位置
獲取放方法:

// 要獲取的檔名
String template = "doorPlate.html";

Configuration cfg = new
Configuration(Configuration.VERSION_2_3_30); cfg.setDirectoryForTemplateLoading( ResourceUtils.getFile("classpath:templates")); cfg.setDefaultEncoding("UTF-8"); cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); //得到模板 Template temp = cfg.getTemplate(template);

使用freemarker填充模板

HashMap<String, Object> data = new HashMap();
// data.put("key",value)
StringWriter stringWriter = new StringWriter();
// 填入資料
temp.process(data, stringWriter);
stringWriter.flush();
stringWriter.close();
//獲得html內容的字串
String htmlStr = stringWriter.toString();

將html字串轉為圖片

這裡通過自定義ReplacedElementFactory來支援ima標籤,注意:我這裡img標籤存放的是base64編碼圖片,而不是圖片地址。因為用base64圖片可以直接從標籤中讀取值,用地址的話需要手動去處理地址,獲取圖片,稍微麻煩一些。

// 看程式碼
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document document = builder.parse(new ByteArrayInputStream(html.getBytes()));
Java2DRenderer renderer = new Java2DRenderer(document, width, height);

// 重點在這裡,自定義工廠 處理img標籤
renderer.getSharedContext().setReplacedElementFactory(new Base64ImgReplacedElementFactory());
renderer.getSharedContext().getTextRenderer().setSmoothingThreshold(1);
BufferedImage image = renderer.getImage();
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
	// 可以輸出到流
    ImageIO.write(image, "png", outputStream);
    // 也可以直接儲存到檔案
    ImageIO.write(image, "png", new File("/home/gyc/Desktop/test.png"));
    return Base64.getEncoder().encodeToString(outputStream.toByteArray());
 } catch (Exception e) {
    throw new CustomException("桌牌圖片轉換失敗");
}

// 自定義元素工廠的程式碼
public class Base64ImgReplacedElementFactory implements ReplacedElementFactory {

        @SneakyThrows
        @Override
        public ReplacedElement createReplacedElement(LayoutContext layoutContext, BlockBox blockBox,UserAgentCallback userAgentCallback, int width, int height) {
            Element e = blockBox.getElement();
            if (e == null) {
                return null;
            }
            String nodeName = e.getNodeName();
            if ("img".equals(nodeName)) {
            // 這裡直接從標籤獲取base64圖片的值,如果是地址的話需要通過地址去獲取圖片
                String attribute = e.getAttribute("src");
                // 這裡的width和height就是標籤的css屬性
                return new ImageReplacedElement(buildImage(attribute, userAgentCallback), width, height);
            }
            return null;
        }

        /**
         * 將base64編碼解碼並生成影象
         *
         * @param srcAttr 屬性
         * @param uac     回撥
         * @return FSImage
         * @throws IOException         io異常
         * @throws BadElementException BadElementException
         */
        protected java.awt.Image buildImage(String srcAttr, UserAgentCallback uac) throws IOException{

            if (srcAttr.startsWith("data:image/")) {
                String b64encoded = srcAttr.substring(srcAttr.indexOf("base64,") + "base64,".length()
                );
                // 解碼
                byte[] decodedBytes = Base64.getDecoder().decode(b64encoded);
                ByteArrayInputStream bais = new ByteArrayInputStream(decodedBytes);
                return ImageIO.read(bais);
            }
            return null;
        }

        @Override
        public void reset() { }

        @Override
        public void remove(Element element) { }

        @Override
        public void setFormSubmissionListener(FormSubmissionListener formSubmissionListener) { }
    }

到這裡就結束了