go旅途之图片绘制文字

4,200 阅读2分钟

前言

上一篇介绍了生成RGBA对象,并生成一张png图像写入硬盘中。本文主要介绍如何向RGBA对象绘制文字。

代码

package main

import (
    "image"
    "os"
    "fmt"
    "bufio"
    "image/png"
    "github.com/golang/freetype"
    "io/ioutil"
    "log"
    "image/draw"
)

func GetContext(s string) *freetype.Context {
    fontBytes,err := ioutil.ReadFile(s)

    if err != nil{
        log.Println("ReadFile",s,err)
        return nil
    }

    f,err := freetype.ParseFont(fontBytes)
    if err != nil{
        log.Println("ParseFont",err)
        return nil
    }

    c := freetype.NewContext()
    c.SetFont(f)
    c.SetDPI(72)
    c.SetFont(f)
    c.SetFontSize(26)
    return c
}

func main(){
    background := image.NewRGBA(image.Rect(0,0,500,500))
    draw.Draw(background,background.Bounds(),image.White,image.ZP,draw.Src)
    context := GetContext("font.ttf")
    context.SetClip(background.Bounds())
    context.SetDst(background)
    context.SetSrc(image.Black)
    pt := freetype.Pt(10,10 + int(context.PointToFixed(26)>>6))
    _ , err := context.DrawString("你好go",pt);
    if err !=nil{
        fmt.Println(err)
        os.Exit(1)
    }
    outFile,err := os.Create("p1.png")

    if err != nil{
        fmt.Println(err)
        os.Exit(-1)
    }
    defer outFile.Close()
    buff := bufio.NewWriter(outFile)

    err = png.Encode(buff,background)

    if err != nil{
        fmt.Println(err)
        os.Exit(-1)
    }

    err = buff.Flush()
    if err != nil{
        fmt.Println(err)
        os.Exit(-1)
    }
    fmt.Println("Save to 1.png")
}

画图接口

接口在image/draw包,dst为目标图像,r为在目标图像绘制位置。src为源图像,sp为源图像的起始点,op可以理解为绘制操作的类型。

Draw函数使用nil的mask参数调用DrawMask函数。
//image/draw
func Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point, op Op) {
	DrawMask(dst, r, src, sp, nil, image.Point{}, op)
}

对齐目标图像dst的矩形r左上角、源图像src的sp点、遮罩mask的mp点,根据op修改dst的r矩形区域内的内容,mask如果为nil则视为完全透明。
//image/draw
func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op)

下面这行代码成功地将background图像初始化为的白色。

draw.Draw(background,background.Bounds(),image.White,image.ZP,draw.Src)

读取文件

现在需要读取字体格式文件,将加载字体结构。 用io/ioutil包,读取文件.

//io/ioutil
func ReadFile(filename string) ([]byte, error) 

加载字体格式

ParseFont加载.ttf字体格式文件的内容,并返回truetype.Font的字体结构,这里不过多深究字体格式

//github.com/golang/freetype
func ParseFont(b []byte) (*truetype.Font, error)

定义字体样式

//github.com/golang/freetype
func NewContext() *Context

// 设置屏幕分辨率的DPI
func (c *Context) SetDPI(dpi float64) 

// 设置字体样式,为ParseFont的返回值
func (c *Context) SetFont(f *truetype.Font) 

// 设置字体占用像素
func (c *Context) SetFontSize(fontSize float64)

// SetHinting sets the hinting policy.
func (c *Context) SetHinting(hinting font.Hinting) 

// 设置要绘制的目标图像
func (c *Context) SetDst(dst draw.Image) {
	c.dst = dst
}

// 猜测应该是设置采样图像
func (c *Context) SetSrc(src image.Image) 

// 设置绘制范围
func (c *Context) SetClip(clip image.Rectangle) 

定义绘制位置

//返回一个屏幕坐标定义好的位置,该位置为文字左上角
func Pt(x, y int) fixed.Point26_6

func (c *Context) PointToFixed(x float64) fixed.Int26_6 {
	return fixed.Int26_6(x * float64(c.dpi) * (64.0 / 72.0))
}

注意x,y指定文字左上角的像素坐标,通常我们是希望指定文字左下角的像素坐标。 例如我们希望在(10,10)位置写方案,若直接调用传(10,10)的点,结果如下

若传入 (10,10 + int(context.PointToFixed(fontsize)>>6)

写文字到图像

在指定位置写指定文字

func (c *Context) DrawString(s string, p fixed.Point26_6) (fixed.Point26_6, error) 

传送门

github.com/wuzhuorui/W…