1. 程式人生 > >golang基礎--image/draw渲染圖片、利用golang/freetype庫在圖片上生成文字

golang基礎--image/draw渲染圖片、利用golang/freetype庫在圖片上生成文字

文章目錄

需求

在一張A4紙上,利用image/draw標準庫生成4張二維碼,和該二維碼的客戶資訊
1、二維碼生成利用到的庫就是image/draw,通過draw.Draw進行寫入
2、然後字型渲染利用了golang/freetype開源庫
https://github.com/golang/freetype/blob/master/example/freetype/main.go

安裝依賴

"github.com/golang/freetype"
"golang.org/x/image/font"

以上的golang.org/x/image/font需要翻牆,如果不能翻牆利用如下方法也可以:
在這裡插入圖片描述

邏輯

1、通過os.Create("dst.jpg")

生成一個最終的圖片,該圖片上畫了4個二維碼,和頭部文字渲染
2、通過os.Open("/Users/zhiliao/zhiliao/gopro/go_safly/src/qr.png")去獲取本地的一個二維碼圖片路徑,然後通過png.Decode(file1)生成圖片
3、修改二維碼圖片的尺寸resize.Resize(314, 314, img, resize.Lanczos3)
4、通過image.NewRGBA(image.Rect(0, 0, 827, 1169))生成一個RGBA結構體的矩形框,就好比是畫布的概念
5、選渲染頭部的客戶資訊字型,需要一箇中文字型庫,這個可以用Mac系統庫的中文字型,或者自行下載ttf字型庫,然後載入該字型
6、draw.Draw(jpg, jpg.Bounds(), bg, image.ZP, draw.Src)是進行設定渲染的引數,引數是畫布、渲染開始的地方、圖片來源、圖片引數、渲染模式
7、然後就是設定baseline,我這裡去掉了,然後就是劃線,最後就是渲染字型,通過c.DrawString(s, pt)
8、接下來就是畫4個二維碼

draw.Draw(jpg, img.Bounds().Add(image.Pt(60, 150)), img, img.Bounds().Min, draw.Src) //擷取圖片的一部分
	draw.Draw(jpg, img.Bounds().Add(image.Pt(435, 150)), img, img.Bounds().Min, draw.Src) //擷取圖片的一部分
	draw.Draw(jpg, img.Bounds().Add(image.Pt(60, 610)), img, img.Bounds().Min, draw.Src) //擷取圖片的一部分
	draw.Draw(jpg, img.Bounds().Add(image.Pt(435, 610)), img, img.Bounds().Min, draw.Src) //擷取圖片的一部分

9、最後通過png.Encode(file, jpg)輸出到我們最終生成的圖片

效果圖

在這裡插入圖片描述

例項

package main

import (
	"flag"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/golang/freetype"
	"github.com/nfnt/resize"
	"golang.org/x/image/font"
	"image"
	"image/draw"
	"image/png"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"
)

var (
	dpi      = flag.Float64("dpi", 72, "screen resolution in Dots Per Inch")
	fontfile = flag.String("fontfile", "/Users/zhiliao/Downloads/ffffonts/simsun.ttf", "filename of the ttf font")
	hinting  = flag.String("hinting", "none", "none | full")
	size     = flag.Float64("size", 30, "font size in points")
	spacing  = flag.Float64("spacing", 1.5, "line spacing (e.g. 2 means double spaced)")
	wonb     = flag.Bool("whiteonblack", false, "white text on a black background")
)


var text = []string{
	"地支:瀋陽市某區某鎮某街道某樓某",
	"姓名:王永飛",
	"電話:1232131231232",
}

