• Stars
    star
    126
  • Rank 284,543 (Top 6 %)
  • Language
    JavaScript
  • Created over 10 years ago
  • Updated about 7 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Render a webpage and get the image/pdf as a stream.

phantom-render-stream

Render a webpage and get the image as a stream.

npm install phantom-render-stream

Build Status

It uses a pool of phantom processes so it doesn't need to spawn a new process for each website. New requests are added to the pool member with the shortest queue length.

Synopsis

This module depends on the phantomjs-prebuilt module, which will install PhantomJS for you if you don't already have it.

var phantom = require('phantom-render-stream');
var fs = require('fs');

var render = phantom();

// render a website url

render('http://example.com/my-site')
  .pipe(fs.createWriteStream('out.png'));

// or as a transform stream

fs.createReadStream('some-html-file.html')
  .pipe(render())
  .pipe(fs.createWriteStream('out.png'))

You can also pass some options:

var render = phantom({
  pool        : 5,           // Change the pool size. Defaults to 1
  timeout     : 1000,        // Set a render timeout in milliseconds. Defaults to 30 seconds.
  tmp         : '/tmp',      // Set the tmp where tmp data is stored when communicating with the phantom process.
                             //   Defaults to /tmp if it exists, or os.tmpDir()
  format      : 'jpeg',      // The default output format. Defaults to png
  quality     : 100,         // The default image quality. Defaults to 100. Only relevant for jpeg format.
  width       : 1280,        // Changes the width size. Defaults to 1280
  height      : 800,         // Changes the height size. Defaults to 960
  zoomFactor  : 1.5,         // Changes the scaling factor. Defaults to 1
  paperFormat : 'A4',        // Defaults to A4. Also supported: 'A3', 'A4', 'A5', 'Legal', 'Letter', 'Tabloid'.
  orientation : 'portrait',  // Defaults to portrait. 'landscape' is also valid
  margin      : '0cm',       // Defaults to 0cm. Supported dimension units are: 'mm', 'cm', 'in', 'px'. No unit means 'px'.
  userAgent   : '',          // No default.
  headers     : {Foo:'bar'}, // Additional headers to send with each upstream HTTP request
  paperSize:  : null,        // Defaults to the paper format, orientation, and margin.
  crop        : false,       // Defaults to false. Set to true or {top:5, left:5} to add margin
  printMedia  : false,       // Defaults to false. Force the use of a print stylesheet.
  maxErrors   : 3,           // Number errors phantom process is allowed to throw before killing it. Defaults to 3.
  expects     : 'something', // No default. Do not render until window.renderable is set to 'something'
  retries     : 1,           // How many times to try a render before giving up. Defaults to 1.
  phantomFlags: ['--ignore-ssl-errors=true'] // Defaults to []. Command line flags passed to PhantomJS
  maxRenders  : 500,         // How many renders can a phantom process make before being restarted. Defaults to 500
  listener    : '0.0.0.0',   // Specify the interface to bind (ie 127.0.0.1)

  injectJs    : ['./includes/my-polyfill.js'] // Array of paths to polyfill components or external scripts that will be injected when the page is initialized
});

Or override the options for each render stream

render(myUrl, {format:'jpeg', quality: 100, width: 1280, height: 960}).pipe(...)

Supported output formats

We support the output formats that PhantomJS's render method supports. At the time of this writing these are:

  • png
  • gif
  • jpg
  • pdf

Example

Since the interface is just a stream you can pipe the web site anywhere! Try installing picture-tube and run the following example

var phantom = require('phantom-render-stream');
var pictureTube = require('picture-tube');
var render = phantom();

render('http://google.com')
  .pipe(pictureTube())
  .pipe(process.stdout);

Deferred render

If you need your page to do something before phantom renders it you just need to immediately set window.renderable to false. If that is set when the page is opened the module will wait for window.renderable to be set to true and when this happens the render will occur.

Here is an example to illustrate it better.

<!DOCTYPE HTML>
<html lang="en">
<head>
  ...
  <script type="text/javascript">window.renderable = false</script>
  <meta charset="UTF-8">
  <title></title>
</head>
<body>

</body>
...
<script type="text/javascript">
  doSomeAjaxLoading(function() {
    doSomeRendering();
    window.renderable = true;
  })
</script>
</html>

Adding Cookies

You can add any special cookies at render time. For format, see http://phantomjs.org/api/webpage/method/add-cookie.html. Example:

var render = phantom({
  pool: 5,
  format: 'pdf'
  // other opts
});

render('http://somewhere.com', {
  cookies: [{
    'name'     : 'Valid-Cookie-Name',   /* required property */
    'value'    : 'Valid-Cookie-Value',  /* required property */
    'domain'   : 'localhost',
    'path'     : '/foo',                /* required property */
    'httponly' : true,
    'secure'   : false,
    'expires'  : (new Date()).getTime() + (1000 * 60 * 60)   /* <-- expires in 1 hour */
  }]
}).pipe(somewhereElse);

That will use that cookie for that particular render job. You probably want to set the expires property to something fairly short, as there may not be a guarantee that a pooled phantom process won't pick up the cookie for a particular render job, and you may want that session to only be valid for an individual job run.

Injecting JavaScript

Sometimes you need to inject polyfills, e.g. PhantomJS Date.parse is broken. You can add paths to local files to polyfill broken / missing features of PhantomJS using the opts.injectJs property. Example:

var phantom = render({
  injectJs: ['./includes/my-date-polyfill.js']
});

Obviously, make sure the path './includes/my-date-polyfill.js' is resolvable from the project root, or pass in an absolute path. When the page is initialized, any scripts you listed there will be injected before any rendering happens.

