From 354f1fd62b8be5a260777f95d90538113cdbdd6c Mon Sep 17 00:00:00 2001 From: dustoair <107600816+dustoair@users.noreply.github.com> Date: Sat, 6 Aug 2022 11:46:33 +0800 Subject: [PATCH] open src --- .gitignore | 5 ++ convert.go | 226 ++++++++++++++++++++++++++++++++++++++++++++++++ convert_test.go | 9 ++ go.mod | 16 ++++ readme.md | 3 + 5 files changed, 259 insertions(+) create mode 100644 .gitignore create mode 100644 convert.go create mode 100644 convert_test.go create mode 100644 go.mod create mode 100644 readme.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2fa6406 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.idea +go.sum +*.png +*.jpg +*.webp \ No newline at end of file diff --git a/convert.go b/convert.go new file mode 100644 index 0000000..22f24c1 --- /dev/null +++ b/convert.go @@ -0,0 +1,226 @@ +package html2Img + +import ( + "context" + "errors" + "fmt" + "github.com/chromedp/cdproto/emulation" + "github.com/chromedp/cdproto/page" + "github.com/chromedp/chromedp" + uuid "github.com/iris-contrib/go.uuid" + "os" + "time" +) + +// FormatPng png jpg webp +const FormatPng = page.CaptureScreenshotFormatPng + +// DefaultQuality jpg only +const DefaultQuality = 0 + +// DefaultFromSurface capture from surface rather than viewport +const DefaultFromSurface = true + +// DefaultViewportX viewport x +const DefaultViewportX = 0 + +// DefaultViewportY viewport y +const DefaultViewportY = 0 + +const DefaultViewportWidth = 996 +const DefaultViewportHeight = 996 + +const DefaultViewportScale = 1 + +// DefaultWaitingTime waiting time unit:Millisecond +const DefaultWaitingTime = 0 + +type Html2ImageParams struct { + page.CaptureScreenshotParams + CustomClip bool + WaitingTime int // Waiting time after the page loaded. Default 0 means not wait. unit:Millisecond +} + +type CommonRequestDTO struct { + Url string `schema:"url,omitempty" validate:"required,url"` + UploadKey string `schema:"uploadKey,omitempty" validate:"omitempty"` + Username string `schema:"u,omitempty" validate:"required"` + Password string `schema:"p,omitempty" validate:"required"` +} + +type Html2ImageRequestDTO struct { + CommonRequestDTO + Format page.CaptureScreenshotFormat `schema:"format,omitempty" validate:"omitempty"` // Image compression format (defaults to png). + Quality int64 `schema:"quality,omitempty" validate:"omitempty"` // Compression quality from range [0..100] (jpeg only). + CustomClip bool `schema:"customClip,omitempty" validate:"omitempty"` //if set this value, the below clip will work,otherwise not work! + ClipX float64 `schema:"clipX,omitempty" validate:"omitempty"` // Capture the screenshot of a given region only.X offset in device independent pixels (dip). + ClipY float64 `schema:"clipY,omitempty" validate:"omitempty"` // Capture the screenshot of a given region only.Y offset in device independent pixels (dip). + ClipWidth float64 `schema:"clipWidth,omitempty" validate:"omitempty"` // Capture the screenshot of a given region only.Rectangle width in device independent pixels (dip). + ClipHeight float64 `schema:"clipHeight,omitempty" validate:"omitempty"` // Capture the screenshot of a given region only.Rectangle height in device independent pixels (dip). + ClipScale float64 `schema:"clipScale,omitempty" validate:"omitempty"` // Capture the screenshot of a given region only.Page scale factor. + FromSurface bool `schema:"fromSurface,omitempty" validate:"omitempty"` // Capture the screenshot from the surface, rather than the view. Defaults to true. + WaitingTime int `schema:"waitingTime,omitempty" validate:"omitempty"` // Waiting time after the page loaded. Default 0 means not wait. unit:Millisecond +} + +func NewDefaultHtml2ImageParams() Html2ImageParams { + return Html2ImageParams{ + CustomClip: false, + CaptureScreenshotParams: page.CaptureScreenshotParams{ + Format: FormatPng, + Quality: DefaultQuality, + Clip: &page.Viewport{ + X: DefaultViewportX, + Y: DefaultViewportY, + Width: DefaultViewportWidth, + Height: DefaultViewportHeight, + Scale: DefaultViewportScale, + }, + FromSurface: DefaultFromSurface, + }, + WaitingTime: DefaultWaitingTime, + } +} + +func newDefaultHtml2ImageRequestDTO() *Html2ImageRequestDTO { + return &Html2ImageRequestDTO{ + Format: FormatPng, + Quality: DefaultQuality, + CustomClip: false, + ClipX: DefaultViewportX, + ClipY: DefaultViewportY, + ClipWidth: DefaultViewportWidth, + ClipHeight: DefaultViewportHeight, + ClipScale: DefaultViewportScale, + FromSurface: DefaultFromSurface, + WaitingTime: DefaultWaitingTime, + } +} + +func convertToHtml2ImageParams(requestDTO *Html2ImageRequestDTO) Html2ImageParams { + params := NewDefaultHtml2ImageParams() + params.Format = requestDTO.Format + params.Quality = requestDTO.Quality + params.CustomClip = requestDTO.CustomClip + params.Clip.X = requestDTO.ClipX + params.Clip.Y = requestDTO.ClipY + params.Clip.Width = requestDTO.ClipWidth + params.Clip.Height = requestDTO.ClipHeight + params.Clip.Scale = requestDTO.ClipScale + params.FromSurface = requestDTO.FromSurface + params.WaitingTime = requestDTO.WaitingTime + return params +} + +type ConvertConfig struct { + Url string `validate:"required,url"` + Params Params +} + +type DoctronConfig struct { + TraceId uuid.UUID + Ctx context.Context + DoctronType int + ConvertConfig +} + +type Params interface { +} + +type Converter interface { + Convert() ([]byte, error) + GetConvertElapsed() time.Duration +} + +type Conver struct { + ctx context.Context + cc ConvertConfig + buf []byte + convertElapsed time.Duration +} + +type html2image struct { + Conver +} + +func (ins *html2image) GetConvertElapsed() time.Duration { + return ins.convertElapsed +} + +func (ins *html2image) Convert() ([]byte, error) { + start := time.Now() + defer func() { + ins.convertElapsed = time.Since(start) + }() + var params Html2ImageParams + params, ok := ins.cc.Params.(Html2ImageParams) + if !ok { + return nil, errors.New("wrong html2image params given") + } + ctx, cancel := chromedp.NewContext(ins.ctx) + defer cancel() + + if err := chromedp.Run(ctx, + chromedp.Navigate(ins.cc.Url), + chromedp.Sleep(time.Duration(params.WaitingTime)*time.Millisecond), + chromedp.ActionFunc(func(ctx context.Context) error { + + if !params.CustomClip { + // get layout metrics + _, _, contentSize, _, _, _, err := page.GetLayoutMetrics().Do(ctx) + if err != nil { + return err + } + params.Clip.X = contentSize.X + params.Clip.Y = contentSize.Y + params.Clip.Width = contentSize.Width + params.Clip.Height = contentSize.Height + } + + // force viewport emulation + err := emulation.SetDeviceMetricsOverride(int64(params.Clip.Width), int64(params.Clip.Height), 1, false). + WithScreenOrientation(&emulation.ScreenOrientation{ + Type: emulation.OrientationTypePortraitPrimary, + Angle: 0, + }). + Do(ctx) + if err != nil { + return err + } + + // capture screenshot + ins.buf, err = params.Do(ctx) + return err + }), + ); err != nil { + return nil, err + } + + return ins.buf, nil +} + +func GetImg(url, filename string) error { + result := DoctronConfig{} + requestDTO := newDefaultHtml2ImageRequestDTO() + result.Url = requestDTO.Url + ins := new(html2image) + ins.Conver = Conver{ + ctx: context.Background(), + cc: ConvertConfig{ + Url: url, + Params: convertToHtml2ImageParams(requestDTO), + }, + } + + img, err := ins.Convert() + if err != nil { + fmt.Println("err", err) + return err + } + err = os.WriteFile(filename, img, 0666) + if err != nil { + fmt.Println("err", err) + return err + } + + return nil +} diff --git a/convert_test.go b/convert_test.go new file mode 100644 index 0000000..df2ba3e --- /dev/null +++ b/convert_test.go @@ -0,0 +1,9 @@ +package html2Img + +import ( + "testing" +) + +func Test_html2image(t *testing.T) { + GetImg("https://www.baidu.com", "test.webp") +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..f3762d8 --- /dev/null +++ b/go.mod @@ -0,0 +1,16 @@ +module html2Img + +go 1.19 + +require ( + github.com/chromedp/cdproto v0.0.0-20220804213442-94946ca6fcf8 // indirect + github.com/chromedp/chromedp v0.8.3 // indirect + github.com/chromedp/sysutil v1.0.0 // indirect + github.com/gobwas/httphead v0.1.0 // indirect + github.com/gobwas/pool v0.2.1 // indirect + github.com/gobwas/ws v1.1.0 // indirect + github.com/iris-contrib/go.uuid v2.0.0+incompatible // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect +) diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..617f0ce --- /dev/null +++ b/readme.md @@ -0,0 +1,3 @@ +html 2 img +[]: # Language: markdown +[]: # Path: readme.md \ No newline at end of file