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

add functions to export page or svg to pdf and png formats #22

Merged
merged 1 commit into from Dec 2, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
55 changes: 55 additions & 0 deletions chrome.go
Expand Up @@ -438,6 +438,61 @@ func (c *chrome) bounds() (Bounds, error) {
return bounds.Bounds, err
}

func (c *chrome) pdf(width, height int) ([]byte, error) {
result, err := c.send("Page.printToPDF", h{
"paperWidth": float32(width) / 96,
"paperHeight": float32(height) / 96,
})
if err != nil {
return nil, err
}
pdf := struct {
Data []byte `json:"data"`
}{}
err = json.Unmarshal(result, &pdf)
return pdf.Data, err
}

func (c *chrome) png(x, y, width, height int, bg uint32, scale float32) ([]byte, error) {
if x == 0 && y == 0 && width == 0 && height == 0 {
// By default either use SVG size if it's an SVG, or use A4 page size
bounds, err := c.eval(`document.rootElement ? [document.rootElement.x.baseVal.value, document.rootElement.y.baseVal.value, document.rootElement.width.baseVal.value, document.rootElement.height.baseVal.value] : [0,0,816,1056]`)
if err != nil {
return nil, err
}
rect := make([]int, 4)
if err := json.Unmarshal(bounds, &rect); err != nil {
return nil, err
}
x, y, width, height = rect[0], rect[1], rect[2], rect[3]
}

_, err := c.send("Emulation.setDefaultBackgroundColorOverride", h{
"color": h{
"r": (bg >> 16) & 0xff,
"g": (bg >> 8) & 0xff,
"b": bg & 0xff,
"a": (bg >> 24) & 0xff,
},
})
if err != nil {
return nil, err
}
result, err := c.send("Page.captureScreenshot", h{
"clip": h{
"x": x, "y": y, "width": width, "height": height, "scale": scale,
},
})
if err != nil {
return nil, err
}
pdf := struct {
Data []byte `json:"data"`
}{}
err = json.Unmarshal(result, &pdf)
return pdf.Data, err
}

func (c *chrome) kill() error {
if c.ws != nil {
if err := c.ws.Close(); err != nil {
Expand Down
56 changes: 56 additions & 0 deletions export.go
@@ -0,0 +1,56 @@
package lorca

import (
"fmt"
"io/ioutil"
"os"
)

const (
// PageA4Width is a width of an A4 page in pixels at 96dpi
PageA4Width = 816
// PageA4Height is a height of an A4 page in pixels at 96dpi
PageA4Height = 1056
)

// PDF converts a given URL (may be a local file) to a PDF file. Script is
// evaluated before the page is printed to PDF, you may modify the contents of
// the page there of wait until the page is fully rendered. Width and height
// are page bounds in pixels. PDF by default uses 96dpi density. For A4 page
// you may use PageA4Width and PageA4Height constants.
func PDF(url, script string, width, height int) ([]byte, error) {
return doHeadless(url, func(c *chrome) ([]byte, error) {
c.eval(script)
return c.pdf(width, height)
})
}

// PNG converts a given URL (may be a local file) to a PNG image. Script is
// evaluated before the "screenshot" is taken, so you can modify the contents
// of a URL there. Image bounds are provides in pixels. Background is in ARGB
// format, the default value of zero keeps the background transparent. Scale
// allows zooming the page in and out.
//
// This function is most convenient to convert SVG to PNG of different sizes,
// for example when preparing Lorca app icons.
func PNG(url, script string, x, y, width, height int, bg uint32, scale float32) ([]byte, error) {
return doHeadless(url, func(c *chrome) ([]byte, error) {
c.eval(script)
return c.png(x, y, width, height, bg, scale)
})
}

func doHeadless(url string, f func(c *chrome) ([]byte, error)) ([]byte, error) {
dir, err := ioutil.TempDir("", "lorca")
if err != nil {
return nil, err
}
defer os.RemoveAll(dir)
args := append(defaultChromeArgs, fmt.Sprintf("--user-data-dir=%s", dir), "--remote-debugging-port=0", "--headless", url)
chrome, err := newChromeWithArgs(ChromeExecutable(), args...)
if err != nil {
return nil, err
}
defer chrome.kill()
return f(chrome)
}