Header and footer (PDF Only)

For PDF Files only - Header and Footer can be added by adding a global PhantomJSPrinting object to the html you are rendering. Example:

<script type="text/javascript">
  var PhantomJSPrinting = {
    header: {
      height: "1cm",
      contents: function(pageNum, numPages) { return pageNum + "/" + numPages; }
    },
    footer: {
      height: "1cm",
      contents: function(pageNum, numPages) { return pageNum + "/" + numPages; }
    }
  };
</script>

## Disable Javascript
For security reasons it could be necessary to disable javascript:

```javascript
var phantom = render({
  javascriptEnabled: false
});

Request whitelist

For security reasons you probably would filter the outgoing requests:

var phantom = render({
  requestWhitelist: [
    '^http://localhost/assets/.*'
  ]
});

Extra Dependencies

For rendering, PhantomJS requires the fontconfig library, which may be missing if you're using Ubuntu Server. To install on Ubuntu:

sudo apt-get install libfontconfig

Troubleshooting

Render stream emits "log" event with useful debug details coming from onError (JS error), onConsoleMessage, onResourceError, onResourceTimeout webpage hooks.

var render = phantom();

render('http://somewhere.com')
  .on('log', function(log) {
    // {type: 'error', data: {msg: 'ReferenceError: Can\'t find variable: a', trace: [..]}}
  })
  .pipe(res);

Also, some additional debugging output may be enabled by running your app with a DEBUG environment variable set as follows:

DEBUG=phantom-render-stream  node ./your-script.js

If you are getting undefined error codes and responses when attempting to render, it's likely a connection issue of some sort. If the URL uses SSL, adding --ignore-ssl-errors=true to phantomFlags may help. You also try adding --debug=true to the phantomFlags array.

See Also

  • wkhtmltopdf is a Node module that uses wkhtmltopdf to convert HTML to PDF. It is similar in that it uses Webkit and produces output as a stream, and different in that it doesn't use PhantomJS. Also, wkhtmotopdf only supports PDF output.
  • nightmare uses Electron which is similar to PhantomJS but more modern and may render faster. There are different output options to produce PNGs or PDFs. There's sample code for generating a PDF that's returned as a stream.

License

MIT

More Repositories

1

tcp-spy

TCP Proxy server for debugging.
JavaScript
64
star
2

fully-connected-topology

Node module to create a network with a fully connected topology.
JavaScript
58
star
3

varint.c

Varint C library.
C
37
star
4

after-all

Call several asynchronous functions and invoke a callback 'after all' of them are done.
JavaScript
29
star
5

choppa

Node.js module to chop a stream into specified size chunks.
JavaScript
17
star
6

send-json

Node.js module to send objects as JSON over http.
JavaScript
15
star
7

io-install

Install me to install io.js
Shell
14
star
8

length-prefixed-message

Node.js module that reads and writes binary length prefixed messages.
JavaScript
12
star
9

submongojs

sub-sections of mongodb databases with mongojs
JavaScript
10
star
10

handlebars-stream

Through stream that renders objects with handlebars templates.
JavaScript
10
star
11

bfc

A brainfuck compiler written in go.
Go
10
star
12

onstop

Detect when a recurring event has stopped happening, given a time interval.
JavaScript
10
star
13

after-sequence

Run several async functions and run a callback when they are gone.
JavaScript
9
star
14

request-payload

Node.js module to get the payload of an HTTP request.
JavaScript
9
star
15

lispjs

A small lisp-like language that compiles to JavaScript
JavaScript
9
star
16

shamir3pass

Shamir three pass protocol encryption function in Go.
Go
8
star
17

parse-mongo-url

Parse mongodb connection strings.
JavaScript
7
star
18

mongo-write-stream

Node.js module that creates a writable object stream to a mongodb collection.
JavaScript
6
star
19

tcc

Go bindings for libtcc.
Go
6
star
20

onstoptyping

Fire an event when a user stops typing on an input or textarea.
JavaScript
6
star
21

typesafe-event-emitter

TypeScript type declarations to make event emitters more type safe.
5
star
22

receive-json

Node.js module to receive JSON over an HTTP request.
JavaScript
5
star
23

localshare

Desktop app to share files on a local network.
Go
5
star
24

piechart

An HTML canvas piechart.
JavaScript
4
star
25

each-series

Asynchronously iterate an array as a series in Node.js
JavaScript
4
star
26

print-dom-element

npm module to print an HTML element. To be used with browserify.
JavaScript
3
star
27

ssh-sign

Browser extension to store ssh keys and sign messages with them.
TypeScript
3
star
28

jquery-ghost

A fast, lightweight "ghost text" plugin for jQuery.
JavaScript
3
star
29

vim-close-duplicate-tabs

Vim plugin for closing duplicate tabs
Vim Script
3
star
30

vejr

CLI program that shows the weather forecast
Go
2
star
31

noted

A note taking app. Buit with node.js
CSS
2
star
32

mongoexpressgen

Small generators for APIs and CRUDS with Express and MongoDB
JavaScript
2
star
33

spyglass

Web interface for hms
JavaScript
2
star
34

midi-editor

JavaScript
1
star
35

persistent-timeout

Set timeouts that survive restarts, persisted with leveldb.
JavaScript
1
star
36

minilisp

Super small Lisp compiler. Mainly done to translate code with closures to C.
Go
1
star
37

to-mongodb-core

Gets the underlying mongodb-core instance in the passed mongodb-native or mongojs instance.
JavaScript
1
star