1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        【GoCN酷Go推薦】Golang 圖片處理 — image 庫(kù)

        共 7994字,需瀏覽 16分鐘

         ·

        2021-07-04 12:23

        在開(kāi)發(fā)中,有時(shí)會(huì)遇到對(duì)圖片的處理需求,在 Python中, PIL/Pillow  庫(kù)非常強(qiáng)大和易用。

        而 Golang 語(yǔ)言中,處理圖片的標(biāo)準(zhǔn)庫(kù) image也可以實(shí)現(xiàn)一些基本操作。

        image 庫(kù)支持常見(jiàn)的 PNG、JPEG、GIF 等格式的圖片處理, 可以對(duì)圖片進(jìn)行讀取、裁剪、繪制、生成等操作。

        讀取、新建圖片

        讀取

        圖片的讀取,和文件的讀取類(lèi)似,只需要使用 os.Open()函數(shù),獲取一個(gè)輸入流,然后將數(shù)據(jù)流進(jìn)行解碼操作。

        需要注意的是,在解碼階段,要將不同類(lèi)型的圖片的解碼器先進(jìn)行注冊(cè),這樣才不會(huì)報(bào)unknown format 的錯(cuò)誤。

        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 方法返回的第一個(gè)值是一個(gè) image.Image類(lèi)型接口。不同的顏色模型的圖片返回不同類(lèi)型的值。該接口有三個(gè)方法:

        type Image interface {
          ColorModel() color.Model // 返回圖片的顏色模型
          Bounds() Rectangle     // 返回圖片的長(zhǎng)寬
          At(x, y int) color.Color // 返回(x,y)像素點(diǎn)的顏色
        }

        image 庫(kù)中很多結(jié)構(gòu)都實(shí)現(xiàn)了該接口,對(duì)于一些標(biāo)準(zhǔn)庫(kù)中沒(méi)有實(shí)現(xiàn)的功能,我們也可以自己實(shí)現(xiàn)該接口去滿(mǎn)足。

        新建

        如果是需要新建一個(gè)圖片,可以使用image.NewRGBA()方法。

        img := image.NewRGBA(image.Rect(00300300))

        這里的 NewRGBA方法返回的是一個(gè)實(shí)現(xiàn)了 image.Image接口的 image.RGBA類(lèi)型數(shù)據(jù)。這里是一個(gè)300*300的透明背景的圖片。

        保存圖片

        保存圖片和保存文件也類(lèi)似,需要先將圖片編碼,然后以數(shù)據(jù)流的形式寫(xiě)入文件。

        img := image.NewRGBA(image.Rect(00300300))

        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(00300300))
        subImage := img.SubImage(image.Rect(002020))

        該方法將從創(chuàng)建的300 * 300的圖片裁剪出20 * 20 像素的子圖片。

        繪制圖片

        繪制圖片主要使用到 draw.Drawdraw.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方法各個(gè)參數(shù)含義如下:

        • dst  繪圖的背景圖
        • r  背景圖的繪圖區(qū)域
        • src  要繪制的圖
        • sp  src 對(duì)應(yīng)的繪圖開(kāi)始點(diǎn)
        • op 組合方式

        以下代碼是將一個(gè) Gopher 的圖案繪制到了一張黑色背景空白圖的左上角。

        f, err := os.Open("./gopher.png")
        if err != nil {
          panic(err)
        }
        gopherImg, _, err := image.Decode(f) // 打開(kāi)圖片

        img := image.NewRGBA(image.Rect(00300300))
        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(00), draw.Over) // 將gopherImg繪制到背景圖上

        DrawMask

        DrawMask方法多了一個(gè)遮罩蒙層參數(shù)mask,以及蒙層的起始位置參數(shù) mp。

        Draw方法是 DrawMask的一種特殊形式,當(dāng) DrawMaskmask 參數(shù)為nil時(shí),即為Draw方法。

        DrawMask將背景圖上的繪圖區(qū)域起始點(diǎn)、要繪制圖的起始點(diǎn)、遮罩蒙層的起始點(diǎn)進(jìn)行對(duì)齊,然后對(duì)背景圖上的繪圖矩陣區(qū)域執(zhí)行 Porter-Duff合并操作。

        下面是給圖片加一個(gè)圓形遮罩的示例:

        func drawCirclePic() {
         f, err := os.Open("./gopher.png")
         if err != nil {
          panic(err)
         }
         gopherImg, _, err := image.Decode(f)


         d := gopherImg.Bounds().Dx()
         
         //將一個(gè)cicle作為蒙層遮罩,圓心為圖案中點(diǎn),半徑為邊長(zhǎng)的一半
         c := circle{p: image.Point{X: d / 2, Y: d / 2}, r: d / 2
         circleImg := image.NewRGBA(image.Rect(00, d, d))
         draw.DrawMask(circleImg, circleImg.Bounds(), gopherImg, image.Point{}, &c, image.Point{}, draw.Over)

         SavePng(circleImg)
        }

        type circle struct { // 這里需要自己實(shí)現(xiàn)一個(gè)圓形遮罩,實(shí)現(xiàn)接口里的三個(gè)方法
         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)
        }

        // 對(duì)每個(gè)像素點(diǎn)進(jìn)行色值設(shè)置,在半徑以?xún)?nèi)的圖案設(shè)成完全不透明
        func (c *circle) At(x, y int) color.Color {
         xx, yy, rr := float64(x-c.p.X)+0.5float64(y-c.p.Y)+0.5float64(c.r)
         if xx*xx+yy*yy < rr*rr {
          return color.Alpha{A: 255}
         }
         return color.Alpha{}
        }

        給圖片加一個(gè)圓角遮罩的示例:

        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(00, 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(00, c.p.X, c.p.Y)
        }

        // 對(duì)每個(gè)像素點(diǎn)進(jìn)行色值設(shè)置,分別處理矩形的四個(gè)角,在四個(gè)角的內(nèi)切圓的外側(cè),色值設(shè)置為全透明,其他區(qū)域不透明
        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.5float64(y-c.r)+0.5float64(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.5float64(y-c.r)+0.5float64(c.r)
          inArea = true
         }
         // left bottom
         if x <= c.r && y >= (c.p.Y-c.r) {
          xx, yy, rr = float64(c.r-x)+0.5float64(y-(c.p.Y-c.r))+0.5float64(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.5float64(y-(c.p.Y-c.r))+0.5float64(c.r)
          inArea = true
         }

         if inArea && xx*xx+yy*yy >= rr*rr {
          return color.Alpha{}
         }
         return color.Alpha{A: 255}
        }

        在圖案進(jìn)行圓形、圓角繪制的過(guò)程中,因?yàn)樽钚挝皇?px,所以可能會(huì)有鋸齒邊緣的問(wèn)題,解決這個(gè)問(wèn)題可以通過(guò)先將原圖放大,遮罩后再縮小來(lái)解決。

        Reference

        The Go image/draw package - The Go Blog (golang.org)https://blog.golang.org/image-draw)

        Porter-Duff blend 模式 - Xamarin | Microsoft Docs(https://docs.microsoft.com/zh-tw/xamarin/xamarin-forms/user-interface/graphics/skiasharp/effects/blend-modes/porter-duff)


        還想了解更多嗎?

        歡迎加入我們GOLANG中國(guó)社區(qū):https://gocn.vip/


        《酷Go推薦》招募:


        各位Gopher同學(xué),最近我們社區(qū)打算推出一個(gè)類(lèi)似GoCN每日新聞的新欄目《酷Go推薦》,主要是每周推薦一個(gè)庫(kù)或者好的項(xiàng)目,然后寫(xiě)一點(diǎn)這個(gè)庫(kù)使用方法或者優(yōu)點(diǎn)之類(lèi)的,這樣可以真正的幫助到大家能夠?qū)W習(xí)到

        新的庫(kù),并且知道怎么用。


        大概規(guī)則和每日新聞?lì)愃?,如果?bào)名人多的話每個(gè)人一個(gè)月輪到一次,歡迎大家報(bào)名?。▓?bào)名地址:https://wj.qq.com/s2/7734329/3f51)


        掃碼也可以加入 GoCN 的大家族喲~


        瀏覽 170
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            日本大鸡巴操逼视频 | 操鸡吧视频 | 天天操天天日天天干 | 嫩草影院在线观看91麻豆 | www.久久.com | 国产黄色视频在线免费观看 | 啊~用力cao嗯cao烂我闺蜜 | 亚洲综合婷婷 | 黄动漫在线观看视频 | 三上悠亚的av |