news 2026/4/16 14:16:44

wangEditor复制word公式转MathType格式

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
wangEditor复制word公式转MathType格式

《长沙大二码农的暑假暴走开发记:Word图片转存功能の奇幻漂流》

Day1:需求诞生——从“懒癌晚期”到“技术狂魔”

“妈!我暑假要搞个大事!”
当我把“Word图片一键转存”的PPT甩在家庭群时,我妈回了个“?”,我爸回了句“6”。
其实动机很简单:作为学生会宣传部“专业P图师”(自封的),每次从Word里抠图都要经历:

  1. 右键另存为 → 弹出“此图片受保护”
  2. 截图 → 发现像素糊成马赛克
  3. 跪求原图 → 被设计师同学嘲讽“菜狗”

怒而拍桌“我要写个程序,让Word图片自动上传到服务器!”
(然后偷偷幻想:开学后能不能靠这个装逼接私活?)


Day2-3:组件狩猎——在GitHub的海洋里“捞鱼”

前端三件套

  • Vue2-cli:学校教过,勉强能用(反正复制粘贴代码不会错)
  • wangEditor:比CKEditor简单!但文档里“图片上传”部分写着“自行实现后端接口”……
    内心OS“所以爱会消失对吗?”
  • 免费解析库
    • mammoth.js:能提Word图片,但输出是Base64,上传会卡死浏览器(测试时直接让Chrome崩溃3次)
    • docx-preview:GitHub 1.8k星!但示例代码全是React的(作为Vue仔当场裂开)
    • pdf.js:处理PDF还行,但Word?“不,你不想”(强行适配后报错像放鞭炮)

最终妥协

  • 前端:用FileReader读Word文件 → 解析ZIP结构(毕竟docx本质是ZIP包)→ 手动捞word/media/下的图片
  • 后端:PHP接收图片流 → 存到阿里云OSS(参考了某位大佬的博客,代码抄得飞起)

