You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Docxtemplater生成的DOCX文档在页面转换为PDF?

将生成的DOCX文档转换为PDF的方案

问题背景

我制作了一个生成Word DOCX文档的页面,当前使用以下代码生成DOCX文档:

function loadFile(url,callback){
    PizZipUtils.getBinaryContent(url,callback);
}
function gen(id, dane) {
    $.ajax({
        url:"create.php",
        method:"post",
        data:{id},
        success:function(data)
        {
            dane.numer = data;
            generate(dane);
        }
    });
}
function generate(data) {
    loadFile("/doc.docx",function(error,content){
        if (error) { throw error };
        function replaceErrors(key, value) {
            if (value instanceof Error) {
                return Object.getOwnPropertyNames(value).reduce(function(error, key) {
                    error[key] = value[key];
                    return error;
                }, {});
            }
            return value;
        }
        function errorHandler(error) {
            console.log(JSON.stringify({error: error}, replaceErrors));

            if (error.properties && error.properties.errors instanceof Array) {
                const errorMessages = error.properties.errors.map(function (error) {
                    return error.properties.explanation;
                }).join("\n");
                console.log('errorMessages', errorMessages);
            }
            throw error;
        }
        var zip = new PizZip(content);
        var doc;
        try {
            doc=new window.docxtemplater(zip);
        } catch(error) {
            errorHandler(error);
        }
        doc.setData(data);
        try {
            doc.render();
        }
        catch (error) {
            errorHandler(error);
        }
        var out=doc.getZip().generate({
            type:"blob",
            mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
        })
        saveAs(out,"Prot "+ data.name +".docx")
    })
}

请问如何在该页面将生成的Word DOCX文档转换为PDF文件?

解决方案

方案一:前端纯JS转换(适合简单文档)

这种方式无需后端参与,但对复杂样式(如表格、特殊字体、分页)支持有限。

  1. 引入依赖库
    通过CDN引入处理DOCX转HTML、HTML转PDF的工具:
<script src="https://unpkg.com/mammoth@1.6.0/mammoth.browser.min.js"></script>
<script src="https://unpkg.com/jspdf@2.5.1/dist/jspdf.umd.min.js"></script>
<script src="https://unpkg.com/html2canvas@1.4.1/dist/html2canvas.min.js"></script>
  1. 修改生成逻辑,添加转换代码
    在原generate函数生成DOCX Blob后,新增转换逻辑:
function generate(data) {
    loadFile("/doc.docx",function(error,content){
        // 原DOCX生成代码保持不变

        var out=doc.getZip().generate({
            type:"blob",
            mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
        });

        // 新增:DOCX转PDF逻辑
        convertDocxToPdf(out, data.name);
        // 可选:保留原DOCX下载
        saveAs(out,"Prot "+ data.name +".docx");
    })
}

// 定义转换函数
function convertDocxToPdf(docxBlob, filename) {
    const reader = new FileReader();
    reader.onload = function(e) {
        // 将DOCX转为HTML
        mammoth.convertToHtml({arrayBuffer: e.target.result})
        .then(result => {
            const html = result.value;
            // 处理转换提示(可选)
            result.messages.forEach(msg => console.log(`${msg.type}: ${msg.message}`));

            // 将HTML转为PDF
            const { jsPDF } = window.jspdf;
            const pdfDoc = new jsPDF('p', 'mm', 'a4');
            
            // 用html2canvas处理HTML后生成PDF(适配复杂元素)
            const tempContainer = document.createElement('div');
            tempContainer.style.display = 'none';
            tempContainer.innerHTML = html;
            document.body.appendChild(tempContainer);

            html2canvas(tempContainer)
            .then(canvas => {
                const imgData = canvas.toDataURL('image/png');
                const imgWidth = 210;
                const pageHeight = 297;
                const imgHeight = canvas.height * imgWidth / canvas.width;
                let heightLeft = imgHeight;
                let position = 0;

                pdfDoc.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight);
                heightLeft -= pageHeight;

                // 处理分页
                while (heightLeft >= 0) {
                    position = heightLeft - imgHeight;
                    pdfDoc.addPage();
                    pdfDoc.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight);
                    heightLeft -= pageHeight;
                }

                // 下载PDF
                pdfDoc.save(`Prot ${filename}.pdf`);
                document.body.removeChild(tempContainer);
            });
        })
        .catch(err => console.error('DOCX转HTML失败:', err));
    };
    reader.readAsArrayBuffer(docxBlob);
}

方案二:后端转换(推荐,样式还原度高)

通过后端服务处理转换,适合复杂文档,样式还原更准确。

  1. 前端修改:上传DOCX到后端
function generate(data) {
    loadFile("/doc.docx",function(error,content){
        // 原DOCX生成代码保持不变

        var out=doc.getZip().generate({
            type:"blob",
            mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
        });

        // 上传DOCX到后端转换
        const formData = new FormData();
        formData.append('docxFile', out, 'temp.docx');
        formData.append('filename', data.name);

        $.ajax({
            url: 'convert_to_pdf.php',
            method: 'POST',
            data: formData,
            processData: false,
            contentType: false,
            success: function(pdfData) {
                const blob = new Blob([pdfData], {type: 'application/pdf'});
                saveAs(blob, `Prot ${data.name}.pdf`);
            },
            error: xhr => console.error('转换失败:', xhr.responseText)
        });

        // 可选:保留原DOCX下载
        saveAs(out,"Prot "+ data.name +".docx");
    })
}
  1. 后端PHP示例(基于LibreOffice命令行,效率高)
    确保服务器已安装LibreOffice,创建convert_to_pdf.php:
<?php
if ($_FILES['docxFile']['error'] === UPLOAD_ERR_OK) {
    $inputPath = $_FILES['docxFile']['tmp_name'];
    $outputDir = sys_get_temp_dir();
    $outputPath = tempnam($outputDir, 'pdf_') . '.pdf';
    $filename = $_POST['filename'];

    // 调用LibreOffice命令转换
    $command = "libreoffice --headless --convert-to pdf --outdir " . escapeshellarg($outputDir) . " " . escapeshellarg($inputPath);
    exec($command, $outputLogs, $returnCode);

    if ($returnCode === 0 && file_exists($outputPath)) {
        header('Content-Type: application/pdf');
        header('Content-Disposition: attachment; filename="Prot ' . $filename . '.pdf"');
        readfile($outputPath);
        unlink($outputPath);
    } else {
        http_response_code(500);
        echo "转换失败: " . implode("\n", $outputLogs);
    }
} else {
    http_response_code(400);
    echo "文件上传失败";
}
?>

注意事项

  • 前端转换仅适合结构简单的文档,复杂样式优先选择后端方案
  • 后端使用LibreOffice时,需确保服务器已安装该软件,且命令行执行权限正常
  • 转换大文件时,需调整服务器的上传大小和超时限制

内容的提问来源于stack exchange,提问作者miko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 18:45:41