沧州市网站建设_网站建设公司_腾讯云_seo优化
2026/1/5 18:48:45 网站建设 项目流程

《苏州程序员の暑假奇遇记:Word图片转存大作战》
日期:2023年7月15日 星期五 苏州 暴雨转晴(适合宅家敲代码)

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

“客户爸爸说,他们每天要从Word里抠100+张图片存到服务器,手动右键另存为+FTP上传,手指都快磨出老茧了!”
我叼着冰棍瘫在电竞椅上,看着屏幕里客户发来的“血泪控诉”,突然觉得自己的暑假不该只用来肝《原神》。
“这需求,不就是‘Word图片一键转存+自动上传服务器’吗?简单!”(Flag立得飞起)


第二章:组件狩猎——在GitHub的海洋里“捞针”

打开GitHub,输入关键词“word image extract”,结果如下:

  1. mammoth.js:能转Word为HTML,但图片是base64编码的,上传得自己处理(“这不就是让我手动搓轮子吗?”)
  2. docx-preview:能预览Word,但图片提取?“抱歉,本库只负责看,不负责摸。”
  3. officegen:生成Word的神器,但反向操作?“反向抽烟?不会!”

绝望之际,突然想到——
“既然Word能转HTML,那图片肯定是``标签啊!直接抓src里的base64,转Blob上传不就行了?”
(拍桌)“我真是个天才!现在只需要找个能解析Word的库!”


第三章:前端攻坚——Vue2 + wangEditor5的“梦幻联动”

Step 1:让wangEditor5支持Word粘贴

wangEditor5默认不支持直接粘贴Word内容,但官方文档说可以“自定义扩展”。
代码片段

// src/utils/editorConfig.jsimport{Editor}from'wangeditor5'import{Boot}from'@wangeditor5/core'// 自定义粘贴过滤器Boot.registerModule({name:'pasteFilter',editor:Editor,config:(editor)=>{editor.on('paste',(data)=>{if(data.type==='text/html'){consthtml=data.data// 简单处理:提取所有标签(实际需更复杂的DOM解析)constimgTags=html.match(/]+src="([^">]+)"/g)||[]console.log('提取到的图片:',imgTags)}})}})

测试结果

  • 复制Word图片→粘贴到编辑器→控制台输出``标签,但srcdata:image/png;base64,...(成功一半!)
Step 2:Base64转Blob并上传

代码片段

// src/utils/imageUploader.jsexportasyncfunctionuploadWordImages(base64List){constformData=newFormData()base64List.forEach((base64,index)=>{// Base64转Blobconstblob=dataURLtoBlob(base64)formData.append(`images[]`,blob,`word_image_${index}.png`)})// 调用阿里云OSS直传(后端签名的URL)constresponse=awaitfetch('https://your-server.com/api/upload-sign',{method:'POST',body:formData})returnresponse.json()}functiondataURLtoBlob(dataurl){constarr=dataurl.split(',')constmime=arr[0].match(/:(.*?);/)[1]constbstr=atob(arr[1])letn=bstr.lengthconstu8arr=newUint8Array(n)while(n--){u8arr[n]=bstr.charCodeAt(n)}returnnewBlob([u8arr],{type:mime})}

测试结果

  • 图片成功上传到阿里云OSS,但文件名是乱码(“一定是客户爸爸的Word里藏了外星文字!”)

第四章:后端收尾——PHP的“优雅”处理

Step 1:生成阿里云OSS上传签名

代码片段

// api/upload-sign.phpdate('Y-m-d\TH:i:s\Z',time()+3600),'conditions'=>[['bucket'=>$bucket],['starts-with','$key','word-images/']// 限定上传目录]];$base64Policy=base64_encode(json_encode($policy));$signature=base64_encode(hash_hmac('sha1',$base64Policy,$accessKeySecret,true));echojson_encode(['accessId'=>$accessKeyId,'policy'=>$base64Policy,'signature'=>$signature,'host'=>"https://{$bucket}.{$endpoint}",'expire'=>time()+3600]);}catch(OssException$e){http_response_code(500);echojson_encode(['error'=>$e->getMessage()]);}?>

测试结果

  • 前端拿到签名后,直接通过OSS的POST Policy上传,PHP后端只需“躺平”接收结果(“PHP果然是世界上最好的语言!”)

第五章:群友助力——QQ群里的“神仙打架”

在QQ群223813913里喊了一嗓子:
“求救!Word图片转存,前端怎么提取所有图片?”
瞬间炸出一堆大佬:

  1. @上海-张工
    “别用正则匹配HTML!用DOMParser解析更靠谱!”
    constparser=newDOMParser()constdoc=parser.parseFromString(html,'text/html')constimages=Array.from(doc.querySelectorAll('img'))
  2. @深圳-李姐
    “阿里云OSS直传可以配置回调,上传成功后自动通知你的后端!”
  3. @杭州-小学生(实际是阿里云架构师)
    “建议用docx.js直接解析Word文件,比转HTML更精准!”

最终方案

  • 前端:wangEditor5+DOMParser提取图片
  • 后端:PHP生成OSS签名 + 回调处理

第六章:大功告成——客户爸爸的“真香”现场

测试视频发给客户后,回复如下:
“这速度!这体验!比我们手动操作快10倍!明天请你喝星巴克!”
(内心OS:“星巴克?不如折现给我买机械键盘!”


今日总结

  1. 技术栈:Vue2 + wangEditor5 + PHP + 阿里云OSS
  2. 关键点
    • Word转HTML后提取图片
    • Base64转Blob上传
    • OSS直传减少服务器压力
  3. 群友价值“一个人可以走得快,但一群人可以走得远(还能一起摸鱼)!”

明日计划

  • 优化图片压缩(前端用browser-image-compression
  • 写一篇技术博客《从Word到OSS:暑假程序员の自救指南》

(签名)
苏州·秃头但快乐的程序员
2023年7月15日

P.S.:如果你们也想加入“Word图片转存”豪华套餐,欢迎来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转换成图片上传到服务器中。

上传网络图片

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

下载示例

点击下载完整示例

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询