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

Cannot render pdf with images stored locally #1643

Closed
acgrama opened this issue Dec 21, 2017 · 9 comments

Comments

@acgrama
Copy link

@acgrama acgrama commented Dec 21, 2017

I cannot get images stored locally to be rendered in generated pdf with Puppeteer, but external images for which I specify a url work.

In particular, in the sample code below, rendering the page in test_html1 works, while rendering the test_html2 does not work.

(async () => {
const browser = await puppeteer.launch({ args: ['--no-sandbox'] });
const page = await browser.newPage();
const test_html1 = `<html><h3>Hello world!</h3><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/2/2f/Google_2015_logo.svg/1024px-Google_2015_logo.svg.png"></html>`;
 // const test_html2 = `<html><h3>Hello world!</h3><img src="file:///home/cristina/Documents/logo.jpg"></html>`;
await page.goto(`data:text/html,${test_html}`, { waitUntil: 'networkidle0' });
await page.pdf({ path: `${this.outputPath}/test-puppeteer.pdf`,
  format: 'A4', landscape: !data.isPortrait,
  margin: { top: '0.5cm', right: '1cm', bottom: '0.8cm', left: '1cm' }, printBackground: true });
await browser.close();
})();`

Result with test_html1:
test1

Result with test_html2:
test2

@yujiosaka

This comment has been minimized.

Copy link
Contributor

@yujiosaka yujiosaka commented Dec 21, 2017

@acgrama

You can see why by launching with headless: false option.
I can see this error:
2017-12-21 21 58 18

It's a security block to protect from malicious websites to access local images, and cannot be disabled by --no-sandbox option.

@acgrama

This comment has been minimized.

Copy link
Author

@acgrama acgrama commented Dec 21, 2017

Aha, thank you, this is very valuable information!

Too bad I cannot start with headless: false option, since I'm running in docker as root (also the reason why I'm using the -no-sandbox option).

Is there any way to embed locally stored images in a rendered pdf? We are generating dynamic pdf reports, so if images cannot be embedded from local storage Puppeteer seems kind of useless for us...

@yujiosaka

This comment has been minimized.

Copy link
Contributor

@yujiosaka yujiosaka commented Dec 21, 2017

@acgrama
In that case, why don't you just serve those static files? Something like this should work:

const puppeteer = require('puppeteer');
const express = require('express');
const app = express();
app.use(express.static('/home/cristina/Documents'))
app.listen(3000);

(async () => {
  const browser = await puppeteer.launch({ args: ['--no-sandbox'] });
  const page = await browser.newPage();
  const test_html = `<html><h3>Hello world!</h3><img src="http://localhost:3000/logo.jpg"></html>`;
  await page.goto(`data:text/html,${test_html}`, { waitUntil: 'networkidle0' });
  await page.pdf({ path: `${this.outputPath}/test-puppeteer.pdf`,
    format: 'A4', landscape: !data.isPortrait,
    margin: { top: '0.5cm', right: '1cm', bottom: '0.8cm', left: '1cm' }, printBackground: true });
  await browser.close();
})();

Also I checked Chromium options, but I don't find useful one for that.

@dhruv-m-patel

This comment has been minimized.

Copy link

@dhruv-m-patel dhruv-m-patel commented Dec 21, 2017

I faced this issue a while ago, hosting images on an s3 bucket and using that image worked fine.

+1 for local resource support request though when running puppeteer inside docker 👍

@ebidel

This comment has been minimized.

Copy link
Contributor

@ebidel ebidel commented Dec 21, 2017

Dupe of: #1472

As part of the docker image/script, you could also start a web server to serve the image. Basically run @yujiosaka's example :)

You could also write the file dynamically, navigate to it, and generate the pdf. This worked for me, assuming logo.jpg is in the same dir as your script:

const puppeteer = require('puppeteer');
const fs = require('fs');
const {promisify} = require('util');

const OUT_FILE = 'myfile.html';

(async() => {
  await promisify(fs.writeFile)(OUT_FILE, `
    <html>
      <h3>hello image!</h3>
      <img src="logo.jpg">
    </html>
  `);

  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto(`file://${process.cwd()}/${OUT_FILE}`);
  await page.pdf({path: 'page.pdf'});

  promisify(fs.unlink)(OUT_FILE); // cleanup

  await browser.close();
})();

You'll probably need the --allow-file-access-from-files and --enable-local-file-accesses flags if you're loading other types of resources, but image load fine over file://.

@acgrama

This comment has been minimized.

Copy link
Author

@acgrama acgrama commented Dec 22, 2017

@yujiosaka @ebidel Thank you both for the suggestions! Yeah, I was lazily hoping we could reuse as much of our current (PhantomJS-based) code as possible ;-)
But it should be feasible to change our current approach without too much effort.

@aslushnikov aslushnikov closed this Jan 4, 2018
@tuxalin

This comment has been minimized.

Copy link

@tuxalin tuxalin commented Apr 16, 2018

I've stumbled with this issue too, another solution would be to use data streams for the img src, eg:

function base64_encode(file) {
var bitmap = fs.readFileSync(file);
return new Buffer(bitmap).toString('base64');
}
img.src = 'data:image/png;base64,' + base64_encode(imagePath);

randytarampi added a commit to randytarampi/me that referenced this issue Aug 16, 2018
An easy to implement suggestion from GoogleChrome/puppeteer#1643 (comment).
randytarampi added a commit to randytarampi/me.resume that referenced this issue Aug 17, 2018
randytarampi added a commit to randytarampi/me.resume that referenced this issue Aug 17, 2018
randytarampi added a commit to randytarampi/me.resume that referenced this issue Aug 17, 2018
randytarampi added a commit to randytarampi/me.resume that referenced this issue Aug 18, 2018
randytarampi added a commit to randytarampi/me.resume that referenced this issue Aug 18, 2018
@bogacg

This comment has been minimized.

Copy link

@bogacg bogacg commented Aug 18, 2018

Puppeteer is officially supported under Google Cloud Functions, therefore I believe it would be correct thing to have an option to use local files without need of an extra server or temporarily saving html somewhere.

randytarampi added a commit to randytarampi/me.resume that referenced this issue Aug 19, 2018
randytarampi added a commit to randytarampi/me that referenced this issue Aug 19, 2018
@JaapWeijland

This comment has been minimized.

Copy link

@JaapWeijland JaapWeijland commented Sep 10, 2018

I am using Puppeteer for PDF generation on GCF too. There should be a way to embed an image without spinning up a server.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
8 participants
You can’t perform that action at this time.