QQ群交流
加入群223813913后,发现大佬们都在聊“K8s部署”“微服务”,而我:
“各位大佬,怎么用PHP把图片存到OSS啊?”
(群友:“建议重开”


Day4-7:开发实录——从“Hello World”到“Hello Bug”

Step1:前端搞事情

  • JSZip解压Word文件,结果发现:

    // 代码片段:捞图片的暴力写法constzip=newJSZip(file);constimages=[];zip.folder("word/media/").forEach((path,file)=>{if(/\.(png|jpg|jpeg)$/.test(path)){images.push(file.async("base64"));// 后来发现base64上传会炸}});

    Bug1word/media/可能不存在 → 加了个try-catch(优雅.jpg)
    Bug2:图片顺序乱套 → 改用Array.sort()按文件名排序(结果发现Word图片名是image1.pngimage10.png“微软你礼貌吗?”

  • 集成wangEditor上传:

    // 伪代码:把图片塞进编辑器consteditor=newwangEditor("#editor");editor.config.customUploadImg=async(files)=>{constformData=newFormData();formData.append("file",files[0]);// 实际要传所有图片…懒得改constres=awaitaxios.post("/upload",formData);editor.cmd.do("insertHTML",``);};

    Bug3:wangEditor的customUploadImg一次只能传一张图 → 改用Promise.all批量上传(手动狗头)

Step2:后端接盘

  • PHP接收图片流:
    // 极简版上传接口(实际有安全校验…大概)$file=$_FILES["file"];$oss=newOssClient($key,$secret,$endpoint);$oss->putObject("my-bucket",$file["name"],fopen($file["tmp_name"],"r"));echojson_encode(["url"=>"https://oss-cn-hangzhou.aliyuncs.com/my-bucket/".$file["name"]]);
    Bug4:文件名冲突 → 用uniqid()生成随机名(结果OSS里全是64a1b2c3d4e5f.png这种乱码)
    Bug5:MySQL存元数据时字段长度不够 → 把VARCHAR(255)改成TEXT“设计数据库时我在睡觉”

Step3:阿里云OSS配置

  • 创建Bucket → 设置跨域规则(CORS)→ 生成AccessKey(“千万别泄露!”
  • 测试时发现上传失败 → 查日志发现是**“签名错误”** → 原来是PHP SDK版本太旧…
    解决方案
    composerrequire aliyuncs/oss-sdk-php:^2.3# 升级到最新版

Day8-10:测试与部署——从“本地跑通”到“线上炸服”

本地测试

  • 用Word写了个测试文档,插了5张图(包括1张GIF动图)
  • 前端解析 → 上传 → 编辑器显示 →“成了!”(激动到打翻可乐)

部署到阿里云ECS

  • Nginx配置反向代理 → PHP-FPM跑后端 → MySQL存数据
  • 测试时发现:“上传大文件会超时!”
    解决方案
    • 修改php.ini
      upload_max_filesize = 50M post_max_size = 50M
    • Nginx加超时设置:
      client_max_body_size 50M; proxy_read_timeout 300s;

最终效果

  • 上传10MB的Word → 前端解析2秒 → 后端上传5秒 → 编辑器显示图片
  • “虽然慢,但至少能用了!”(老板感动到哭.jpg)

Day11:总结与装逼

技术栈回顾

  • 前端:Vue2 + wangEditor + JSZip
  • 后端:PHP + OSS SDK
  • 数据库:MySQL(存图片URL和元数据)
  • 服务器:阿里云ECS(学生机免费版)

群内装逼
“大佬们,我搞定了Word图片转存!虽然代码很烂…”
群友:“上GitHub!”
我:“算了,怕被喷…”(实际是懒)

未来计划

  1. 优化解析速度(用Web Worker)
  2. 支持Excel/PPT的图片提取(“先鸽着”
  3. 写个博客吹牛(“正在写…”

最后吐槽
“原来开发就是:‘抄代码 → 改Bug → 抄代码 → 改Bug’的无限循环…”
(但看到编辑器里显示的图片时,还是觉得…
“真香!”


(完)
P.S.:欢迎长沙的同行约饭交流!QQ群:223813913(群文件有源码,但**“慎用”**)

复制插件文件


安装jquery

npm install jquery

导入组件

importEfrom'wangeditor'const{$,BtnMenu,DropListMenu,PanelMenu,DropList,Panel,Tooltip}=Eimport{WordPaster}from'../../static/WordPaster/js/w'import{zyCapture}from'../../static/zyCapture/z'import{zyOffice}from'../../static/zyOffice/js/o'

初始化组件

//zyCapture ButtonclasszyCaptureBtnextendsBtnMenu{constructor(editor){const$elem=E.$(`<div class="w-e-menu">`)super($elem,editor)}clickHandler(){window.zyCapture.setEditor(this.editor).Capture();}tryChangeActive(){this.active()}}//zyOffice ButtonclassimportWordBtnextendsBtnMenu{constructor(editor){const$elem=E.$(`<div class="w-e-menu">`)super($elem,editor)}clickHandler(){window.zyOffice.SetEditor(this.editor).api.openDoc();}tryChangeActive(){this.active()}}//zyOffice ButtonclassexportWordBtnextendsBtnMenu{constructor(editor){const$elem=E.$(`<div class="w-e-menu">`)super($elem,editor)}clickHandler(){window.zyOffice.SetEditor(this.editor).api.exportWord();}tryChangeActive(){this.active()}}//zyOffice ButtonclassimportPdfBtnextendsBtnMenu{constructor(editor){const$elem=E.$(`<div class="w-e-menu">`)super($elem,editor)}clickHandler(){window.zyOffice.SetEditor(this.editor).api.openPdf();}tryChangeActive(){this.active()}}//WordPaster ButtonclassWordPasterBtnextendsBtnMenu{constructor(editor){const$elem=E.$(`<div class="w-e-menu">`)super($elem,editor)}clickHandler(){WordPaster.getInstance().SetEditor(this.editor).Paste();}tryChangeActive(){this.active()}}//wordImport ButtonclassWordImportBtnextendsBtnMenu{constructor(editor){const$elem=E.$(`<div class="w-e-menu">`)super($elem,editor)}clickHandler(){WordPaster.getInstance().SetEditor(this.editor).importWord();}tryChangeActive(){this.active()}}//excelImport ButtonclassExcelImportBtnextendsBtnMenu{constructor(editor){const$elem=E.$(`<div class="w-e-menu">`)super($elem,editor)}clickHandler(){WordPaster.getInstance().SetEditor(this.editor).importExcel();}tryChangeActive(){this.active()}}//ppt paster ButtonclassPPTImportBtnextendsBtnMenu{constructor(editor){const$elem=E.$(`<div class="w-e-menu">`)super($elem,editor)}clickHandler(){WordPaster.getInstance().SetEditor(this.editor).importPPT();}tryChangeActive(){this.active()}}//pdf paster ButtonclassPDFImportBtnextendsBtnMenu{constructor(editor){const$elem=E.$(`<div class="w-e-menu">`)super($elem,editor)}clickHandler(){WordPaster.getInstance().SetEditor(this.editor);WordPaster.getInstance().ImportPDF();}tryChangeActive(){this.active()}}//importWordToImg ButtonclassImportWordToImgBtnextendsBtnMenu{constructor(editor){const$elem=E.$(`<div class="w-e-menu">`)super($elem,editor)}clickHandler(){WordPaster.getInstance().SetEditor(this.editor).importWordToImg();}tryChangeActive(){this.active()}}//network paster ButtonclassNetImportBtnextendsBtnMenu{constructor(editor){const$elem=E.$(`<div class="w-e-menu">`)super($elem,editor)}clickHandler(){WordPaster.getInstance().SetEditor(this.editor);WordPaster.getInstance().UploadNetImg();}tryChangeActive(){this.active()}}exportdefault{name:'HelloWorld',data(){return{msg:'Welcome to Your Vue.js App'}},mounted(){vareditor=newE('#editor');WordPaster.getInstance({//上传接口:http://www.ncmem.com/doc/view.aspx?id=d88b60a2b0204af1ba62fa66288203edPostUrl:"http://localhost:8891/upload.aspx",License2:"",//为图片地址增加域名:http://www.ncmem.com/doc/view.aspx?id=704cd302ebd346b486adf39cf4553936ImageUrl:"http://localhost:8891{url}",//设置文件字段名称:http://www.ncmem.com/doc/view.aspx?id=c3ad06c2ae31454cb418ceb2b8da7c45FileFieldName:"file",//提取图片地址:http://www.ncmem.com/doc/view.aspx?id=07e3f323d22d4571ad213441ab8530d1ImageMatch:''});zyCapture.getInstance({config:{PostUrl:"http://localhost:8891/upload.aspx",License2:'',FileFieldName:"file",Fields:{uname:"test"},ImageUrl:'http://localhost:8891{url}'}})// zyoffice,// 使用前请在服务端部署zyoffice,// http://www.ncmem.com/doc/view.aspx?id=82170058de824b5c86e2e666e5be319czyOffice.getInstance({word:'http://localhost:13710/zyoffice/word/convert',wordExport:'http://localhost:13710/zyoffice/word/export',pdf:'http://localhost:13710/zyoffice/pdf/upload'})// 注册菜单E.registerMenu("zyCaptureBtn",zyCaptureBtn)E.registerMenu("WordPasterBtn",WordPasterBtn)E.registerMenu("ImportWordToImgBtn",ImportWordToImgBtn)E.registerMenu("NetImportBtn",NetImportBtn)E.registerMenu("WordImportBtn",WordImportBtn)E.registerMenu("ExcelImportBtn",ExcelImportBtn)E.registerMenu("PPTImportBtn",PPTImportBtn)E.registerMenu("PDFImportBtn",PDFImportBtn)E.registerMenu("importWordBtn",importWordBtn)E.registerMenu("exportWordBtn",exportWordBtn)E.registerMenu("importPdfBtn",importPdfBtn)//挂载粘贴事件editor.txt.eventHooks.pasteEvents.length=0;editor.txt.eventHooks.pasteEvents.push(function(){WordPaster.getInstance().SetEditor(editor).Paste();e.preventDefault();});editor.create();varedt2=newE('#editor2');//挂载粘贴事件edt2.txt.eventHooks.pasteEvents.length=0;edt2.txt.eventHooks.pasteEvents.push(function(){WordPaster.getInstance().SetEditor(edt2).Paste();e.preventDefault();return;});edt2.create();}}h1,h2{font-weight:normal;}ul{list-style-type:none;padding:0;}li{display:inline-block;margin:010px;}a{color:#42b983;}

测试前请配置图片上传接口并测试成功
接口测试
接口返回JSON格式参考

为编辑器添加按钮

components:{Editor,Toolbar},data(){return{editor:null,html:'dd',toolbarConfig:{insertKeys:{index:0,keys:['zycapture','wordpaster','pptimport','pdfimport','netimg','importword','exportword','importpdf']}},editorConfig:{placeholder:''},mode:'default'// or 'simple'}},

整合效果

导入Word文档,支持doc,docx

导入Excel文档,支持xls,xlsx

粘贴Word

一键粘贴Word内容,自动上传Word中的图片,保留文字样式。

Word转图片

一键导入Word文件,并将Word文件转换成图片上传到服务器中。

导入PDF

一键导入PDF文件,并将PDF转换成图片上传到服务器中。

导入PPT

一键导入PPT文件,并将PPT转换成图片上传到服务器中。

上传网络图片

一键自动上传网络图片,自动下载远程服务器图片,自动上传远程服务器图片

下载示例

点击下载完整示例

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 11:04:37

为什么你的交易系统不安全?PHP+区块链日志设计的4个致命盲区

第一章&#xff1a;PHP区块链交易系统的安全现状随着区块链技术在金融、供应链和数字资产等领域的广泛应用&#xff0c;基于 PHP 构建的区块链交易系统逐渐增多。尽管 PHP 以其开发效率高、生态成熟著称&#xff0c;但在处理高安全性要求的区块链交易场景时&#xff0c;仍面临诸…

作者头像 李华
网站建设 2026/4/16 11:16:02

LUT调色包下载后如何应用于HeyGem输出视频后期?

LUT调色包下载后如何应用于HeyGem输出视频后期&#xff1f; 在AI数字人内容批量生成的今天&#xff0c;一个常被忽视的问题浮出水面&#xff1a;为什么同样是用HeyGem生成的播报视频&#xff0c;有些看起来像专业影视作品&#xff0c;而另一些却显得“塑料感”十足、色彩平淡&a…

作者头像 李华
网站建设 2026/4/16 10:53:26

PHP图像识别结果解析实战(从入门到精通的完整指南)

第一章&#xff1a;PHP图像识别结果解析概述在现代Web应用开发中&#xff0c;图像识别技术逐渐成为提升用户体验和系统智能化水平的重要手段。PHP作为广泛使用的服务器端脚本语言&#xff0c;虽然本身不直接提供图像识别能力&#xff0c;但可通过集成第三方API或调用Python等语…

作者头像 李华
网站建设 2026/4/15 15:24:49

Java--Stream流详解,零基础入门到精通,收藏这篇就够了

目录 一、什么是反射&#xff1f; 二、反射的用途 三、获取Class对象 四、Class类型的对象使用场景1 五、Class类型的对象使用场景2 六、通过反射创建对象 七、使用 Java 反射机制获取和调用类的构造方法&#xff0c;访问私有构造方法并创建对象 八、通过反射&#xff…

作者头像 李华