2019年7月25日 星期四

如何用 GoLang 處理圖片:圖片貼上

首先是第一張圖

這邊參考 Go png package 的範例來建立

package main

import (
	"bytes"
	"encoding/base64"
	"image"
	"image/color"
	"image/png"
	"io/ioutil"
	"os"
	"log"
)

func main() {
	const width, height = 256, 256

	// Create a colored image of the given width and height.
	img := image.NewNRGBA(image.Rect(0, 0, width, height))

	for y := 0; y < height; y++ {
		for x := 0; x < width; x++ {
			img.Set(x, y, color.NRGBA{
				R: uint8((x + y) & 255),
				G: uint8((x + y) << 1 & 255),
				B: uint8((x + y) << 2 & 255),
				A: 255,
			})
		}
	}

	pngBuffer := bytes.Buffer{}
	if err := png.Encode(&pngBuffer, img); err != nil {
		log.Fatal(err)
	}

	// 將圖片存在 Temp 資料夾
	// 如果不能,就輸出圖片的 data-url
	if pngFile, err := ioutil.TempFile(os.TempDir(), `example-*.png`); err != nil {
		log.Printf(
			"PNG Result: \n%s%s",
			"data:image/png;base64,", base64.StdEncoding.EncodeToString(pngBuffer.Bytes()),
		)
	} else {
		defer pngFile.Close()
		if _, err = pngFile.Write(pngBuffer.Bytes()); err != nil {
			log.Printf("Error: Cannot generate image %s", pngFile.Name())
		} else {
			log.Printf("Generate image %s successfully", pngFile.Name())
		}

	}
}

再來是第二張圖片,這次我們選擇從網路抓圖片

網路抓圖的 function 如下

func loadImage(imgURL string) (image.Image, error) {
	if resp, err := http.Get(imgURL); err != nil {
		return nil, err
	} else {
		defer resp.Body.Close()
		i, _, err := image.Decode(resp.Body)
		return i, err
	}
}

圖片若抓成功,則將之貼在第一張圖片 (img) 上

根據《The Go image/draw package》,使用 image/draw 來處理,如下所示:

i, _ := loadImage(doodle)
draw.Draw(img, image.Rect(0, 0, width, height), i, image.ZP, draw.Over)

整段 code 如下:

package main

import (
	"bytes"
	"encoding/base64"
	"image"
	"image/color"
	"image/draw"
	"image/png"
	"os"

	"io/ioutil"
	"log"
	"net/http"
)

const doodle = "https://www.google.com/logos/doodles/2019/60th-anniversary-of-the-land-of-crimson-clouds-publication-4912169354264576-2x.png"

func main() {
	const width, height = 256, 256

	// Create a colored image of the given width and height.
	img := image.NewNRGBA(image.Rect(0, 0, width, height))

	for y := 0; y < height; y++ {
		for x := 0; x < width; x++ {
			img.Set(x, y, color.NRGBA{
				R: uint8((x + y) & 255),
				G: uint8((x + y) << 1 & 255),
				B: uint8((x + y) << 2 & 255),
				A: 255,
			})
		}
	}

	// 讀取圖片,並試著將圖片貼至 img 上
	if i, err := loadImage(doodle); err == nil {
		draw.Draw(img, image.Rect(-width/2, 0, width, height), i, image.ZP, draw.Over)
	} else {
		log.Printf("Error: Cannot Load Image %s", doodle)
	}

	pngBuffer := bytes.Buffer{}
	if err := png.Encode(&pngBuffer, img); err != nil {
		log.Fatal(err)
	}

	// 將圖片存在 Temp 資料夾
	// 如果不能,就輸出圖片的 data-url
	if pngFile, err := ioutil.TempFile(os.TempDir(), `example-*.png`); err != nil {
		log.Printf(
			"PNG Result: \n%s%s",
			"data:image/png;base64,", base64.StdEncoding.EncodeToString(pngBuffer.Bytes()),
		)
	} else {
		defer pngFile.Close()
		if _, err = pngFile.Write(pngBuffer.Bytes()); err != nil {
			log.Printf("Error: Cannot generate image %s", pngFile.Name())
		} else {
			log.Printf("Generate image %s successfully", pngFile.Name())
		}

	}
}

// 從網路讀取圖片,並將之轉成 image.Image
func loadImage(imgURL string) (image.Image, error) {
	if resp, err := http.Get(imgURL); err != nil {
		return nil, err
	} else {
		defer resp.Body.Close()
		i, _, err := image.Decode(resp.Body)
		return i, err
	}
}

沒有留言:

張貼留言