import JSZipUtils from 'jszip-utils'; import docxtemplater from 'docxtemplater'; import ImageModule from 'docxtemplater-image-module-free'; import Pizzip from 'pizzip'; import FileSaver from 'file-saver'; /** * 将base64格式图片转换为ArrayBuffer * @param {string} base64Str - base64格式图片字符串(可包含data URL前缀) * @returns {ArrayBuffer} 转换后的ArrayBuffer对象 */ function base64ToArrayBuffer(base64Str) { // 移除data URL前缀(如果存在) const base64Content = base64Str.replace(/^data:image\/\w+;base64,/, ''); // 处理URL安全的base64字符 const safeBase64 = base64Content.replace(/-/g, '+').replace(/_/g, '/'); // 解码base64字符串 const binaryStr = atob(safeBase64); // 转换为Uint8Array const byteLength = binaryStr.length; const uint8Array = new Uint8Array(byteLength); for (let i = 0; i < byteLength; i++) { uint8Array[i] = binaryStr.charCodeAt(i); } // 返回ArrayBuffer return uint8Array.buffer; } /** * 等比例缩放图片 * 根据图片的长宽比进行不同方式的缩放 * 如果宽度大于高度(横拍图片),则按照设定高度等比缩放; * 如果宽度小于高度(竖拍图片),则按照设定宽度等比缩放; * @param {Number} horizontalHeight 设定高度 * @param {Number} verticalWidth 设定宽度 * @param {*} img * @param {*} tagValue * @param {*} tagName * @returns */ function getSizeProportional( horizontalHeight, verticalWidth, img, tagValue, tagName ) { return new Promise(function (resolve, reject) { const image = new Image(); image.src = tagValue; image.onload = function () { let width = image.width; let height = image.height; // console.log('width height', width, height); if (width > height && horizontalHeight && height > horizontalHeight) { const scale = image.height / horizontalHeight; height = horizontalHeight; width = image.width / scale; } else if (width <= height && verticalWidth && width > verticalWidth) { const scale = image.width / verticalWidth; width = verticalWidth; height = image.height / scale; } // console.log('scale', width, height); resolve([width, height]); }; image.onerror = function (e) { console.log('img, tagValue, tagName : ', img, tagValue, tagName); alert('An error occured while loading ' + tagValue); reject(e); }; }); } /** * 固定大小缩放图片 * 根据图片的长宽比进行不同方式的缩放 * 如果宽度大于高度(横拍图片),则按照设定高度和宽高比缩放; * 如果宽度小于高度(竖拍图片),则按照设定宽度和宽高比缩放; * @param {*} horizontalHeight 设定高度 * @param {*} verticalWidth 设定宽度 * @param {*} scale 缩放比例,长边除短边的比例系数 * @param {*} img * @param {*} tagValue * @param {*} tagName * @returns */ function getSizeFixed( horizontalHeight, verticalWidth, scale, img, tagValue, tagName ) { return new Promise(function (resolve, reject) { const image = new Image(); image.src = tagValue; image.onload = function () { let width = image.width; let height = image.height; if ( width > height && horizontalHeight && height > horizontalHeight && scale ) { height = horizontalHeight; width = horizontalHeight * scale; } else if ( width <= height && verticalWidth && width > verticalWidth && scale ) { width = verticalWidth; height = verticalWidth * scale; } resolve([width, height]); }; image.onerror = function (e) { console.log('img, tagValue, tagName : ', img, tagValue, tagName); alert('An error occured while loading ' + tagValue); reject(e); }; }); } /** * 获取图片配置信息 * @param {Number} horizontalHeight 图片宽度大于高度时,限制其高度 * @param {Number} verticalWidth 图片宽度小于高度时,限制其宽度 * @returns */ function getImageOptions(options) { const horizontalHeight = options ? options.horizontalHeight : undefined; const verticalWidth = options ? options.verticalWidth : undefined; return { centered: false, fileType: 'docx', getImage(tagValue) { // In this case tagValue will be a URL tagValue = "https://docxtemplater.com/puffin.png" return new Promise(function (resolve, reject) { if (tagValue.indexOf('http') == 0) { JSZipUtils.getBinaryContent(tagValue, function (error, content) { if (error) { return reject(error); } return resolve(content); }); } else if (tagValue.indexOf('data:image') == 0) { const buffer = base64ToArrayBuffer(tagValue); return resolve(buffer); } }); }, getSize(img, tagValue, tagName) { // return getSizeProportional(horizontalHeight, verticalWidth, img, tagValue, tagName) return getSizeFixed( horizontalHeight, verticalWidth, options.scale, img, tagValue, tagName ); } }; } export const exportDocx = (tempDocpath, data, zipName, imageSize) => { return new Promise((resolve, reject) => { JSZipUtils.getBinaryContent(tempDocpath, (error, content) => { if (error) { reject(error); throw error; } const zip = new Pizzip(content); let doc = new docxtemplater() .setOptions({ paragraphLoop: true }) .loadZip(zip); if (imageSize) { const imageOptions = getImageOptions(imageSize); doc.attachModule(new ImageModule(imageOptions)); } doc.compile(); doc.resolveData(data).then(() => { try { doc.render(); } catch (error) { console.log(error); throw error; } const out = doc.getZip().generate({ type: 'blob', mimeType: 'application/vnd.openxmlformats-officedocumnet.wordprocessingml.document' }); FileSaver.saveAs(out, zipName); resolve(); }); }); }); };