func main() {

	file, err := os.Create("dst.jpg")
	if err != nil {
		fmt.Println(err)
	}
	defer file.Close()

	file1, err := os.Open("/Users/zhiliao/zhiliao/gopro/go_safly/src/qr.png")
	if err != nil {
		fmt.Println(err)
	}
	defer file1.Close()
	img, _ := png.Decode(file1)
	//尺寸
	img = resize.Resize(314, 314, img, resize.Lanczos3)


	jpg := image.NewRGBA(image.Rect(0, 0, 827, 1169))

	fontRender(jpg)

	draw.Draw(jpg, img.Bounds().Add(image.Pt(60, 150)), img, img.Bounds().Min, draw.Src) //擷取圖片的一部分
	draw.Draw(jpg, img.Bounds().Add(image.Pt(435, 150)), img, img.Bounds().Min, draw.Src) //擷取圖片的一部分
	draw.Draw(jpg, img.Bounds().Add(image.Pt(60, 610)), img, img.Bounds().Min, draw.Src) //擷取圖片的一部分
	draw.Draw(jpg, img.Bounds().Add(image.Pt(435, 610)), img, img.Bounds().Min, draw.Src) //擷取圖片的一部分



	png.Encode(file, jpg)

}

func fontRender(jpg *image.RGBA)  {
	flag.Parse()
	fontBytes, err := ioutil.ReadFile(*fontfile)
	if err != nil {
		log.Println(err)
		return
	}
	f, err := freetype.ParseFont(fontBytes)
	if err != nil {
		log.Println(err)
		return
	}

	fg, bg := image.Black, image.White
	//ruler := color.RGBA{0xdd, 0xdd, 0xdd, 0xff}
	//if *wonb {
	//	fg, bg = image.White, image.Black
	//	ruler = color.RGBA{0x22, 0x22, 0x22, 0xff}
	//}
	draw.Draw(jpg, jpg.Bounds(), bg, image.ZP, draw.Src)
	c := freetype.NewContext()
	c.SetDPI(*dpi)
	c.SetFont(f)
	c.SetFontSize(*size)
	c.SetClip(jpg.Bounds())
	c.SetDst(jpg)
	c.SetSrc(fg)

	switch *hinting {
	default:
		c.SetHinting(font.HintingNone)
	case "full":
		c.SetHinting(font.HintingFull)
	}

	//Draw the guidelines.
	//for i := 0; i < 200; i++ {
	//	jpg.Set(10, 10+i, ruler)
	//	jpg.Set(10+i, 10, ruler)
	//}

	// Draw the text.
	pt := freetype.Pt(200, 10+int(c.PointToFixed(*size)>>6))
	for _, s := range text {
		_, err = c.DrawString(s, pt)
		if err != nil {
			log.Println(err)
			return
		}
		pt.Y += c.PointToFixed(*size * *spacing)
	}

}


func Cors() gin.HandlerFunc {
	return func(c *gin.Context) {
		method := c.Request.Method      //請求方法
		origin := c.Request.Header.Get("Origin")        //請求頭部
		var headerKeys []string                             // 宣告請求頭keys
		for k, _ := range c.Request.Header {
			headerKeys = append(headerKeys, k)
		}
		headerStr := strings.Join(headerKeys, ", ")
		if headerStr != "" {
			headerStr = fmt.Sprintf("access-control-allow-origin, access-control-allow-headers, %s", headerStr)
		} else {
			headerStr = "access-control-allow-origin, access-control-allow-headers"
		}
		if origin != "" {
			c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
			c.Header("Access-Control-Allow-Origin", "*")        // 這是允許訪問所有域
			c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE")      //伺服器支援的所有跨域請求的方法,為了避免瀏覽次請求的多次'預檢'請求
			//  header的型別
			c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session,X_Requested_With,Accept, Origin, Host, Connection, Accept-Encoding, Accept-Language,DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Pragma")
			//              允許跨域設定                                                                                                      可以返回其他子段
			c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers,Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma,FooBar")      // 跨域關鍵設定 讓瀏覽器可以解析
			c.Header("Access-Control-Max-Age", "172800")        // 快取請求資訊 單位為秒
			c.Header("Access-Control-Allow-Credentials", "false")       //  跨域請求是否需要帶cookie資訊 預設設定為true
			c.Set("content-type", "application/json")       // 設定返回格式是json
		}

		//放行所有OPTIONS方法
		if method == "OPTIONS" {
			c.JSON(http.StatusOK, "Options Request!")
		}
		// 處理請求
		c.Next()        //  處理請求
	}
}