Golang 圖片處理 — image 庫
編輯推薦:Bazinga
在開發中,有時會遇到對圖片的處理需求,在 Python 中, PIL/Pillow 庫非常強大和易用。
而 Golang 語言中,處理圖片的標準庫 image
也可以實現一些基本操作。
image
庫支援常見的 PNG、JPEG、GIF 等格式的圖片處理, 可以對圖片進行讀取、裁剪、繪製、生成等操作。
讀取、新建圖片
讀取
圖片的讀取,和檔案的讀取類似,只需要使用 os.Open()
函式,獲取一個輸入流,然後將資料流進行解碼操作。
需要注意的是,在解碼階段,要將不同型別的圖片的解碼器先進行註冊,這樣才不會報unknown format
的錯誤。
package main
import (
"fmt"
"image"
_ "image/png"
"os"
)
func main() {
f, err := os.Open("./gopher.png")
if err != nil {
panic(err)
}
img, formatName, err := image.Decode(f)
if err != nil {
panic(err)
}
fmt.Println(formatName)
fmt.Println(img.Bounds())
fmt.Println(img.ColorModel())
}
Decode
方法返回的第一個值是一個 image.Image
型別介面。不同的顏色模型的圖片返回不同型別的值。該介面有三個方法:
type Image interface {
ColorModel() color.Model // 返回圖片的顏色模型
Bounds() Rectangle // 返回圖片的長寬
At(x, y int) color.Color // 返回(x,y)畫素點的顏色
}
image 庫中很多結構都實現了該介面,對於一些標準庫中沒有實現的功能,我們也可以自己實現該介面去滿足。
新建
如果是需要新建一個圖片,可以使用image.NewRGBA()
方法。
img := image.NewRGBA(image.Rect(0, 0, 300, 300))
這裡的 NewRGBA
方法返回的是一個實現了 image.Image
介面的 image.RGBA
型別資料。 這裡是一個 300*300 的透明背景的圖片。
儲存圖片
儲存圖片和儲存檔案也類似,需要先將圖片編碼,然後以資料流的形式寫入檔案。
img := image.NewRGBA(image.Rect(0, 0, 300, 300))
outFile, err := os.Create("gopher2.png")
defer outFile.Close()
if err != nil {
panic(err)
}
b := bufio.NewWriter(outFile)
err = png.Encode(b, img)
if err != nil {
panic(err)
}
err = b.Flush()
if err != nil {
panic(err)
}
裁剪圖片
圖片的裁剪主要使用SubImage()
方法,如下:
img := image.NewRGBA(image.Rect(0, 0, 300, 300))
subImage := img.SubImage(image.Rect(0, 0, 20, 20))
該方法將從建立的 300 * 300 的圖片裁剪出 20 * 20 畫素的子圖片。
繪製圖片
繪製圖片主要使用到 draw.Draw
和draw.DrawMask
方法。
func Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point, op Op)
func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op)
Draw
Draw
方法各個引數含義如下:
- dst 繪圖的背景圖
- r 背景圖的繪圖區域
- src 要繪製的圖
- sp src 對應的繪圖開始點
- op 組合方式
以下程式碼是將一個 Gopher 的圖案繪製到了一張黑色背景空白圖的左上角。
f, err := os.Open("./gopher.png")
if err != nil {
panic(err)
}
gopherImg, _, err := image.Decode(f) // 開啟圖片
img := image.NewRGBA(image.Rect(0, 0, 300, 300))
for x := 0; x < img.Bounds().Dx(); x++ { // 將背景圖塗黑
for y := 0; y < img.Bounds().Dy(); y++ {
img.Set(x, y, color.Black)
}
}
draw.Draw(img, img.Bounds(), gopherImg, image.Pt(0, 0), draw.Over) // 將gopherImg繪製到背景圖上
DrawMask
DrawMask
方法多了一個遮罩蒙層引數mask
,以及蒙層的起始位置引數 mp
。
Draw
方法是 DrawMask
的一種特殊形式,當 DrawMask
的 mask
引數為 nil 時,即為Draw
方法。
DrawMask
將背景圖上的繪圖區域起始點、要繪製圖的起始點、遮罩蒙層的起始點進行對齊,然後對背景圖上的繪圖矩陣區域執行 Porter-Duff合併操作。
下面是給圖片加一個圓形遮罩的示例:
func drawCirclePic() {
f, err := os.Open("./gopher.png")
if err != nil {
panic(err)
}
gopherImg, _, err := image.Decode(f)
d := gopherImg.Bounds().Dx()
//將一個cicle作為蒙層遮罩,圓心為圖案中點,半徑為邊長的一半
c := circle{p: image.Point{X: d / 2, Y: d / 2}, r: d / 2}
circleImg := image.NewRGBA(image.Rect(0, 0, d, d))
draw.DrawMask(circleImg, circleImg.Bounds(), gopherImg, image.Point{}, &c, image.Point{}, draw.Over)
SavePng(circleImg)
}
type circle struct { // 這裡需要自己實現一個圓形遮罩,實現介面裡的三個方法
p image.Point // 圓心位置
r int
}
func (c *circle) ColorModel() color.Model {
return color.AlphaModel
}
func (c *circle) Bounds() image.Rectangle {
return image.Rect(c.p.X-c.r, c.p.Y-c.r, c.p.X+c.r, c.p.Y+c.r)
}
// 對每個畫素點進行色值設定,在半徑以內的圖案設成完全不透明
func (c *circle) At(x, y int) color.Color {
xx, yy, rr := float64(x-c.p.X)+0.5, float64(y-c.p.Y)+0.5, float64(c.r)
if xx*xx+yy*yy < rr*rr {
return color.Alpha{A: 255}
}
return color.Alpha{}
}
給圖片加一個圓角遮罩的示例:
func drawRadiusPic() {
f, err := os.Open("./gopher.png")
if err != nil {
panic(err)
}
gopherImg, _, err := image.Decode(f)
w := gopherImg.Bounds().Dx()
h := gopherImg.Bounds().Dy()
c := radius{p: image.Point{X: w, Y: h}, r: int(40)}
radiusImg := image.NewRGBA(image.Rect(0, 0, w, h))
draw.DrawMask(radiusImg, radiusImg.Bounds(), gopherImg, image.Point{}, &c, image.Point{}, draw.Over)
SavePng(radiusImg)
}
type radius struct {
p image.Point // 矩形右下角位置
r int
}
func (c *radius) ColorModel() color.Model {
return color.AlphaModel
}
func (c *radius) Bounds() image.Rectangle {
return image.Rect(0, 0, c.p.X, c.p.Y)
}
// 對每個畫素點進行色值設定,分別處理矩形的四個角,在四個角的內切圓的外側,色值設定為全透明,其他區域不透明
func (c *radius) At(x, y int) color.Color {
var xx, yy, rr float64
var inArea bool
// left up
if x <= c.r && y <= c.r {
xx, yy, rr = float64(c.r-x)+0.5, float64(y-c.r)+0.5, float64(c.r)
inArea = true
}
// right up
if x >= (c.p.X-c.r) && y <= c.r {
xx, yy, rr = float64(x-(c.p.X-c.r))+0.5, float64(y-c.r)+0.5, float64(c.r)
inArea = true
}
// left bottom
if x <= c.r && y >= (c.p.Y-c.r) {
xx, yy, rr = float64(c.r-x)+0.5, float64(y-(c.p.Y-c.r))+0.5, float64(c.r)
inArea = true
}
// right bottom
if x >= (c.p.X-c.r) && y >= (c.p.Y-c.r) {
xx, yy, rr = float64(x-(c.p.X-c.r))+0.5, float64(y-(c.p.Y-c.r))+0.5, float64(c.r)
inArea = true
}
if inArea && xx*xx+yy*yy >= rr*rr {
return color.Alpha{}
}
return color.Alpha{A: 255}
}
在圖案進行圓形、圓角繪製的過程中,因為最小單位是 1px,所以可能會有鋸齒邊緣的問題,解決這個問題可以通過先將原圖放大,遮罩後再縮小來解決。
Reference
The Go image/draw package - The Go Blog (golang.org)
Porter-Duff blend 模式 - Xamarin | Microsoft Docs
- 加微信實戰群請加微信(註明:實戰群):gocnio
相關文章
- SwiftUI Image 圖片處理SwiftUI
- Laravel 使用 Intervention/image 處理圖片Laravel
- 002.00 圖片處理 PIL.Image
- 圖片處理擴充套件 Intervention/image 的簡單使用套件
- 使用 Intervention/image 對 Laravel 專案中的圖片進行處理Laravel
- python+selenium 處理圖片驗證碼,Image 點不出 crop 方法Python
- thumbor:功能強大的圖片處理庫
- 002.00 圖片處理
- Thumbnailator處理圖片AI
- 【YLCircleImageView】圖片處理View
- webpack圖片處理Web
- 圖片上傳及圖片處理
- webpack 圖片處理 loaderWeb
- Python批量處理圖片Python
- DDGScreenShot —iOS 圖片處理--多圖片拼接 (swift)iOSSwift
- iOS image處理BlendModesiOS
- Swift Image 的處理Swift
- 處理圖片流資料
- CGContextRef處理圓形圖片GCContext
- java thumbnailator 做圖片處理JavaAI
- OpenCv--圖片處理操作OpenCV
- java 圖片水印處理類Java
- JavaScript WebGL 圖片透明處理JavaScriptWeb
- webpack(6)webpack處理圖片Web
- photoshop常用圖片處理技巧
- android圖片處理,讓圖片變成圓形Android
- SwiftUI圖片處理(縮放、拼圖)SwiftUI
- Photoshop類圖片處理軟體
- 002.01 圖片去外框處理
- 圖片展示 [ Numpy 處理, Matplotlib 展示 ]
- 如何處理 Web 圖片優化?Web優化
- 分享一個圖片處理類
- 圖片區域點選處理
- 走近webpack(3)–圖片的處理Web
- DxO PhotoLab 5,raw圖片處理
- Mac raw圖片處理軟體Mac
- DxO PhotoLab for mac(RAW圖片處理)Mac
- 圖形影像處理之簡單圖片