将 BLOB (docxtemplater) 转换为 PDF - REACT

问题描述 投票:0回答:1

大家好,我正在使用 React.js 和 Node.js 开发一个网站,我根据用户的输入生成一个 Word 文档,这与 docxtemplater 配合得很好!

问题是我想让用户直接将word文档下载为PDF文档,但docxtemplater只允许我们将文件另存为docx。 为了转换docx,我有想法用gridfs将我的blob文档保存在mongodb中(已经完成并且工作正常),然后获取我的blob并将其转换为pdf(我被阻止的地方)

这是我的代码部分,用于生成我的docx并将生成的word docx保存在mongodb中(我故意删除了一些对这个问题不重要的东西)

import React, { useState, useEffect } from "react";
import Docxtemplater from "docxtemplater";
import PizZip from "pizzip";
import PizZipUtils from "pizzip/utils/index.js";
import { saveAs } from "file-saver"; 
import axios from "axios";

function loadFile(url, callback) {
  PizZipUtils.getBinaryContent(url, callback);
}

export const DocxFile = ({ formData }) => {
  const [file, setFile] = useState(null);
  const [currentlyUploading, setCurrentlyUploading] = useState(false);
  const [docxId, setDocxId] = useState(null);
  const [progress, setProgress] = useState(null);
  const [inputContainsFile, setInputContainsFile] = useState(false);
  const [template, setTemplate] = useState();


  const generateDocument = () => {
    loadFile(template, function (error, content) {
      if (error) {
        throw error;
      }

      var zip = new PizZip(content);
      var doc = new Docxtemplater(zip, {
        paragraphLoop: true,
        linebreaks: true,
      });

      doc.setData({
        company: formData.general.companyClient,
        version: formData.documentVersion,
        quote: formData.general.quoteNumber,
        HERE MY DATA //Working :)
      });
      try {
        doc.render();
      } catch (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;
        }

        if (error.properties && error.properties.errors instanceof Array) {
          const errorMessages = error.properties.errors
            .map(function (error) {
              return error.properties.explanation;
            })
            .join("\n");
        }
        throw error;
      }
      var out = doc.getZip().generate({
        type: "blob",
        mimeType:
          "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
      });
      saveAs(
        out,
        `${name}.${documentVersion}.docx`
      );

      setFile(out);
      setInputContainsFile(true);
    });
  };

  const fileUploadHandler = () => {
    const fd = new FormData();
    fd.append("docx", file, file.name);
    axios
      .post(`api/docx/upload`, fd, {
        onUploadProgress: (ProgressEvent) => {
          setProgress((ProgressEvent.loaded / ProgressEvent.total) * 100);
          console.log(
            "upload progress",
            Math.round((ProgressEvent.loaded / ProgressEvent.total) * 100)
          );
        },
      })
      .then(({ data }) => {
        setDocxId(data);
        setFile(null);
        setInputContainsFile(false);
        setCurrentlyUploading(false);
      })
      .catch((err) => {
        console.log(err);
        if (err.response.status === 400) {
          const errMsg = err.response.data;
          if (errMsg) {
            console.log(errMsg);
          }
        } else {
          console.log("other error", err);
          setInputContainsFile(false);
          setCurrentlyUploading(false);
        }
      });
  };
  const handleClick = () => {
    if (inputContainsFile) {
      setCurrentlyUploading(true);
      fileUploadHandler();
    }
  };

  return (
    <>
      <button
        className="modify__button1 enregistrer generator__button"
        onClick={generateDocument}
      >
       Generate the docx
      </button>
      <label htmlFor="file" onClick={handleClick}>
        {file ? <>SUBMIT</> : <></>}
      </label>
    </>
  );
};

这是我发送后在 mongodb 上得到的:MongodbBLOB

之后,我将执行一个 get 请求来获取我的 blob(我已经知道如何获取我的 blob)但是,然后,我如何将其转换为 pdf(并保留用于我的 docx 的模板)?

reactjs blob gridfs docxtemplater
1个回答
0
投票

我发现的最好的选择(无需在光盘上写入任何内容!)基于

libreoffice-convert
npm(您仍然需要在计算机上安装 libreoffice)。

现在我可以基于 docxtemplater 的相同模板轻松创建 DOCX 和 PDF ;-)

我的反应代码:

// In your controller or service:

export const exportTextToFile = async (text: string, filetype: string): Promise<Blob> => {
    const exportToFileEndpointUrl = `${API_BASE_URL}/api/export/${filetype}`;
    const response = await axios.post<ArrayBuffer>(exportToFileEndpointUrl, text, {
        responseType: 'arraybuffer',
    });

    return new Blob([response.data]);
};



// In your component:

const getAndDownloadFile = async (filetype: string) => {
        try {
            const blob = await exportTextToFile(text, filetype);
            saveAs(blob, `MyFile.${filetype}`);
        } catch (error) {
            console.error(error);
        }
    };

在 NodeJS 后端应用程序中:

import libre from 'libreoffice-convert';


try {
        const docxBuffer = await generateDocx(...);

        if (filetype === 'pdf') {
            libre.convert(docxBuffer, 'pdf', undefined, (err, pdfBuffer) => {
                if (err) {
                    throw err;
                } else {
                    res.send(pdfBuffer);
                }
            });
        } else if (filetype === 'docx') {
            res.send(docxBuffer);
        }

        logger.info('Sent file buffer to the client', { filetype });
    } catch (error) {
        logger.error('Error during file creation', { filetype, error: error.message });
        res.sendStatus(500);
    }


// Your docxtemplater generator:

import Docxtemplater from 'docxtemplater';

function generateDocx(...): Promise<Buffer> {
    const content = fs.readFileSync(path.resolve(__dirname, 'your-template.docx'), 'binary');

    const zip = new PizZip(content);
    const doc = new Docxtemplater(zip, {
        paragraphLoop: true,
        linebreaks: true,
    });
    doc.render({
       /// your template params
    });

    const buffer = doc.getZip().generate({
        type: 'nodebuffer',
        compression: 'DEFLATE',
    });

    return buffer;
}
© www.soinside.com 2019 - 2024. All rights reserved.