1

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 Answers1

4

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.

Zeke Lu
  • 6,349
  • 1
  • 17
  • 23
  • thank you very much, you are my savior :D I found similar code but it not worked for me, I think i just wrote it wrong, but you really helped thx :) – Bohdan Myronchuk Mar 29 '23 at 09:15