用docxtemplater
库实现前端通过模板导出word,遇到需求,要插图片并转成word
并导出,在图片转换这块遇到了问题,网上查示例大多都跑不通,自己琢磨半天,总算搞明白了。
附上清晰完整示例,供参考。
如有不懂,私我询问!
首先需要一个word文件作为模板
必须是docx
文件!!!
{%}
代表图片 xgq
是变量
安装需要的包
npm install docxtemplater
npm install docxtemplater-image-module-free
npm install pizzip
npm install file-saver
npm install html2canvas # 如需截图的话 安装
import Docxtemplater from 'docxtemplater';
import { saveAs } from 'file-saver';
import PizZip from 'pizzip';
import ImageModule from 'docxtemplater-image-module-free';
import html2canvas from 'html2canvas';
import image from './20240522152640.jpg';
import docx from './test.docx';
插入本地图片并转换
const imageData = await fetch(image);
const imageArrayBuffer = await imageData.arrayBuffer();
const imgDataDict: Record<string, ArrayBuffer> = {
xgq: imageArrayBuffer,
};
const docxData = await fetch(docx);
const docxArrayBuffer = await docxData.arrayBuffer();
const zip = new PizZip(docxArrayBuffer);
const doc = new Docxtemplater(zip, {
paragraphLoop: true,
linebreaks: true,
modules: [
new ImageModule({
getImage: (value: string, key: string) => {
return imgDataDict[key];
},
getSize: (afterValue: ArrayBuffer, value: string, key: string) => {
return [400, 400];
},
}),
],
});
doc.render({
xgq: "xgq", // 这里得是字符串否则会报错
});
const blob = doc.getZip().generate({
type: "blob",
mimeType:
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
});
saveAs(blob, "download.docx");
插入base64图片并转换
const base64 =
"data:image/jpeg;base64,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";
const imageArrayBuffer = base64DataURLToArrayBuffer(base64);
const imgDataDict: Record<string, ArrayBuffer> = {
xgq: imageArrayBuffer,
};
const docxData = await fetch(docx);
const docxArrayBuffer = await docxData.arrayBuffer();
const zip = new PizZip(docxArrayBuffer);
const doc = new Docxtemplater(zip, {
paragraphLoop: true,
linebreaks: true,
modules: [
new ImageModule({
getImage: (value: string, key: string) => {
return imgDataDict[key];
},
getSize: (afterValue: ArrayBuffer, value: string, key: string) => {
return [400, 400];
},
}),
],
});
doc.render({
xgq: "xgq", // 这里得是字符串否则会报错
});
const blob = doc.getZip().generate({
type: "blob",
mimeType:
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
});
saveAs(blob, "download.docx");
const base64DataURLToArrayBuffer = (dataURL: string) => {
const base64Regex = /^data:image\/(png|jpg|jpeg|svg|svg\+xml);base64,/;
if (!base64Regex.test(dataURL)) {
return false;
}
const stringBase64 = dataURL.replace(base64Regex, "");
let binaryString;
if (typeof window !== "undefined") {
binaryString = window.atob(stringBase64);
} else {
binaryString = new Buffer(stringBase64, "base64").toString("binary");
}
const len = binaryString.length;
const bytes = new Uint8Array(len);
for (let i = 0; i < len; i++) {
const ascii = binaryString.charCodeAt(i);
bytes[i] = ascii;
}
return bytes.buffer;
};
截图某个网页区域并插入转换
<div id="test" style={{ border: "1px solid red", width: 300 }}>
<div>截图</div>
<button type="button">666</button>
<br />
<img src={image} />
</div>;
const dom: any = document.getElementById("test");
const canvas = await html2canvas(dom, {
useCORS: true,
scale: 5,
});
const imageDataURL = canvas.toDataURL("image/png");
const response = await fetch(imageDataURL);
const imageArrayBuffer = await response.arrayBuffer();
const imgDataDict: Record<string, ArrayBuffer> = {
xgq: imageArrayBuffer,
};
const docxData = await fetch(docx);
const docxArrayBuffer = await docxData.arrayBuffer();
const zip = new PizZip(docxArrayBuffer);
const doc = new Docxtemplater(zip, {
paragraphLoop: true,
linebreaks: true,
modules: [
new ImageModule({
getImage: (value: string, key: string) => {
return imgDataDict[key];
},
getSize: (afterValue: ArrayBuffer, value: string, key: string) => {
return [400, 400];
},
}),
],
});
doc.render({
xgq: "xgq", // 这里得是字符串否则会报错
});
const blob = doc.getZip().generate({
type: "blob",
mimeType:
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
});
saveAs(blob, "download.docx");