Sparticuz / node-qpdf2

A Content Preserving transformations on PDFs wrapped around QPDF
MIT License
20 stars 16 forks source link

Buffer input #25

Open Sparticuz opened 2 years ago

Sparticuz commented 2 years ago

According to https://github.com/qpdf/qpdf/issues/54, we can't use stdin as input. Build a helper function that will take in a buffer as input and output it to /tmp before passing it to qpdf

EmmanDizon commented 1 year ago

is this resolve ? i want also an input buffer. @Sparticuz

EmmanDizon commented 1 year ago

what i want is, i will generate an HTML template to PDF using pdf-creator-node, then thaat result buffer i will transfer to node-qpdf2 library to set a password. is that possible ?

Sparticuz commented 1 year ago

This is what I use in my app, outside of this package. I will probably add it next time I allocate some time to this package.

import { randomUUID } from "node:crypto";
import { writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import type { Readable } from "node:stream";

/** Writes a Readable to a File in tmpdir() */
export const writeTemporaryFile = async (file: Readable): Promise<string> => {
  const filePath = join(tmpdir(), `${randomUUID().replaceAll("-", "")}.pdf`);
  await writeFile(filePath, file);
  return filePath;
};

So I'll take my buffer or stream or whatever, and put it in this function which outputs a file path that I can use in node-qpdf2.

EmmanDizon commented 1 year ago

is the tmpdir automatically deletes after execution ? @Sparticuz

EmmanDizon commented 1 year ago

aint working for me. this is my code:

generatePDF.js: ` console.time(); const fs = require("fs"); const pdf = require("pdf-creator-node"); const data = require("./utils/data"); const { secure } = require("./pdf");

  const generatePdf = async () => {
    // Read HTML Template
    const html = fs.readFileSync("./template.html", "utf8");

const options = {
  format: "A3",
  orientation: "portrait",
};

const document = {
  html: html,
  data,
  type: "buffer",
};

const pdfBuffer = await pdf.create(document, options);
await secure(pdfBuffer);

console.timeEnd();

}; generatePdf();`

secure.js: ` const { S3 } = require("aws-sdk"); const fs = require("fs"); const { writeTemporaryFile } = require("./temp"); const s3 = new S3();

const secure = async (file) => {
  try {
    const { encrypt } = await import("node-qpdf2");

    const pdf = {
      input: await writeTemporaryFile(file),
      password: "1234emman",
    };

    const encryptedPdf = await encrypt(pdf);

    const htmlParams = {
      Bucket: "certificate",
      Key: `documents/emman/test.pdf`,
      Body: encryptedPdf,
      ServerSideEncryption: "AES256",
      ContentDisposition: "inline",
      ContentType: "application/pdf",
    };

    await s3.upload(htmlParams).promise();
  } catch (error) {
    console.error(error);
  }
};

module.exports = { secure };

`

temp.js:

` const { randomUUID } = require("crypto"); const { writeFile } = require("fs/promises"); const { tmpdir } = require("os"); const { join } = require("path");

/** Writes a Readable to a File in tmpdir() */
const writeTemporaryFile = async (file) => {
  const filePath = join(tmpdir(), `${randomUUID().replaceAll("-", "")}.pdf`);
  await writeFile(filePath, file);
  return filePath;
};

module.exports = { writeTemporaryFile };

`

When i open the file on s3 bucket, it contains nothing

EmmanDizon commented 1 year ago

here is the screenshot:

image

Sparticuz commented 1 year ago

I've never used pdf-creator-node before. Does the file display properly before attempting to encrypt it?

EmmanDizon commented 1 year ago

@Sparticuz yes it works when creating an output like this:

const pdf = { input: await writeTemporaryFile(file), password: "1234emman", output: "./tmp/secure.pdf", };

await encrypt(pdf);

when i open the pdf on tmp/secure.pdf, inputs a password then open the pdf then boom, i see my html template, that "file" parameter on const secure = async (file) => { is a buffer from pdf-creator-node.

it works fine when passing like code above. but what if i dont want to create "./tmp/secure.pdf", pass the pdfbuffer to s3 bucket, it aint working like the previous code above our conversations i mentioned:

` const encryptedPdf = await encrypt(pdf);

const htmlParams = {
  Bucket: "certificate",
  Key: `documents/emman/test.pdf`,
  Body: encryptedPdf,
  ServerSideEncryption: "AES256",
  ContentDisposition: "inline",
  ContentType: "application/pdf",
};

await s3.upload(htmlParams).promise();`
Sparticuz commented 1 year ago

I don't think qpdf supports that. I guess you could then read the file into a buffer then pass it to s3, but that seems redundant. Again, this Feature Request will probably just 'fake it' by just taking the buffer and throwing it into a file, then taking the file and throwing it in a buffer.

EDIT:

Actually, This is in my tests, it should work:

test.serial("Should encrypt File -> Buffer", async (t) => {
  const BufferFromFile = await encrypt({
    input,
    password: "1234",
  });
  t.true(Buffer.isBuffer(BufferFromFile));
});
EmmanDizon commented 1 year ago

Not work for me when i open the PDF file the content is missing.

dmytrovskyi commented 11 months ago

Hi! Thanks for your work! I also faced with issue that after encryption my PDF was blank. I save the document locally not in any clouds. In the result document, I have the same number of pages, but they are white. During testing before the encryption, the pdf has content.

dmytrovskyi commented 11 months ago

Found one interesting thing, if I save data to a file and then read it all works fine. But if I operate with the buffer that returns from encrypt method - the document is white. @EmmanDizon maybe my case will help you.