Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can not render a WebGL image for PDF -- get a black box instead #1731

Closed
onamission opened this issue Jan 5, 2018 · 35 comments
Closed

Can not render a WebGL image for PDF -- get a black box instead #1731

onamission opened this issue Jan 5, 2018 · 35 comments
Labels
bug chromium Issues with Puppeteer-Chromium confirmed

Comments

@onamission
Copy link

onamission commented Jan 5, 2018

Summary:

I am trying to get a PDF of a page that has a panoramic image on it using Puppeteer. The panoramic image is rendered using WebGL, which I suspect to be the issue. All I get is a black box instead of the image (see the bottom of this post for screen image). But, I can use Puppeteer to get a screenshot of that same page and the panorama looks great. I am not sure why it won't render when I attempt getting a PDF, but works for screenshot.

Steps to reproduce

Tell us about your environment:

  • Puppeteer version: puppeteer@0.10.2
  • Platform / OS version: Linux c1301da96bb5 4.9.49-moby running in a Docker container
  • URLs (if applicable):
  • Node.js version: 8.8.1 (NOTE: the code below was originally developed in 6.1, but we now run 8.8.1)

What steps will reproduce the problem?

Please include code that reproduces the issue.

  1. Using this code:
var page, browser;
return Puppeteer.launch({args: options.chromeArgs})
    .then(res => {
        if (!res) {
            return reject(new Error("No browser to open"));
        }
        browser = res;
        return browser.newPage();
    })
    .then(res => {
        if (!res) {
            throw new Error("No browswer available");
         }
        page = res;
        return page.setViewport({
            height: 720,
            width: 1280,
            isLandscape: true,
        ));
    })
    .then(() => {
        return page.goto(url,{"waitUntil":"networkidle0"});
    })
    .then(() => {
        return page.pdf(options);
    })
    .then(buffer => {
       if (browser) {
           browser.close();
       }
       return resolve(buffer);
    })
    .catch(err => {
        if (browser) {
            browser.close();
        }
        return reject(err);
    });
  1. I have tried these options:
            "pageTimeout": 120000,
            "chromeArgs": ["--disable-gpu","--disable-setuid-sandbox","--no-sandbox"],
            "headless": true,
            "printBackground": true,
            "displayHeaderFooter": true,
            "landscape": true,
            "margin": {
                "top": 0,
                "bottom": 0,
                "left": 0,
                "right": 0
            }
        }
  1. I have also tried adding these the the chromeArgs:
    --use-gl=swiftshader
    --use-gl=osmesa
    --use-gl=swiftshader-webgl

What is the expected result?
I would expect the PDF to look like the screenshot -- like this
004

Here is the screenshot from Puppeteer (NOTE: the html page is formatted slightly differently for PDF rendering, but the panoramic image is the same)
0002

What happens instead?
The PDF has a black box where the panoramic image should be.
003

@JoelEinbinder
Copy link
Contributor

What happens if you try to print the page with chrome?

@aslushnikov
Copy link
Contributor

@onamission I see you try to create pdf right after the networkidle0 event. I'd expect the page with WebGL context to do some async rendering using requestAnimationFrame, so it might be that you need to wait a bit before attempting to pdf the page.

@joelgriffith
Copy link
Contributor

Curious if anyone has solved this since I've ran into a similar issue. Image/PNG generation works just fine but PDF's are showing blanks for a canvas-based map.

I can post repo steps here if it makes debugging easier.

@ianformanek
Copy link

Same problem here so I'll add examples plus link to the actual page in case this would be helpful.

The following page renders just fine as screenshot, but the map canvas (Mapbox-gl WebGL) is blank when rendering as PDF: https://dashboards.cluvio.com/dashboards/wx7y-53qr-pv5o/shared?sharingToken=759d96a5-da83-493c-833e-6b8f694a6189

dashboard

dashboard.pdf

@joelgriffith
Copy link
Contributor

FWIW I think this might be a problem deeper downstream since this issue is present in a few libraries. I've created a post on the headless dev group here https://groups.google.com/a/chromium.org/forum/#!topic/headless-dev/BVpTJ4JIR8Q to try and see if it's deeper than just this library

@joelgriffith
Copy link
Contributor

Some follow up: I've been instructed to create a bug in the Chromium tracker, which is can be found here.

I'll keep this thread up-to-date as its status changes.

@antiquechrono
Copy link

I'm having a similar issue except both screenshot and pdf both output as white. If I turn off headless then the screenshot renders as expected and the pdf crashes with the following.

