解决wangEditor从word复制粘贴图片,带有页眉页脚的问题

发布时间 2023-09-16 16:09:14作者: Xproer-松鼠

话不多说,直接贴代码。

rtf数据能提取到页眉页脚图片的原因:

提取 Word 文档中包含的所有图像数据,包括页眉和页脚中的图像数据。这是因为 RTF(Rich Text Format)是一种标记语言,可以在其中嵌入文本、图像和其他媒体类型的数据。在 Word 中,页眉和页脚的内容也可以通过 RTF 格式进行描述和呈现。

//改写wangEditor的粘贴
editorConfig.customPaste = (editor, event) => {

// 获取粘贴的html部分(??没错粘贴word时候,一部分内容就是html),该部分包含了图片img标签
let html = event.clipboardData.getData('text/html');

// 获取rtf数据(从word、wps复制粘贴时有),复制粘贴过程中图片的数据就保存在rtf中
const rtf = event.clipboardData.getData('text/rtf');

if (html && rtf) { // 该条件分支即表示要自定义word粘贴

// 列表缩进会超出边框,直接过滤掉
html = html.replace(/text\-indent:\-(.*?)pt/gi, '')

// 从html内容中查找粘贴内容中是否有图片元素,并返回img标签的属性src值的集合
const imgSrcs = findAllImgSrcsFromHtml(html);

// 如果有
if (imgSrcs && Array.isArray(imgSrcs) && imgSrcs.length) {

// 从rtf内容中查找图片数据
const rtfImageData = extractImageDataFromRtf(rtf);
debugger
// 如果找到
if (rtfImageData.length) {

// TODO:此处可以将图片上传到自己的服务器上

// 执行替换:将html内容中的img标签的src替换成ref中的图片数据,如果上面上传了则为图片路径
html = replaceImagesFileSourceWithInlineRepresentation(html, imgSrcs, rtfImageData)
editor.dangerouslyInsertHtml(html);

}
}

// 阻止默认的粘贴行为
event.preventDefault();
return false;
} else {
return true;
}
}

//从html中获取img的src集合
const findAllImgSrcsFromHtml = (htmlData) => {

let imgReg = /<img.*?(?:>|\/>)/gi; //匹配图片中的img标签
let srcReg = /src=[\'\"]?([^\'\"]*)[\'\"]?/i; // 匹配图片中的src

let arr = htmlData.match(imgReg); //筛选出所有的img
if (!arr || (Array.isArray(arr) && !arr.length)) {
return false;
}

let srcArr = [];
for (let i = 0; i < arr.length; i++) {
let src = arr[i].match(srcReg);
// 获取图片地址
srcArr.push(src[1]);
}

return srcArr;
}

//从rtf中获取所有的图片数据
const extractImageDataFromRtf = (rtfData, ignoreHeadersFooters = true) => {
if (!rtfData) {
return [];
}

const regexPictureHeader = /{\\pict[\s\S]+?({\\\*\\blipuid\s?[\da-fA-F]+)[\s}]*/
const regexPicture = new RegExp('(?:(' + regexPictureHeader.source + '))([\\da-fA-F\\s]+)\\}', 'g');
const images = rtfData.match(regexPicture);
const result = [];

if (images) {
for (const image of images) {
let imageType = false;

if (image.includes('\\pngblip')) {
imageType = 'image/png';
} else if (image.includes('\\jpegblip')) {
imageType = 'image/jpeg';
}

if (imageType) {
//是否跳过页眉页脚
if (ignoreHeadersFooters) {
const headerFooterRegex = /{\\header[\s\S]+?}\\par|{\\footer[\s\S]+?}\\par/g;
if (headerFooterRegex.test(image)) {
continue;
}
}
result.push({
hex: image.replace(regexPictureHeader, '').replace(/[^\da-fA-F]/g, ''),
type: imageType
});
}
}
}

return result;
}

//将html内容中img标签的属性值替换
const replaceImagesFileSourceWithInlineRepresentation = (htmlData, imageSrcs, imagesHexSources, isBase64Data =
true) => {
if (imageSrcs.length === imagesHexSources.length) {
for (let i = 0; i < imageSrcs.length; i++) {
const newSrc = isBase64Data ?
`data:${imagesHexSources[i].type};base64,${_convertHexToBase64(imagesHexSources[i].hex)}` :
imagesHexSources[i];

htmlData = htmlData.replace(imageSrcs[i], newSrc);
}
}

return htmlData;
}

//十六进制转base64
const _convertHexToBase64 = (hexString) => {
return btoa(hexString.match(/\w{2}/g).map(char => {
return String.fromCharCode(parseInt(char, 16));
}).join(''));
}



// 及时销毁 editor ,重要!
useEffect(() => {
return () => {
if (editor == null) return
editor.destroy()
setEditor(null)
}
}, [editor])

 

参考文章:http://blog.ncmem.com/wordpress/2023/09/16/%e8%a7%a3%e5%86%b3wangeditor%e4%bb%8eword%e5%a4%8d%e5%88%b6%e7%b2%98%e8%b4%b4%e5%9b%be%e7%89%87%ef%bc%8c%e5%b8%a6%e6%9c%89%e9%a1%b5%e7%9c%89%e9%a1%b5%e8%84%9a%e7%9a%84%e9%97%ae%e9%a2%98/

欢迎入群一起讨论