chromedp is a faster and simpler Go library that supports the Chrome DevTools Protocol, it is one of the most popular headless
browser libraries, you can use it to do a lot of tasks that can only be performed through the browser, such as web screenshots, web rendering tests, downloading videos, simulating login, etc. Today Today I’m going to introduce a useful and simple feature: generating a pdf screenshot of a web page, for more examples you can see the official example chromedp/examples.
First of all, you need to have chrome
installed so that the chromedp
library can call chrome
to perform tasks (actions) via the cdp
protocol.
Generate pdf for web pages
First, you need to introduce the chromedp library.
1
|
go get -u github.com/chromedp/chromedp
|
Then, you can perform a series of actions through `chromedp.Run, such as our example is to first navigate to a page, and then generate the page as a pdf:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
// Generate task list
func printToPDF(urlstr string, res *[]byte) chromedp.Tasks {
return chromedp.Tasks{
chromedp.Navigate(urlstr), // Browse the specified page
chromedp.ActionFunc(func(ctx context.Context) error {
buf, _, err := page.PrintToPDF().WithPrintBackground(true).Do(ctx) // PrintToPDF through cdp implementation
if err != nil {
return err
}
*res = buf
return nil
}),
}
}
|
ActionFunc
is a convenience method to execute a function as an Action, just like the standard library http.Handler
and `http. Because here we want to implement the logic is relatively simple, so through a function to achieve it.
page.PrintToPDF ()
is to define the implementation of the output pdf of some parameters, you can set some additional parameters, these parameters include.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
type PrintToPDFParams struct {
Landscape bool `json:"landscape,omitempty"` // Print in landscape orientation. Default is false.
DisplayHeaderFooter bool `json:"displayHeaderFooter,omitempty"` // Print header and footer. default false.
PrintBackground bool `json:"printBackground,omitempty"` // Print the background image. Default is false.
Scale float64 `json:"scale,omitempty"` // Scaling factor. Default is 1.
PaperWidth float64 `json:"paperWidth,omitempty"` // Page width (inches). Default 8.5 inches (US Letter standard size, not much different from A4 paper).
PaperHeight float64 `json:"paperHeight,omitempty"` // Page height (inches). Default 11 inches (Letter standard size).
MarginTop float64 `json:"marginTop"` // Top margin (inch). Default 1cm (about 0.4 inches).
MarginBottom float64 `json:"marginBottom"` // Bottom Margin (inch). Default 1cm (about 0.4 inches).
MarginLeft float64 `json:"marginLeft"` // Left margin (inch). Default 1cm (about 0.4 inches).
MarginRight float64 `json:"marginRight"` // Right margin (inch). Default 1cm (about 0.4 inches).
PageRanges string `json:"pageRanges,omitempty"` // The page number to print, for example, '1-5, 8, 11-13'. Default is empty, print all.
IgnoreInvalidPageRanges bool `json:"ignoreInvalidPageRanges,omitempty"` // Whether to ignore illegal page ranges. Default is false.
HeaderTemplate string `json:"headerTemplate,omitempty"` // HTML template head.
FooterTemplate string `json:"footerTemplate,omitempty"` // HTML template footer.
PreferCSSPageSize bool `json:"preferCSSPageSize,omitempty"` // Is the css-defined page size preferred? Default false, will automatically adapt.
TransferMode PrintToPDFTransferMode `json:"transferMode,omitempty"` // Return to stream
}
|
Here our example does not do additional settings, only adjust the print background image parameters, of course, you in order to print a beautiful pdf words, you can adjust the parameters here, more suitable for reading and printing.
Do through the cdp protocol to perform printing and return the results.
The main logic is complete, the next step is to perform these tasks.
First to create a chromedp
of the Context
:
1
|
ctx, cancel := chromedp.NewContext(context.Background())
|
Then just call chromedp.Run to execute the task:
1
2
3
|
if err := chromedp.Run(ctx, printToPDF(`https://colobu.com/`, &buf)); err != nil {
log.Fatal(err)
}
|
Finally, write the pdf to the file, complete.
1
2
3
|
if err := ioutil.WriteFile("colobu.pdf", buf, 0644); err != nil {
log.Fatal(err)
}
|
The effect of the generated pdf is as follows:
The complete code is as follows:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
package main
import (
"context"
"io/ioutil"
"log"
"github.com/chromedp/cdproto/page"
"github.com/chromedp/chromedp"
)
func main() {
// Create context
ctx, cancel := chromedp.NewContext(context.Background())
defer cancel()
// Generate pdf
var buf []byte
if err := chromedp.Run(ctx, printToPDF(`https://colobu.com/`, &buf)); err != nil {
log.Fatal(err)
}
if err := ioutil.WriteFile("colobu.pdf", buf, 0644); err != nil {
log.Fatal(err)
}
}
// Generate task list
func printToPDF(urlstr string, res *[]byte) chromedp.Tasks {
return chromedp.Tasks{
chromedp.Navigate(urlstr), // Browse the specified page
chromedp.ActionFunc(func(ctx context.Context) error {
buf, _, err := page.PrintToPDF().WithPrintBackground(false).Do(ctx) // PrintToPDF through cdp implementation
if err != nil {
return err
}
*res = buf
return nil
}),
}
}
|
Generate beautiful charts
echarts is a very famous charting library contributed by baidu, which can generate huge beautiful charts for web pages via js to display data. go language has some “toy” charting libraries, but there is no real icon library, so some people use echarts to generate a web page to display data, this library is go-echarts.
But, after all, this is the convoluted way, and the final data generated is a web page.
Since we just through chromedp can generate pdf, then is it also possible to screenshot, the go-echarts generated charts screenshot into a Go Image object? Let’s give it a try.
First, we first use go-echarts to generate a chart, and save it as a html page:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
func generateEcharts() {
bar := charts.NewBar()
// set some global options like Title/Legend/ToolTip or anything else
bar.SetGlobalOptions(charts.WithTitleOpts(opts.Title{
Title: "生成一个漂亮的bar图表",
Subtitle: "我要得到它的灵魂",
}))
// Put data into instance
bar.SetXAxis([]string{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}).
AddSeries("Category A", generateBarItems()).
AddSeries("Category B", generateBarItems())
// Where the magic happens
f, _ := os.Create("bar.html")
bar.Render(f)
}
func generateBarItems() []opts.BarData {
items := make([]opts.BarData, 0)
for i := 0; i < 7; i++ {
items = append(items, opts.BarData{Value: rand.Intn(300)})
}
return items
}
|
The next step is chromedp’s work, browsing this local page and taking screenshots:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
// Generate echarts pages
generateEcharts()
// create chromedp context
ctx, cancel := chromedp.NewContext(
context.Background(),
chromedp.WithDebugf(log.Printf),
)
defer cancel()
// Define tasks
elementScreenshot := func(urlstr, sel string, res *[]byte) chromedp.Tasks {
return chromedp.Tasks{
chromedp.Navigate(urlstr),
chromedp.Screenshot(sel, res, chromedp.NodeVisible),
}
}
// Generate screenshots
var buf []byte
barFile, _ := filepath.Abs("./bar.html")
if err := chromedp.Run(ctx, elementScreenshot(`file://`+barFile, `canvas`, &buf)); err != nil {
log.Fatal(err)
}
// Writing screenshots to a file
if err := ioutil.WriteFile("bar.png", buf, 0o644); err != nil {
log.Fatal(err)
}
|
Eventually, a screenshot is generated. You can generate this screenshot as an Image object or save it to a file. Here we don’t do any additional processing, so we save it to a file. The generated file is as follows:
Of course, there are many other things you can do with chromedp’s print and screenshot functions, such as converting epub eBooks to pdf format, grafana screenshot alarms, etc.
Reference https://colobu.com/2021/05/05/generate-pdf-for-a-web-page-by-using-chromedp/