mozilla / pdf.js

PDF Reader in JavaScript
https://mozilla.github.io/pdf.js/
Apache License 2.0
47.09k stars 9.81k forks source link

Background image does not load for some PDFs #14296

Open wojtekmaj opened 2 years ago

wojtekmaj commented 2 years ago

Attach (recommended) or Link to PDF file here: welzRkYrNV6JRO8q.pdf

Configuration:

Steps to reproduce the problem:

What is the expected behavior? (add screenshot)

PDF should look like this: yes

What went wrong? (add screenshot) It displays a white background and this seems to be an issue in certain viewers. Here's are some other viewers I tested with, where it works and where it fails:

Instead it renders like this: no

Originally raised by @anniebombanie in https://github.com/wojtekmaj/react-pdf/issues/832

aufula commented 2 years ago

mac's default previewer.app also doesn't render correctly

aufula commented 2 years ago

@Snuffleupagus node-canvas works fine on this issue. I tested skia-canvas which is chrome's low-level rendering lib, get same result to this issue. I think this issue is related to Browser not pdf.js

const { Canvas: CanvasSkia } = require("skia-canvas");
const Canvas = require("canvas");

const fs = require("fs");
const pdfjsLib = require("pdfjs-dist/legacy/build/pdf.js");

const CMAP_URL = "/node_modules/pdfjs-dist/cmaps/";
const CMAP_PACKED = true;
const STANDARD_FONT_DATA_URL = "/node_modules/pdfjs-dist/standard_fonts/";

// Loading file from file system into typed array.
const pdfPath =
  // process.argv[2] || "/web/compressed.tracemonkey-pldi-09.pdf";
  process.argv[2] || "14296.pdf";

const data = new Uint8Array(fs.readFileSync(pdfPath));

function NodeCanvasFactory() {}
NodeCanvasFactory.prototype = {
  create: function NodeCanvasFactory_create(width, height) {
    // const canvas = Canvas.createCanvas(width, height);  // uncomment this line
    const canvas = new CanvasSkia(width, height);

    const context = canvas.getContext("2d");
    return {
      canvas,
      context,
    };
  },

  reset: function NodeCanvasFactory_reset(canvasAndContext, width, height) {
    canvasAndContext.canvas.width = width;
    canvasAndContext.canvas.height = height;
  },

  destroy: function NodeCanvasFactory_destroy(canvasAndContext) {
    // Zeroing the width and height cause Firefox to release graphics
    // resources immediately, which can greatly reduce memory consumption.
    canvasAndContext.canvas.width = 0;
    canvasAndContext.canvas.height = 0;
    canvasAndContext.canvas = null;
    canvasAndContext.context = null;
  },
};

// Load the PDF file.
const loadingTask = pdfjsLib.getDocument({
  data,
  cMapUrl: CMAP_URL,
  cMapPacked: CMAP_PACKED,
  standardFontDataUrl: STANDARD_FONT_DATA_URL,
});

(async function () {
  try {
    const pdfDocument = await loadingTask.promise;
    const page = await pdfDocument.getPage(2);

    const viewport = page.getViewport({ scale: 1.0 });
    const canvasFactory = new NodeCanvasFactory();
    const canvasAndContext = canvasFactory.create(viewport.width, viewport.height);
    const renderContext = {
      canvasContext: canvasAndContext.context,
      viewport,
      canvasFactory,
    };

    const renderTask = page.render(renderContext);
    await renderTask.promise;
    const image = await canvasAndContext.canvas.toBuffer(); // skia version

    fs.writeFile("output.png", image, function (error) {
      if (error) {
        console.error("Error: " + error);
      } else {
        console.log("Finished converting first page of PDF file to a PNG image.");
      }
    });
  } catch (reason) {
    console.log(reason);
  }
})();