markdown java引擎_java 实现markdown 转 image

本文介绍了一种将Markdown转换为渲染后图片的方法,通过markdown转html再转为图片。主要利用了xhtmlrenderer库,并自定义了Html2ImageWrapper类进行配置和处理。最后展示了测试代码和实际应用的效果。
摘要由CSDN通过智能技术生成

markdown 转 image

前段时间实现了长图文生成的基本功能,然后想了下能否有个进阶版,直接将markdown生成渲染后的图片呢?

思路

有不少的库可以将 markdown 转为 html,那么这个需求就可以转为 html转Image了

1. markdown 转 html

2. html 转 图片

主要的核心问题就在这里了,如何实现html转图片?

直接实现html转图片的包没怎么见,看到一个 html2image, 还不太好用

在 AWT or Swing 的Panel上显示网页,在把Panel输出为 image 文件

使用js相关技术实现转换

本篇博文具体实现以 html2image 的实现逻辑作为参考,然后定制实现一把(后面有机会写一篇利用js来实现html转图片的博文)

html2image 的实现原理

html2image 基本上没啥维护了,内部主要是利用了 xhtmlrender 实现html渲染为图片

Graphics2DRenderer renderer = new Graphics2DRenderer();

// 设置渲染内容

renderer.setDocument(document, document.getDocumentURI());

// 获取Graphics2D

graphics2D = bufferedImage.createGraphics();

renderer.layout(graphics2D, dimension);

// 内容渲染

renderer.render(graphics2D);

说明

为什么并不直接使用 java-html2image ?

因为有些定制的场景支持得不太友好,加上源码也比较简单,所以干脆站在前人的基础上进行拓展

设计目标(这里指html转图片的功能)

生成图片的宽可指定

支持对线上网页进行转图片

支持对html中指定的区域进行转换

css样式渲染支持

实现

本篇先会先实现一个基本的功能,即读去markdown文档, 并转为一张图片

1. markdown 转 html 封装

利用之前封装的 MarkDown2HtmlWrapper 工具类

具体实现逻辑参考项目工程,和markdown转html博文

2. html 转 image

参数配置项 HtmlRenderOptions

注意

html 为 Document 属性

autoW, autoH 用于控制是否自适应html实际的长宽

@Data

public class HtmlRenderOptions {

/**

* 输出图片的宽

*/

private Integer w;

/**

* 输出图片的高

*/

private Integer h;

/**

* 是否自适应宽

*/

private boolean autoW;

/**

* 是否自适应高

*/

private boolean autoH;

/**

* 输出图片的格式

*/

private String outType;

/**

* html相关内容

*/

private Document document;

}

封装处理类

同样采用Builder模式来进行配置项设置

public class Html2ImageWrapper {

private static DOMParser domParser;

static {

domParser = new DOMParser(new HTMLConfiguration());

try {

domParser.setProperty("http://cyberneko.org/html/properties/names/elems", "lower");

} catch (Exception e) {

throw new RuntimeException("Can't create HtmlParserImpl", e);

}

}

private HtmlRenderOptions options;

private Html2ImageWrapper(HtmlRenderOptions options) {

this.options = options;

}

private static Document parseDocument(String content) throws Exception {

domParser.parse(new InputSource(new StringReader(content)));

return domParser.getDocument();

}

public static Builder of(String html) {

return new Builder().setHtml(html);

}

public static Builder ofMd(MarkdownEntity entity) {

return new Builder().setHtml(entity);

}

public BufferedImage asImage() {

BufferedImage bf = HtmlRender.parseImage(options);

return bf;

}

public boolean asFile(String absFileName) throws IOException {

File file = new File(absFileName);

FileUtil.mkDir(file);

BufferedImage bufferedImage = asImage();

if (!ImageIO.write(bufferedImage, options.getOutType(), file)) {

throw new IOException("save image error!");

}

return true;

}

public String asString() throws IOException {

BufferedImage img = asImage();

return Base64Util.encode(img, options.getOutType());

}

@Getter

public static class Builder {

/**

* 输出图片的宽

*/

private Integer w = 600;

/**

* 输出图片的高度

*/

private Integer h;

/**

* true,根据网页的实际宽渲染;

* false, 则根据指定的宽进行渲染

*/

private boolean autoW = true;

/**

* true,根据网页的实际高渲染;

* false, 则根据指定的高进行渲染

*/

private boolean autoH = false;

/**

* 输出图片的格式

*/

private String outType = "jpg";

/**

* 待转换的html内容

*/

private MarkdownEntity html;

public Builder setW(Integer w) {

this.w = w;

return this;

}

public Builder setH(Integer h) {

this.h = h;

return this;

}

public Builder setAutoW(boolean autoW) {

this.autoW = autoW;

return this;

}

public Builder setAutoH(boolean autoH) {

this.autoH = autoH;

return this;

}

public Builder setOutType(String outType) {

this.outType = outType;

return this;

}

public Builder setHtml(String html) {

this.html = new MarkdownEntity();

return this;

}

public Builder setHtml(MarkdownEntity html) {

this.html = html;

return this;

}

public Html2ImageWrapper build() throws Exception {

HtmlRenderOptions options = new HtmlRenderOptions();

options.setW(w);

options.setH(h);

options.setAutoW(autoW);

options.setAutoH(autoH);

options.setOutType(outType);

if (fontColor != null) {

html.addDivStyle("style", "color:" + options.getFontColor());

}

html.addDivStyle("style", "width:" + w + ";");

html.addWidthCss("img");

html.addWidthCss("code");

options.setDocument(parseDocument(html.toString()));

return new Html2ImageWrapper(options);

}

}

}

