Go ChromeDP ignores any external or internal css during printing to pdf and uses only those, that in html file ONLY

516 views Asked by At

Go ChromeDP not using any css either internal or external styles (only those, that was written in html, not other file). I using method

page.SetDocumentContent(frameTree.Frame.ID, string(buf.Bytes())).Do(ctx)

to add html file to chromedp, and

buf, _, err: = page.PrintToPDF().Do(ctx)
if err != nil {
    return err
}
_, err = outputBuf.Write(buf)
if err != nil {
    return err
}

to print to pdf, but pdf in result not styled (even with external css fileserver). I tried to add it with page.GetResourceTree().Do(ctx) + css.CreateStyleSheet(resourceTree.Frame.ID).Do(ctx) +

css.SetStyleSheetText(stylesheet, `.c {
     color: red;
     font-size: 30px;
     background-color: aqua;
}
`).Do(ctx)

and it worked, but it sad to use it every time I want generate pdf, especially in my case, because I am using html from html/template. Maybe there are easy way to add external css into single html file? What do you think?

Thanks for any answer

Bohdan

I want to convert go template with external css, images and font into pdf using chromedp, but it ignored anything beyond main html file.

1

There are 1 answers

1
Zeke Lu On BEST ANSWER

Please note that external resources take time to load. You should wait for them to be loaded. When the page is ready, the Page.loadEventFired event is raised. So we can wait for this event and print the page afterward. See the demo below:

package main

import (
    "context"
    "fmt"
    "log"
    "net/http"
    "net/http/httptest"
    "os"
    "sync"
    "time"

    "github.com/chromedp/cdproto/page"
    "github.com/chromedp/chromedp"
)

func main() {
    ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // Simulate a network latency.
        time.Sleep(2 * time.Second)
        w.Header().Set("Content-Type", "text/css")
        fmt.Fprint(w, `h1 {font-size: 100pt; color: red;}`)
    }))
    defer ts.Close()

    ctx, cancel := chromedp.NewContext(context.Background())
    defer cancel()

    // construct your html
    html := `<html>
    <head>
        <link rel="stylesheet" href="%s/style.css">
    </head>
    <body>
        <h1> Hello World! </h1>
    </body>
</html>
`

    var wg sync.WaitGroup
    wg.Add(1)
    if err := chromedp.Run(ctx,
        chromedp.Navigate("about:blank"),
        // setup the listener to listen for the page.EventLoadEventFired
        chromedp.ActionFunc(func(ctx context.Context) error {
            lctx, cancel := context.WithCancel(ctx)
            chromedp.ListenTarget(lctx, func(ev interface{}) {
                if _, ok := ev.(*page.EventLoadEventFired); ok {
                    wg.Done()
                    // remove the event listener
                    cancel()
                }
            })
            return nil
        }),
        chromedp.ActionFunc(func(ctx context.Context) error {
            frameTree, err := page.GetFrameTree().Do(ctx)
            if err != nil {
                return err
            }
            return page.SetDocumentContent(frameTree.Frame.ID, fmt.Sprintf(html, ts.URL)).Do(ctx)
        }),
        // wait for page.EventLoadEventFired
        chromedp.ActionFunc(func(ctx context.Context) error {
            wg.Wait()
            return nil
        }),
        chromedp.ActionFunc(func(ctx context.Context) error {
            buf, _, err := page.PrintToPDF().Do(ctx)
            if err != nil {
                return err
            }
            return os.WriteFile("sample.pdf", buf, 0644)
        }),
    ); err != nil {
        log.Fatal(err)
    }

    log.Println("done!")
}

Reference: https://github.com/chromedp/chromedp/issues/1152.