首页 前端知识 【前端 wasm】go语言实现一款docx转换为html的插件,给前端调用

【前端 wasm】go语言实现一款docx转换为html的插件,给前端调用

2024-07-20 17:07:13 前端知识 前端哥 611 714 我要收藏

文章目录

    • 背景
    • 仓库介绍
      • 获取代码
      • 本地体验
    • 项目效果展示
      • 本地test.docx
      • 线上解析效果
    • 线上体验
      • codesandbox
      • 在inscode中体验(1.1.0版本正在审核)
    • go代码主逻辑展示
    • html使用wasm展示
    • 开发进度
    • 最终吐槽

背景

之前的一个项目, 涉及到前端解析docx文件流为html来做编辑,但是,说实话,前端常用的mammoth库除了文字和图片能提取, 很多样式都会丢,效果看着非常不理想。

最终docx相关功能:通过转pdf进行预览,然后编辑直接不做。

于是,兴趣使然,我尝试使用go语言读取docx文件,使用encoding/xml模块解析docx中的文字和图片,最终输出为html。

仓库介绍

我将此库命名为 docx-to-html-wasm ,当然,只支持简单的段落文字、表格文字以及图片解析。

获取代码

  • npm仓库地址:https://www.npmjs.com/package/docx-to-html-wasm?activeTab=code
  • 执行npm view docx-to-html-wasm@1.1.0 dist.tarball可获取

本地体验

## 新建目录 test ,进入
yarn add docx-to-html-wasm@latest
serve -s node_modules/docx-to-html-wasm
## 访问浏览器 127.0.0.1:3000

因为wasm文件的加载是通过fetch请求,所以你需要通过serve启动一个简单的静态网站服务,然后访问127.0.0.1:3000. 如图中的红框所示
在这里插入图片描述

项目效果展示

本地test.docx

在这里插入图片描述

线上解析效果

在这里插入图片描述

线上体验

codesandbox

codesandbox访问

在inscode中体验(1.1.0版本正在审核)

go代码主逻辑展示

go代码写的太烂,只展示main函数。转化逻辑让chatgpt帮你写就行。

  • !wasm时,读取docx并转换为html到本地进行预览。
  • wasm时,接收前端input传来的文件流(base64编码二进制流,防止文件损坏),解析为html并返回。
//go:build !wasm
// +build !wasm

package main

import (
	"encoding/base64"
	"fmt"
	"go-wasm/src/parse"
	"go-wasm/src/utils"
	"io/ioutil"
)

func main() {
	// 读取docx文件的内容
	content, err := ioutil.ReadFile("example.docx")
	if err != nil {
		fmt.Println("Error reading docx file:", err)
		return
	}

	// 将内容转换为UTF-8编码
	utf8Content := string(content)

	// 将UTF-8编码的内容进行base64编码
	base64Content := base64.StdEncoding.EncodeToString([]byte(utf8Content))
	// fmt.Print(base64Content)
	// 解码
	zipReader := utils.ConvertBase64ToZipReader(base64Content)
	html, _ := parse.DocxToHTML(zipReader)
	// fmt.Print(html)
	ioutil.WriteFile("dist/index.html", []byte(html), 0777)
}

//go:build wasm
// +build wasm

package main

import (
	"go-wasm/src/parse"
	"go-wasm/src/utils"
	"syscall/js"
)

// wasm构建使用以下函数
func DocxToHtml(this js.Value, inputs []js.Value) interface{} {
	base64Content := inputs[0].String()
	zipReader := utils.ConvertBase64ToZipReader(base64Content)
	html, _ := parse.DocxToHTML(zipReader)
	return js.ValueOf(html)
}

func registerCallbacks() {
	js.Global().Set("DocxToHtml", js.FuncOf(DocxToHtml))
}

func main() {
	c := make(chan struct{}, 0)
	registerCallbacks()
	<-c
}

html使用wasm展示

所有文件获取方式都在 本文的仓库介绍

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Docx to HTML</title>
</head>
<style>
    #html-output img {
        width: 100%;
    }
</style>
<body>
    <div style="display: flex;width: 100%;justify-content: space-around">
        <input type="file" id="fileInput" accept=".docx">
        <div style="width: 48%" id="html-output"></div>
    </div>
    <script src="wasm_exec.js"></script>
    <script>
        // 加载go-wasm模块
        const go = new Go();
        WebAssembly.instantiateStreaming(fetch('output.wasm'), go.importObject).then((result) => {
            const mod = result.module;
            const inst = result.instance;
            go.run(inst);
        });
        // 调用wasm,转化docx为html
        async function convertDocx(base64Data) {
            const DocxToHtml = globalThis.DocxToHtml;
            const htmlOutput = DocxToHtml(base64Data);
            document.getElementById('html-output').innerHTML = htmlOutput;
        }
        // 文件转base64
        async function convertFileToBase64(file) {
            var reader = new FileReader();
            reader.onloadend = function () {
                console.log('reader.result', reader.result)
                convertDocx(reader.result.split(',')[1])
            }
            file ? reader.readAsDataURL(file) : alert('请选择一个文件')
        }
        // 文件上传监听
        document.getElementById('fileInput').addEventListener('change', async function (event) {
            const files = event.target.files;
            convertFileToBase64(files[0])
        });
    </script>
</body>
</html>

开发进度

    • 支持文字解析:
    • 3种图片解析:
      1. 通过本地插入的图片;
      2. 通过直接粘贴作为base64嵌入的图片;
      3. 2的位置及层级会有变种。(我推测至少有4种图片需要解析,可能仅仅是标签位置和层级改变就得做一堆兼容)
    • 支持表格中的纯文字解析,因为encoding/xml通过静态映射xml标签,难以解决段落和表格的顺序问题,可以结合etree库来解析段落和表格的顺序。
    • 不支持横向布局。
    • 不支持页码分割。
    • 性能测试:(纯文字最快,图片越多越慢, g5400测试结果如下:)

      文件大小加载时间(秒)
      60M24s
      20M9s
      10M<4s

最终吐槽

这docx里的xml真复杂,希望有大佬整一个吧。

  • 光图片解析就得兼容至少4种情况,
  • 使用etree性能下降很多,20M的文件解析从4s上升到9秒,但是可以支持表格解析。
  • 甚至还有横向布局这种玩意儿。
  • 把xml布局转化为html+css布局可真是蛋疼。
  • docx文件没有保存页码信息,全靠渲染生成,这也是不同软件下样式有差异的原因。
  • docx在线预览的话建议让后端转pdf回来。 在线编辑的话建议买onlyoffice
转载请注明出处或者链接地址:https://www.qianduange.cn//article/14037.html
标签
golangwasm
评论
发布的文章

HTML5 移动开发秘籍(一)

2024-08-05 23:08:12

【HTML5系列教程】

2024-08-05 23:08:12

HTML5面试题

2024-08-05 23:08:06

JQuery基础---01

2024-08-05 23:08:34

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!