本人喜欢用 Markdown 写东西,轻量而且方便。

但是有时候需要分享给别人看,直接给 .md 文件的话,很多人并不懂;而导出 .pdf 或者 .docx 的话,样式兼容性很不好,所以我通常选择导出 HTML 进行分享。

现有的 Markdown 导出 HTML 需要携带图片的解决方案一般是使用图床,但是这又多了一点成本,并且有时候还会面临没网的情况。

于是我决定写一个小工具来帮助我把图片转换为 HTML 支持的 data url,用 base64 编码的方式把图片嵌入到单个文件中,这样就达到了方便分享阅读的目的。

基于 Go 的 Markdown 导出 HTML 的图片转换工具 第5张插图

使用方法

将 Markdown 文件导出成 HTML,然后使用 convert 工具进行转换。

以我经常使用的 Typora 举例,在“文件→偏好设置→导出→HTML→运行自定义命令”填入convert.exe "${outputPath}" 就可以实现导出 HTML 时自动将图片内嵌到 HTML 文件中的效果。

这个工具支持本地图片和网络图片的转换。

源码

核心函数是对图片进行编码或解码

func nodeEncode(node *html.Node) {
    defer wg.Done()
    for i := 0; i < len(node.Attr); i++ {
        if node.Attr[i].Key == "src" {
            if node.Attr[i].Val == "" {
                break
            }
            uri, isLocal, isDataUrl := parseSrc(node.Attr[i].Val)
            if isDataUrl {
                break
            }
            rawImage := getImageData(uri, isLocal)
            base64Image := base64.StdEncoding.EncodeToString(rawImage)
            mtype := mimetype.Detect(rawImage)
            errorAssert(err)
            node.Attr[i].Val = "data:" + mtype.String() + ";base64," + base64Image
        }
    }
}

func nodeDecode(node *html.Node) {
    defer wg.Done()
    for i := 0; i < len(node.Attr); i++ {
        if node.Attr[i].Key == "src" && node.Attr[i].Val != "" {
            uri, _, isDataUrl := parseSrc(node.Attr[i].Val)
            if !isDataUrl {
                return
            }
            _, base64Image, isFound := strings.Cut(uri, ";base64,")
            if !isFound {
                return
            }

            binImage, err := base64.StdEncoding.DecodeString(base64Image)
            errorAssert(err)
            mtype := mimetype.Detect(binImage)
            imgpath := saveDecodeImage(node, binImage, mtype.Extension())
            relativePath, err := filepath.Rel(fileDir, imgpath)
            errorAssert(err)
            node.Attr[i].Val = relativePath
        }
    }
}

完整的源码和编译好的二进制文件(upx 压缩过)我放在了附件。

因为是第一次使用 go 语言,我也是边学边写,欢迎大家提出改进意见。