Skip to content
This repository was archived by the owner on Nov 24, 2018. It is now read-only.

pdf() API #84

Merged
merged 7 commits into from
Aug 2, 2017
Merged

pdf() API #84

merged 7 commits into from
Aug 2, 2017

Conversation

seangransee
Copy link
Contributor

@seangransee seangransee commented Jul 28, 2017

Page.printToPDF() documentation:
https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-printToPDF

You can test this the same way as the screenshot example:

const { Chromeless } = require('chromeless')

async function run() {
  const chromeless = new Chromeless()

  const pdf = await chromeless
    .goto('https://www.google.com')
    .type('chromeless', 'input[name="q"]')
    .press(13)
    .wait('#resultStats')
    .pdf({landscape: true})

  console.log(pdf) // prints local file path or S3 url

  await chromeless.end()
}

run().catch(console.error.bind(console))

@seangransee
Copy link
Contributor Author

seangransee commented Jul 28, 2017

In src/chrome/local-runtime.ts, the new returnPDF() function shares most of its code with returnScreenshot(). Some abstraction can be done in the future to avoid code-duplication.

EDIT: There's now an open issue for this at #113.

Copy link
Contributor

@joelgriffith joelgriffith left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be great to see the const screenshot fix, but otherwise looks good to me!

docs/api.md Outdated
__Example__

```js
const screenshot = await chromeless
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you mean const pdf here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep. Sloppy copy/pasting on my part.


// write to `/tmp` instead
else {
const filePath = `/tmp/${cuid()}.pdf`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should look into using a module that helps with tmp folders. This file tmp doesn't exist in windows systems

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With node 4 and above os.tmpdir() should do the trick.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be addressed as part of #113.

Bucket: process.env['CHROMELESS_S3_BUCKET_NAME'],
Key: s3Path,
ContentType: 'application/pdf',
ACL: 'public-read',

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably this should be configurable as well with an env variable?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be addressed as part of #113.

Key: s3Path,
ContentType: 'application/pdf',
ACL: 'public-read',
Body: new Buffer(data, 'base64'),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should also use Buffer.from() as new Buffer() is deprecated API in newer Node.js versions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be addressed as part of #113.

@seangransee
Copy link
Contributor Author

@joelgriffith I fixed the documentation error in f764f4e.

@seangransee
Copy link
Contributor Author

As for @lirantal's comments, I figure it's better to keep the implementation of returnPDF() as similar as possible to returnScreenshot() for now to make it easier to abstract out a file creation function in a future PR.

@seangransee seangransee mentioned this pull request Jul 31, 2017
10 tasks

// check if S3 configured
if (process.env['CHROMELESS_S3_BUCKET_NAME'] && process.env['CHROMELESS_S3_BUCKET_URL']) {
const s3Path = `${cuid()}.pdf`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we save both screenshots and pdfs to the same bucked and to the same folder.

What do you think of putting them like bucket/screenshots/${cuid()}.png and bucket/pdfs/${cuid()}.pdf ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be left alone in this pull request, and this can be addressed as part of #113.

src/util.ts Outdated
export async function pdf(client: Client): Promise<string> {
const {Page} = client

const pdf = await Page.printToPDF()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will it be hard to allow user pass options here? In particular landscape may be useful

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually tried to do that before I opened this PR, and I couldn't get it to work. Even when I hard-coded landscape: true here, it would save a portrait PDF.

Try changing line 310 to the following:

const pdf = await Page.printToPDF({landscape: true})

It does not appear to change the output. I tried messing around with options such as scale and paperHeight, and that did not appear to affect anything either.

I'm not quite sure why passing in an options object has no effect here.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The options do work at the CDP/Chrome level, so there may be an issue somewhere else. Perhaps the options aren't being passed along correctly—also the initial support for printing to pdf in headless-chrome was somewhat limited—are you trying in a recent version of Chrome (or via the Proxy?)

Page.printToPDF({
  landscape: false,
  displayHeaderFooter: false,
  printBackground: true,
  scale: 1,
  paperWidth: 8.27, // aka A4
  paperHeight: 11.69, // aka A4
  marginTop: 0,
  marginBottom: 0,
  marginLeft: 0,
  marginRight: 0,
  pageRanges: '',
})

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Passing these options did not work when I was using Chrome 59, but they work now that I've upgraded to Chrome 60. I'm on macOS Sierra.

Now that I know that this works, I'll implement the ability for the user to pass in these options.

@seangransee seangransee changed the title implement pdf API that calls Page.printToPDF() pdf() API Jul 31, 2017
@kimmobrunfeldt
Copy link

I'm really interested in the PDF feature. Is there something I could help with or would there be too many devs poking at the same feature?

@adieuadieu
Copy link
Collaborator

Hi @kimmobrunfeldt It looks like @seangransee has nearly finished the feature—let's give him a bit more time to wrap it up.

@seangransee
Copy link
Contributor Author

seangransee commented Aug 1, 2017

I'll try to get to this today.

@kimmobrunfeldt, if you urgently need it in the meantime, the feature is totally usable in this branch. The only thing missing is the ability to pass in options, so right now the PDF will be generated using the defaults.

@seangransee
Copy link
Contributor Author

@vladgolubev @adieuadieu The API can now optionally accept an options object, as discussed in #84 (comment).

It's implemented in 67e72ef. Feel free to take a look.

Copy link
Contributor

@joelgriffith joelgriffith left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good, we should follow-up with the changes needed in #113

@seangransee
Copy link
Contributor Author

seangransee commented Aug 1, 2017

In case anyone's interested in seeing some sample PDFs this generates:

chromeless
  .goto('https://www.google.com')
  .type('chromeless', 'input[name="q"]')
  .press(13)
  .wait('#resultStats')
  .pdf()

default.pdf


chromeless
  .goto('https://www.google.com')
  .type('chromeless', 'input[name="q"]')
  .press(13)
  .wait('#resultStats')
  .pdf({displayHeaderFooter: true, landscape: true})

header_footer_landscape.pdf

@joelgriffith
Copy link
Contributor

🔥 once we get another maintainer approval we'll merge this (hopefully get it staged for 1.1.0 release)

src/types.ts Outdated
@@ -82,6 +82,10 @@ export type Command =
type: 'returnHtml'
}
| {
type: 'returnPDF',
options: object
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you provide some type definitions here instead of object?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@schickling Take a look at 7db33a1. I'm not very familiar with TypeScript, so feel free to correct any mistakes I may have made.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! :)

docs/api.md Outdated
@@ -392,9 +392,24 @@ console.log(screenshot) // prints local file path or S3 URL

<a name="api-pdf" />

### pdf() - Not implemented yet
### pdf(options?: object) - Chromeless<string>
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be great if object was a concretly documented type

@joelgriffith joelgriffith merged commit 5b14c55 into schickling:master Aug 2, 2017
@gorangajic
Copy link

Using examples from the top and running on the master, I am getting PrintToPDF is not implemented anyone knows why?

@criticalbh
Copy link
Contributor

PrintToPDF is internal CDT method. To print to pdf use pdf()

@seangransee
Copy link
Contributor Author

@gorangajic is correct. I'm getting that error as well when using pdf(). It was definitely working in the past. (And I have the PDFs to prove it 😄)

Maybe the switch to chrome-launcher has something to do with this error? I'm not entirely sure.

@seangransee
Copy link
Contributor Author

@gorangajic, take a look at #146. The error goes away for me when I manually start chrome in headless mode before running the example.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants