博客分享到朋友圈或者微博的时候经常是生成一个长的图文,这个一般是通过 wkhtmltoimage
来实现
今天我们就使用 Golang 搭配 wkhtmltoimage
命令来实现
-
首先是安装
wkhtmltoimage
brew cask install wkhtmltopdf
如果是其它系统,则直接访问 https://wkhtmltopdf.org/ 下载即可
-
然后就可以使用
os/exec
搭配wkhtmltoimage
命令来实现了package main import ( "bytes" "errors" "fmt" "image/jpeg" "image/png" "os" "os/exec" "strconv" "strings" ) type ImageOptions struct { // BinaryPath the path to your wkhtmltoimage binary. REQUIRED // // Must be absolute path e.g /usr/local/bin/wkhtmltoimage BinaryPath string // Input is the content to turn into an image. REQUIRED // // Can be a url (http://example.com), a local file (/tmp/example.html), or html as a string (send "-" and set the Html value) Input string // Format is the type of image to generate // // jpg, png, svg, bmp supported. Defaults to local wkhtmltoimage default Format string // Height is the height of the screen used to render in pixels. // // Default is calculated from page content. Default 0 (renders entire page top to bottom) Height int // Width is the width of the screen used to render in pixels. // // Note that this is used only as a guide line. Default 1024 Width int // Quality determines the final image quality. // // Values supported between 1 and 100. Default is 94 Quality int // Html is a string of html to render into and image. // // Only needed to be set if Input is set to "-" Html string // Output controls how to save or return the image. // // Leave nil to return a []byte of the image. Set to a path (/tmp/example.png) to save as a file. Output string } func GenerateImage(options *ImageOptions) ([]byte, error) { arr, err := buildParams(options) if err != nil { return []byte{}, err } if options.BinaryPath == "" { options.BinaryPath = "/usr/local/bin/wkhtmltoimage" } cmd := exec.Command(options.BinaryPath, arr...) if options.Html != "" { cmd.Stdin = strings.NewReader(options.Html) } output, err := cmd.CombinedOutput() trimmed := cleanupOutput(output, options.Format) return trimmed, err } func buildParams(options *ImageOptions) ([]string, error) { a := []string{} if options.Input == "" { return []string{}, errors.New("Must provide input") } a = append(a, "-q") a = append(a, "--disable-plugins") a = append(a, "--format") if options.Format != "" { a = append(a, options.Format) } else { a = append(a, "png") } if options.Height != 0 { a = append(a, "--height") a = append(a, strconv.Itoa(options.Height)) } if options.Width != 0 { a = append(a, "--width") a = append(a, strconv.Itoa(options.Width)) } if options.Quality != 0 { a = append(a, "--quality") a = append(a, strconv.Itoa(options.Quality)) } // 如果设置了 URL,则优先使用 URL if options.Input != "-" { // 如果使用 URL 则需要将 Html 参数置空 options.Html = "" } a = append(a, options.Input) if options.Output == "" { a = append(a, "-") } else { a = append(a, options.Output) } return a, nil } func cleanupOutput(img []byte, format string) []byte { buf := new(bytes.Buffer) switch { case format == "png": decoded, err := png.Decode(bytes.NewReader(img)) for err != nil { img = img[1:] if len(img) == 0 { break } decoded, err = png.Decode(bytes.NewReader(img)) } png.Encode(buf, decoded) return buf.Bytes() case format == "jpg": decoded, err := jpeg.Decode(bytes.NewReader(img)) for err != nil { img = img[1:] if len(img) == 0 { break } decoded, err = jpeg.Decode(bytes.NewReader(img)) } jpeg.Encode(buf, decoded, nil) return buf.Bytes() } return img } func main() { html := "<html><head></head><body><p style='color:red;'>example</p></body></html>" c := ImageOptions{ Input: "https://www.twle.cn", Width: 640, Format: "png", Html: html, } out, err := GenerateImage(&c) if err != nil { panic(err) } f, err := os.Create("example.png") if err != nil { panic(err) } defer f.Close() n2, err := f.Write(out) if err != nil { panic(err) } fmt.Printf("wrote %d bytes\n", n2) }
目前尚无回复