(node:53832) UnhandledPromiseRejectionWarning: Error: Protocol error (Page.printToPDF): PrintToPDF is not implemented undefined at Promise (/Users/matt/Projects/test/node_modules/puppeteer/lib/Connection.js:196:56) at new Promise (<anonymous>) at CDPSession.send (/Users/matt/Projects/test/node_modules/puppeteer/lib/Connection.js:195:12) at Page.pdf (/Users/matt/Projects/test/node_modules/puppeteer/lib/Page.js:771:39) at /Users/matt/Projects/test/index.js:21:14 at <anonymous> (node:53832) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1) (node:53832) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

@allthesignals
Copy link

@joelgriffith in your Google group comment, you mention that screenshot works - how were you able to at least get screenshot working? I am also trying to get this to work with MapboxGL

@allthesignals
Copy link

I had better luck with this solution: #1260 (comment), specifically for MapboxGL.

@ronalb
Copy link

ronalb commented Mar 27, 2018

@allthesignals Hi, I'm trying to run headless with MapboxGL , it works fine in all distributions ,but
only in Centos it doesnt work. I'm using centos 7.4. do you know anything about it?

@zuohuadong
Copy link

zuohuadong commented Apr 23, 2018

me too.

ubuntu server 16.04 (X)

Linux mint 18.3 with Cinnamon (√)

@fhvknb
Copy link

fhvknb commented May 3, 2018

someone have solved this problem?

@mvoropaiev
Copy link

Hello, had similar issue running headless chromium on lambda for PDF generation (screenshots were working fine with WebGL but PDF not), solved it by rolling back to 64.0.3282.167 (instead of latest stable 67.0.3396.79 or dev 69.0.3452.0), hope it might help someone.

@ronalb
Copy link

ronalb commented Jun 13, 2018

also on windows platform, puppeteer version 1.5 doesn't render webgl,
puppeteer version 1.3 works fine.

@nuthinking
Copy link

Also with Mac 1.5 webgl in pdf is blank.

@robhawkes
Copy link

robhawkes commented Jul 27, 2018

I'm experiencing the same issues in regard to manipulating and outputting a WebGL context via PDF. The process I use it to render a WebGL scene in Chrome headless, export a PNG snapshot using JavaScript, inject that image into the DOM, and then save as both a screenshot and PDF. The whole process is run using a single page within Puppeteer.

Here are results from the most recent Puppeteer versions (on Windows):

1.6.1 (HeadlessChrome/69.0.3494.0 - Revision 575458)

  • WebGL context does not output in PDF
  • Image snapshot of WebGL context does not output in PDF

1.6.0 (HeadlessChrome/69.0.3477.0 - Revision 571375)

  • WebGL context does not output in PDF
  • Image snapshot of WebGL context does not output in PDF

1.5.0 (HeadlessChrome/69.0.3452.0 - Revision 564778)

  • WebGL context does not output in PDF
  • Image snapshot of WebGL context does not output in PDF

1.4.0 (HeadlessChrome/68.0.3419.0 - Revision 555668)

  • WebGL context does not output in PDF
  • Image snapshot of WebGL context does output in PDF

As you can see, something happened between 1.4.0 and 1.5.0 to break the WebGL context in Puppeteer PDF exports.

@ronalb
Copy link

ronalb commented Aug 9, 2018

@robhawkes I had to downgrade to 1.4 because of this issue. I'm rendering mapbox webgl maps in headless chrome.

@robhawkes
Copy link

@ronalb Coincidentally, that's exactly what I'm doing too! The 1.4.0 downgrade has been workable for me so far, though it's frustrating that it's not possible to use the latest version as things stand.

@ronalb
Copy link

ronalb commented Aug 9, 2018

@robhawkes yeah ,very frustrating. as from 1.6 some race conditions bugs were fixed.

@ronalb
Copy link

ronalb commented Aug 13, 2018

@robhawkes just checked on puppeteer 1.7 and it seems to be fixed !

@robhawkes
Copy link

@ronalb You got me excited but it still doesn't seem to work for me (1.7.0 using HeadlessChrome/70.0.3508.0), the WebGL context is still blank. Did you do anything different to get it working?

@ronalb
Copy link

ronalb commented Aug 13, 2018

@robhawkes no I didn't do anything ,but maybe my scenario is different. I also see that you wrote
in version 1.4 that it doesnt work for you in PDF. for me it worked.

