springboot使用xhtmlrenderer將html轉圖片 支援img標籤、css
阿新 • • 發佈:2020-12-19
springboot使用xhtmlrenderer將html轉圖片 支援img標籤、css
需要實現的需求
目前需要實現一個需求,通過填充現有模板來生成圖片。之前模板使用圖片,但修改起來不夠靈活,現在改用html。結合freemarker填充資料,然後使用xhtmlrenderer轉成圖片。但遇到img標籤不起作用的問題,查了很多部落格,受這篇啟發xhtmlrenderer 將html轉換成pdf,完美css,帶圖片
引入依賴
<!-- 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模板我放在這裡
獲取放方法:
// 要獲取的檔名
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) { }
}