上面的实现,有个需要注意的地方

如何将html格式的字符串,转为 Document 对象

利用了开源工具 nekohtml, 可以较好的实现html标签解析,看一下DOMParse 的初始化过程

private static DOMParser domParser;

static {

domParser = new DOMParser(new HTMLConfiguration());

try {

domParser.setProperty("http://cyberneko.org/html/properties/names/elems",

"lower");

} catch (Exception e) {

throw new RuntimeException("Can't create HtmlParserImpl", e);

}

}

try语句块中的内容并不能缺少,否则最终的样式会错乱,关于 nekohtml 的使用说明,可以查阅相关教程

上面的封装,主要是HtmlRenderOptions的构建,主要的渲染逻辑则在下面

渲染

利用 xhtmlrenderer 实现html的渲染

宽高的自适应

图片的布局,内容渲染

public class HtmlRender {

/**

* 输出图片

*

* @param options

* @return

*/

public static BufferedImage parseImage(HtmlRenderOptions options) {

int width = options.getW();

int height = options.getH() == null ? 1024 : options.getH();

Graphics2DRenderer renderer = new Graphics2DRenderer();

renderer.setDocument(options.getDocument(), options.getDocument().getDocumentURI());

Dimension dimension = new Dimension(width, height);

BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

Graphics2D graphics2D = GraphicUtil.getG2d(bufferedImage);

// 自适应修改生成图片的宽高

if (options.isAutoH() || options.getH() == null) {

// do layout with temp buffer

renderer.layout(graphics2D, new Dimension(width, height));

graphics2D.dispose();

Rectangle size = renderer.getMinimumSize();

final int autoWidth = options.isAutoW() ? (int) size.getWidth() : width;

final int autoHeight = (int) size.getHeight();

bufferedImage = new BufferedImage(autoWidth, autoHeight, BufferedImage.TYPE_INT_RGB);

dimension = new Dimension(autoWidth, autoHeight);

graphics2D = GraphicUtil.getG2d(bufferedImage);

}

renderer.layout(graphics2D, dimension);

renderer.render(graphics2D);

graphics2D.dispose();

return bufferedImage;

}

}

测试

@Test

public void testParse() throws Exception {

String file = "md/tutorial.md";

MarkdownEntity html = MarkDown2HtmlWrapper.ofFile(file);

BufferedImage img = Html2ImageWrapper.ofMd(html)

.setW(600)

.setAutoW(false)

.setAutoH(true)

.setOutType("jpg")

.build()

.asImage();

ImageIO.write(img, "jpg", new File("/Users/yihui/Desktop/md.jpg"));

}

输出图片

f151ab0eff07?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

out.jpg

然后演示一个对项目中实际的教程文档输出图片的动态示意图, 因为生成的图片特别特别长,所以就不贴输出的图片了,有兴趣的同学可以下载工程,实际跑一下看看

源markdown文件地址:

f151ab0eff07?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

show.gif

其他

公众号获取更多:

3d36be394b668806c51f8eea55a55ad6.png

个人信息

参考博文

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值