some more info: I think I know the difference , I am not really using the PDF feature , what I do is take an image snapshot,(I had to use some timeout because of mapbox doesn't let me know when the map is loaded)
and put it on a new generated html, then I export the new html to pdf.

@aslushnikov aslushnikov added the chromium Issues with Puppeteer-Chromium label Dec 6, 2018
@joelgriffith
Copy link
Contributor

I haven't seen a lot of movement on the Chromium side (https://bugs.chromium.org/p/chromium/issues/detail?id=809065), is there any sense on how/when this could be fixed?

@andrewharvey
Copy link

@ianformanek Make sure you're using preserveDrawingBuffer: true.

@ianformanek
Copy link

Yeah, this is it! Creating the mapbox-gl instances like this:

      map = new mapboxgl.Map({
        container: '...',
        ...,
        preserveDrawingBuffer: true
      });

fixes the issue when the map would be empty when using puppeteer to render pdf (probably limited to rendering on server without a GPU).

It is still interesting that pdf and image behave differently in this regard, but probably has to do with timing. See also mapbox/mapbox-gl-js#6448

Thanks!

@anurasin
Copy link

anurasin commented Jan 21, 2020

Any update on this thread: The issue is still coming for "puppeteer": "^2.0.0".
With headless mode, on taking the screenshot of a canvas element it's getting the blank output, but on running the same code with headlfull mode it's working just fine.

@gbuckingham89
Copy link

gbuckingham89 commented Oct 19, 2020

I'm seeing this issue when I try to render a PDF containing a mapbox-gl-js map on the latest release of Puppeteer (5.3.1) on Ubuntu server 18.04 LTS.

I've tried using the bundled Chromium version and latest releases of Chrome and Chrome Beta - all give the same result.

I've tried setting the preserveDrawingBuffer: true option on the Mapbox map.

If I set dumpio: true when launching Puppeteer, I do see this error message:

[1019/145021.772786:ERROR:command_buffer_proxy_impl.cc(122)] ContextResult::kTransientFailure: Failed to send GpuChannelMsg_CreateCommandBuffer.

Screenshot 2020-10-19 at 15 48 51

@Peque
Copy link

Peque commented Dec 27, 2020

I had the same issue with Three.js. A workaround is to use the already-suggested preserveDrawingBuffer:

renderer = new THREE.WebGLRenderer({ antialias: true, preserveDrawingBuffer: true });

UPDATE: I ended-up using screenshots instead, since preserveDrawingBuffer was causing unexpected issues with some browsers/OSs when rendering the scene in the browser.

@pguardiario
Copy link

pguardiario commented Jun 19, 2021

For some reason the mapbox issue affects pdf but not screenshots, so my workaround was to replace canvases with screenshots:

let canvases = await page.$$('canvas')
for(let canvas of canvases){
    let str = await canvas.screenshot({ encoding: "base64" })
    let dataUrl = 'data:image/png;base64,' + str
    await canvas.evaluate((canvas, dataUrl) => {
      const newDiv = document.createElement('div')
      newDiv.innerHTML = '<img src="' + dataUrl + '">'
      canvas.parentNode.replaceChild(newDiv, canvas)
    }, dataUrl)
}

@YosanAI
Copy link

YosanAI commented Dec 24, 2021

Any updates? I am still experiencing this on puppeteer: "13.0.0. screenshot works. but pdf doesnt work. I have also noticed that on threejs, when there is no light added to the scene, and the material uses MeshNormalMaterial() it works.

EDIT: @pguardiario answer worked for me

@davenrai
Copy link

I was able to render a webgl frame as a pdf using the following arguments.

const browser = await puppeteer.launch({ args: [ '--ignore-certificate-errors',"--use-gl=swiftshader", "--enable-webgl", ]});

@stale
Copy link

stale bot commented Aug 30, 2022

We're marking this issue as unconfirmed because it has not had recent activity and we weren't able to confirm it yet. It will be closed if no further activity occurs within the next 30 days.

@stale stale bot added the unconfirmed label Aug 30, 2022
@Peque
Copy link

Peque commented Aug 31, 2022

As far as I know this is still an issue. The screenshots workaround works well, but if that is the way to go I think it should be documented or, even better, integrated. 😊

If puppeteer was able to take screenshots automatically it would be great to be able to specify the format and quality (if applicable), since it has a big impact on the size of the generated PDF.

@ismailCodes
Copy link

For some reason the mapbox issue affects pdf but not screenshots, so my workaround was to replace canvases with screenshots:

let canvases = await page.$$('canvas')
for(let canvas of canvases){
    let str = await canvas.screenshot({ encoding: "base64" })
    let dataUrl = 'data:image/png;base64,' + str
    await canvas.evaluate((canvas, dataUrl) => {
      const newDiv = document.createElement('div')
      newDiv.innerHTML = '<img src="' + dataUrl + '">'
      canvas.parentNode.replaceChild(newDiv, canvas)
    }, dataUrl)
}

After two months of trying a lot of solutions, this one worked finally. thanks for thinking out of the box. 🚀🚀

@OrKoN
Copy link
Collaborator

OrKoN commented Mar 29, 2024

I am not able to reproduce the issue using the latest versions. Are there pages that still do not work?

@OrKoN OrKoN closed this as not planned Won't fix, can't repro, duplicate, stale Mar 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug chromium Issues with Puppeteer-Chromium confirmed
Projects
None yet
Development

No branches or pull requests