2022-11-17 01:41:53 +00:00
|
|
|
package png
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"encoding/base64"
|
|
|
|
|
"errors"
|
|
|
|
|
"fmt"
|
|
|
|
|
"os"
|
|
|
|
|
"os/exec"
|
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
|
|
_ "embed"
|
|
|
|
|
|
|
|
|
|
"github.com/playwright-community/playwright-go"
|
2022-11-17 19:25:07 +00:00
|
|
|
"oss.terrastruct.com/d2/lib/xmain"
|
2022-11-17 01:41:53 +00:00
|
|
|
)
|
|
|
|
|
|
2022-11-17 19:25:07 +00:00
|
|
|
type Playwright struct {
|
|
|
|
|
PW *playwright.Playwright
|
|
|
|
|
Browser playwright.Browser
|
|
|
|
|
BrowserContext playwright.BrowserContext
|
|
|
|
|
Page playwright.Page
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (pw *Playwright) RestartBrowser() (newPW Playwright, err error) {
|
|
|
|
|
if err = pw.BrowserContext.Close(); err != nil {
|
|
|
|
|
return Playwright{}, err
|
|
|
|
|
}
|
|
|
|
|
if err = pw.Browser.Close(); err != nil {
|
|
|
|
|
return Playwright{}, err
|
|
|
|
|
}
|
|
|
|
|
browser, err := pw.PW.Chromium.Launch()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return Playwright{}, err
|
|
|
|
|
}
|
|
|
|
|
context, err := browser.NewContext()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return Playwright{}, err
|
|
|
|
|
}
|
|
|
|
|
page, err := context.NewPage()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return Playwright{}, err
|
|
|
|
|
}
|
|
|
|
|
return Playwright{
|
|
|
|
|
PW: pw.PW,
|
|
|
|
|
Browser: browser,
|
|
|
|
|
BrowserContext: context,
|
|
|
|
|
Page: page,
|
|
|
|
|
}, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (pw *Playwright) Cleanup(isWatch bool) (err error) {
|
|
|
|
|
if !isWatch {
|
|
|
|
|
if err = pw.BrowserContext.Close(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if err = pw.Browser.Close(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if err = pw.PW.Stop(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func InitPlaywright() (Playwright, error) {
|
2022-11-17 01:41:53 +00:00
|
|
|
// check if playwright driver/browsers are installed and up to date
|
|
|
|
|
// https://github.com/playwright-community/playwright-go/blob/8e8f670b5fa7ba5365ae4bfc123fea4aac359763/run.go#L64.
|
|
|
|
|
driver, err := playwright.NewDriver(&playwright.RunOptions{})
|
|
|
|
|
if err != nil {
|
2022-11-17 19:25:07 +00:00
|
|
|
return Playwright{}, err
|
2022-11-17 01:41:53 +00:00
|
|
|
}
|
|
|
|
|
if _, err := os.Stat(driver.DriverBinaryLocation); errors.Is(err, os.ErrNotExist) {
|
|
|
|
|
err = playwright.Install()
|
|
|
|
|
if err != nil {
|
2022-11-17 19:25:07 +00:00
|
|
|
return Playwright{}, err
|
2022-11-17 01:41:53 +00:00
|
|
|
}
|
|
|
|
|
} else if err == nil {
|
|
|
|
|
cmd := exec.Command(driver.DriverBinaryLocation, "--version")
|
|
|
|
|
output, err := cmd.Output()
|
|
|
|
|
if err != nil || !bytes.Contains(output, []byte(driver.Version)) {
|
|
|
|
|
err = playwright.Install()
|
|
|
|
|
if err != nil {
|
2022-11-17 19:25:07 +00:00
|
|
|
return Playwright{}, err
|
2022-11-17 01:41:53 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pw, err := playwright.Run()
|
|
|
|
|
if err != nil {
|
2022-11-17 19:25:07 +00:00
|
|
|
return Playwright{}, err
|
2022-11-17 01:41:53 +00:00
|
|
|
}
|
|
|
|
|
browser, err := pw.Chromium.Launch()
|
|
|
|
|
if err != nil {
|
2022-11-17 19:25:07 +00:00
|
|
|
return Playwright{}, err
|
2022-11-17 01:41:53 +00:00
|
|
|
}
|
2022-11-17 19:25:07 +00:00
|
|
|
context, err := browser.NewContext()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return Playwright{}, err
|
|
|
|
|
}
|
|
|
|
|
page, err := context.NewPage()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return Playwright{}, err
|
|
|
|
|
}
|
|
|
|
|
return Playwright{
|
|
|
|
|
PW: pw,
|
|
|
|
|
Browser: browser,
|
|
|
|
|
BrowserContext: context,
|
|
|
|
|
Page: page,
|
|
|
|
|
}, nil
|
2022-11-17 01:41:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//go:embed generate_png.js
|
|
|
|
|
var genPNGScript string
|
|
|
|
|
|
2022-11-17 19:25:07 +00:00
|
|
|
func ExportPNG(ms *xmain.State, page playwright.Page, svg []byte) (outputImage []byte, err error) {
|
|
|
|
|
if page == nil {
|
|
|
|
|
ms.Log.Error.Printf("Playwright was not initialized properly for PNG export")
|
|
|
|
|
return nil, fmt.Errorf("Playwright page is not initialized for png export")
|
2022-11-17 01:41:53 +00:00
|
|
|
}
|
2022-11-17 19:25:07 +00:00
|
|
|
|
2022-11-17 01:41:53 +00:00
|
|
|
encodedSVG := base64.StdEncoding.EncodeToString(svg)
|
|
|
|
|
pngInterface, err := page.Evaluate(genPNGScript, "data:image/svg+xml;charset=utf-8;base64,"+encodedSVG)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pngString := fmt.Sprintf("%v", pngInterface)
|
|
|
|
|
pngPrefix := "data:image/png;base64,"
|
|
|
|
|
if !strings.HasPrefix(pngString, pngPrefix) {
|
2022-11-17 19:25:07 +00:00
|
|
|
ms.Log.Error.Printf("failed to convert D2 file to PNG")
|
2022-11-17 01:41:53 +00:00
|
|
|
return nil, fmt.Errorf("playwright export generated invalid png")
|
|
|
|
|
}
|
|
|
|
|
splicedPNGString := pngString[len(pngPrefix):]
|
2022-11-17 19:25:07 +00:00
|
|
|
return base64.StdEncoding.DecodeString(splicedPNGString)
|
2022-11-17 01:41:53 +00:00
|
|
|
}
|