package main import ( "encoding/base64" "errors" "net/http" "net/url" "strings" "github.com/playwright-community/playwright-go" ) type RawImageFile struct { URL string Blocks []map[string]int Width *int Height *int } type File struct { ContentType string Data []byte } var draw = ` async function drawImage(imageFile) { const canvas = Object.assign(document.createElement("canvas"), { width: imageFile.width, height: imageFile.height, }); const image = (await new Promise((resolve) => { Object.assign(new Image(), { crossOrigin: "use-credentials", src: imageFile.url, onload() { resolve(this); }, }); })); const ctx = canvas.getContext("2d"); for (const q of imageFile.blocks) { ctx.drawImage(image, q.destX, q.destY, q.width, q.height, q.srcX, q.srcY, q.width, q.height); } const dataUrl = canvas.toDataURL(); return dataUrl; } ` var fetch = ` async function fetchImage(imageFile) { const res = await fetch(imageFile.url); const blob = await res.blob(); const dataUrl = await new Promise((resolve, reject) => { const fileReader = Object.assign(new FileReader(), { onload() { resolve(this.result); }, onerror(e) { const error = new Error(` + "`${e.type}: ${e.message}`" + `); reject(error); }, }); fileReader.readAsDataURL(blob); }); return dataUrl; } ` func parseDataURL(dataURL string) (*File, error) { if !strings.HasPrefix(dataURL, "data:") { return nil, errors.New("not data scheme") } parts := strings.SplitN(dataURL, ",", 2) if len(parts) != 2 { return nil, errors.New("invalid data URL") } raw, err := url.PathUnescape(parts[1]) if err != nil { return nil, err } var data []byte if strings.HasSuffix(parts[0], ";base64") { data, err = base64.StdEncoding.DecodeString(raw) if err != nil { return nil, err } } else { data = []byte(raw) } file := File{ ContentType: http.DetectContentType(data), Data: data, } return &file, nil } type Browser struct { pw *playwright.Playwright browser playwright.Browser } func Install() error { opts := playwright.RunOptions{ Browsers: []string{"chromium"}, } return playwright.Install(&opts) } type RunOptions struct { DB Database Headless *bool } func Run(options RunOptions) (*Browser, error) { pw, err := playwright.Run() if err != nil { return nil, err } launchOptions := playwright.BrowserTypeLaunchOptions{ Headless: playwright.Bool(*options.Headless), } b, err := pw.Chromium.Launch(launchOptions) if err != nil { return nil, err } browser := Browser{ pw: pw, browser: b, } return &browser, nil } func (b Browser) Stop() error { return b.pw.Stop() } func (b Browser) NewContext() (playwright.BrowserContext, error) { return b.browser.NewContext() } // TODO // Browser LoadBrowserContext(platform: TPlatform): Promise; // Browser SaveBrowserContext(platform: TPlatform, ctx: BrowserContext): Promise; // Browser DrawImage( // pageOrFrame: Playwright.Page | Playwright.Frame, // imageFile: ImageFile, // ): Promise;