zoukankan      html  css  js  c++  java
  • Golang 绘图基础 -绘制简单图形

    前一节讲的是 绘图到不同输出源,请看地址: http://www.cnblogs.com/ghj1976/p/3440856.html

    上一节的例子效果是通过设置每一个点的的RGBA属性来实现的,这是最基础的方式,通过这种方式我们可以绘制任意形状的图形。

    1、设置点的颜色一个简单例子:

    效果如下:

    123

    代码如下,跟最初我们的代码唯一不同的是设置点颜色时,多了一个条件判断语句:if x%8 == 0 ,代码如下,这种情况下,其实我们通过算法简单的实现了画垂直线的效果:

       1: package main
       2:  
       3: import (
       4:     "fmt"
       5:     "image"
       6:     "image/color"
       7:     "image/png"
       8:     "log"
       9:     "os"
      10: )
      11:  
      12: func main() {
      13:     const (
      14:         dx = 300
      15:         dy = 500
      16:     )
      17:  
      18:     // 需要保存的文件
      19:     imgcounter := 123
      20:     imgfile, _ := os.Create(fmt.Sprintf("%03d.png", imgcounter))
      21:     defer imgfile.Close()
      22:  
      23:     // 新建一个 指定大小的 RGBA位图
      24:     img := image.NewNRGBA(image.Rect(0, 0, dx, dy))
      25:  
      26:     for y := 0; y < dy; y++ {
      27:         for x := 0; x < dx; x++ {
      28:  
      29:             if x%8 == 0 {
      30:                 // 设置某个点的颜色,依次是 RGBA
      31:                 img.Set(x, y, color.RGBA{uint8(x % 256), uint8(y % 256), 0, 255})
      32:             }
      33:         }
      34:     }
      35:  
      36:     // 以PNG格式保存文件
      37:     err := png.Encode(imgfile, img)
      38:     if err != nil {
      39:         log.Fatal(err)
      40:     }
      41:  
      42: }

    比如下面一个函数就是简单的画水平线的代码函数。

       1: // 画 水平线
       2: func (img *Image) drawHorizLine(color color.Color, fromX, toX, y int) {
       3:     // 遍历画每个点
       4:     for x := fromX; x <= toX; x++ {
       5:         img.Set(x, y, color)
       6:     }
       7: }

     

    2、划线

    Golang 官方库没有提供划线的库,不过既然有了画点的方法,我们就可以根据一套算法画出点,下面的效果和代码是按照 Bresenham's line algorithm 算法画的线。

    http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm 

    这个算法画的线简单可以用下面图来标示:

    800px-Bresenham.svg

    下面演示代码画出来的效果图如下:

    注意,为了便于看到效果, 图的左右都画了一条竖线,斜线是按照上面算法画出来的。

    250

    相关代码如下:
    这里的代码借鉴了下面的代码。
    https://github.com/akavel/polyclip-go/blob/9b07bdd6e0a784f7e5d9321bff03425ab3a98beb/polyutil/draw.go

       1: package main
       2:  
       3: import (
       4:     "fmt"
       5:     "image"
       6:     "image/color"
       7:     "image/png"
       8:     "log"
       9:     "os"
      10: )
      11:  
      12: // Putpixel describes a function expected to draw a point on a bitmap at (x, y) coordinates.
      13: type Putpixel func(x, y int)
      14:  
      15: // 求绝对值
      16: func abs(x int) int {
      17:     if x >= 0 {
      18:         return x
      19:     }
      20:     return -x
      21: }
      22:  
      23: // Bresenham's algorithm, http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
      24: // https://github.com/akavel/polyclip-go/blob/9b07bdd6e0a784f7e5d9321bff03425ab3a98beb/polyutil/draw.go
      25: // TODO: handle int overflow etc.
      26: func drawline(x0, y0, x1, y1 int, brush Putpixel) {
      27:     dx := abs(x1 - x0)
      28:     dy := abs(y1 - y0)
      29:     sx, sy := 1, 1
      30:     if x0 >= x1 {
      31:         sx = -1
      32:     }
      33:     if y0 >= y1 {
      34:         sy = -1
      35:     }
      36:     err := dx - dy
      37:  
      38:     for {
      39:         brush(x0, y0)
      40:         if x0 == x1 && y0 == y1 {
      41:             return
      42:         }
      43:         e2 := err * 2
      44:         if e2 > -dy {
      45:             err -= dy
      46:             x0 += sx
      47:         }
      48:         if e2 < dx {
      49:             err += dx
      50:             y0 += sy
      51:         }
      52:     }
      53: }
      54:  
      55: func main() {
      56:  
      57:     const (
      58:         dx = 300
      59:         dy = 500
      60:     )
      61:  
      62:     // 需要保存的文件
      63:  
      64:     // 新建一个 指定大小的 RGBA位图
      65:     img := image.NewNRGBA(image.Rect(0, 0, dx, dy))
      66:  
      67:     drawline(5, 5, dx-8, dy-10, func(x, y int) {
      68:         img.Set(x, y, color.RGBA{uint8(x), uint8(y), 0, 255})
      69:     })
      70:  
      71:     // 左右都画一条竖线
      72:     for i := 0; i < dy; i++ {
      73:         img.Set(0, i, color.Black)
      74:         img.Set(dx-1, i, color.Black)
      75:     }
      76:  
      77:     imgcounter := 250
      78:     imgfile, _ := os.Create(fmt.Sprintf("%03d.png", imgcounter))
      79:     defer imgfile.Close()
      80:  
      81:     // 以PNG格式保存文件
      82:     err := png.Encode(imgfile, img)
      83:     if err != nil {
      84:         log.Fatal(err)
      85:     }
      86: }

     

    3、特殊图形

    这次绘制出来的图形效果如下:

    1234

     

    相关代码如下:
    这里的代码借鉴了下面的代码:
    https://github.com/xMachinae/pallinda13/blob/master/uppg2.go

       1: package main
       2:  
       3: import (
       4:     "fmt"
       5:     "image"
       6:     "image/png"
       7:     "log"
       8:     "os"
       9: )
      10:  
      11: func Pic(dx, dy int) [][]uint8 {
      12:     pic := make([][]uint8, dx)
      13:     for i := range pic {
      14:         pic[i] = make([]uint8, dy)
      15:         for j := range pic[i] {
      16:             pic[i][j] = uint8(i * j)
      17:         }
      18:     }
      19:     return pic
      20: }
      21:  
      22: func main() {
      23:     Show(Pic)
      24: }
      25:  
      26: func Show(f func(int, int) [][]uint8) {
      27:     const (
      28:         dx = 256
      29:         dy = 256
      30:     )
      31:     data := f(dx, dy) // 图片坐标点的颜色二维数组。
      32:     m := image.NewNRGBA(image.Rect(0, 0, dx, dy))
      33:     for y := 0; y < dy; y++ {
      34:         for x := 0; x < dx; x++ {
      35:             v := data[y][x]
      36:             i := y*m.Stride + x*4
      37:             m.Pix[i] = v
      38:             m.Pix[i+1] = v
      39:             m.Pix[i+2] = 255
      40:             m.Pix[i+3] = 255
      41:         }
      42:     }
      43:     ShowImage(m)
      44: }
      45:  
      46: func ShowImage(m image.Image) {
      47:  
      48:     // 需要保存的文件
      49:     imgcounter := 1234
      50:     imgfile, _ := os.Create(fmt.Sprintf("%03d.png", imgcounter))
      51:     defer imgfile.Close()
      52:  
      53:     // 以PNG格式保存文件
      54:     err := png.Encode(imgfile, m)
      55:     if err != nil {
      56:         log.Fatal(err)
      57:     }
      58:  
      59: }

     

    更复杂的算法

    比如下面代码实现了图片简单的上下左右翻转的功能。

    图片旋转的算法
    https://github.com/mpl/goexif/blob/a588a5577cedfda71e3645f8137c38495f308f6c/exif/rotate_test.go

  • 相关阅读:
    tr命令修剪换行符
    K8S从secret文件生成密钥后,如何更新Kubernetes上的密钥呢?
    tcpdump
    wireshark怎么抓包、wireshark抓包详细图文教程
    Kubernetes v1.15.3 升级到 v1.18.5 心得
    Python 简明教程 --- 20,Python 类中的属性与方法
    php大文件(视频)上传解决方案
    求大文件(视频)上传解决方案
    wordpress粘贴word图片且图片文件自动上传功能
    CMS粘贴word图片且图片文件自动上传功能
  • 原文地址:https://www.cnblogs.com/ghj1976/p/3441536.html
Copyright © 2011-2022 走看看