来一个嫦娥奔月祝 xdm 中秋快乐

简介: GOLang 有很多图形库,咱们今天玩一个简单的标准图形库 imageimage 包实现了一个基本的二维图像库,基本的接口叫做 Image 。

来一个嫦娥奔月祝 xdm 中秋快乐

GOLang 有很多图形库,咱们今天玩一个简单的标准图形库 image

image 包实现了一个基本的二维图像库,基本的接口叫做 Image

image.png

我们可以这样导入包

"image"
"image/color"
"image/draw"
"image/jpeg"
"image/png"

GO image 的官方文档: pkg.go.dev/image 在 GOLAND 开发工具里面导入image 包,我们可以看到源码目录如下

image.png

  • color

实现了一个基本的颜色库

  • draw

绘制提供图像组成功能

  • gif

gif 图像解码器和编码器

  • jpeg

JPEG 图像解码器和编码器

  • png

PNG 图像解码器和编码器

  • internal

imageutil包含与图像相关的包共享的代码

image.go 源码

图像是一个有限的矩形颜色网格。从颜色中获取的颜色值

type Config struct {
  ColorModel    color.Model
  Width, Height int
}
type Image interface {
  ColorModel() color.Model
  Bounds() Rectangle
  At(x, y int) color.Color
}

image 包里面的 image.go 是具体实现,且包里面有相应的单元测试可以模仿学习 ,一起来看看 Image 接口 , 这个 Image 接口是 image 包的基本接口,非常重要

一个图像包含颜色,它是在 image/color 包中进行描述的 , Image 接口的值是通过调用这样的函数(NewRGBANewPaletted,或通过调用解码的 io)来创建的

  • ColorModel() color.Model

ColorModel返回图像的颜色模型

  • Bounds() Rectangle

Bounds返回At可以为其返回非零颜色的域,边界不一定包含点(0,0)。

  • At(x, y int) color.Color

At 返回像素在 (x, y) 处的颜色 ,

At(Bounds().Min.X, Bounds().Min.Y) 会返回网格左上角的像素

At(Bounds().Max.X-1, Bounds().Max.Y-1) 会返回网格右下角的像素

咱们可以通过 image 的单元测试来玩一下这个库

案例1 画一张 png 图片

我们使用“image/png”包来进行绘制图像

// 画一张彩图
func drawEncode(){
  const width, height = 500, 500
  // 画一张彩图,指定好宽和高
  img := image.NewNRGBA(image.Rect(0, 0, width, height))
    // 一张个图像分为 上下两个部分进行渲染
  for y := 0; y < height/2; y++ {
    for x := 0; x < width; x++ {
      img.Set(x, y, color.NRGBA{
        R: uint8((x - y) & 255),
        G: uint8((x - y) << 1 & 255),
        B: uint8((x - y) << 2 & 255),
        A: 255,
      })
    }
  }
  for y := height/2; y < height; y++ {
    for x := 0; x < width; x++ {
      img.Set(x, y, color.NRGBA{
        R: uint8((x + y) & 255),
        G: uint8((x + y) << 1 & 255),
        B: uint8((x + y) << 2 & 255),
        A: 255,
      })
    }
  }
  f, err := os.Create("image.png")
  if err != nil {
    log.Fatal(err)
  }
  if err := png.Encode(f, img); err != nil {
    f.Close()
    log.Fatal(err)
  }
  if err := f.Close(); err != nil {
    log.Fatal(err)
  }
}
  • image.NewNRGBA

创建一张图片,指定好宽和高

  • img.Set(x, y, color.NRGBA{})

image.png

设置颜色

NRGBA 结构体如下:

// NRGBA represents a non-alpha-premultiplied 32-bit color.
type NRGBA struct {
   R, G, B, A uint8
}

我们知道红绿蓝是计算机色彩的三基色

R: uint8((x - y) & 255),
G: uint8((x - y) << 1 & 255),
B: uint8((x - y) << 2 & 255),

通过移位 方式来计算 R G B 的值分别是多少

  • R

红色

  • G

绿色

  • B

蓝色

  • A

透明度,255 则为不透明 , 0 为全透明

效果如下:

透明度 255 的效果如下

image.png

透明度上半部分设置 255, 下半部分设置 100

image.png

案例 2 来一个应景的 嫦娥奔月

准备如下素材

1、月亮一张

moon.jpg

image.png

2、嫦娥一枚

goddess.jpg

image.png

尝试使用 golang image 里面提供的包 jpeg 来进行图片合并操作

image/jpeg
func drawGoddess(){
  file, err := os.Create("res.jpg")
  if err != nil {
    fmt.Println(err)
  }
  defer file.Close()
  file1, err := os.Open("./back.jpg")
  if err != nil {
    fmt.Println(err)
  }
  defer file1.Close()
  img, _ := jpeg.Decode(file1)
  file2, err := os.Open("./goddess.jpg")
  if err != nil {
    fmt.Println(err)
  }
  defer file2.Close()
  img2, _ := jpeg.Decode(file2)
  file3, err := os.Open("./moon.jpg")
  if err != nil {
    fmt.Println(err)
  }
  defer file3.Close()
  img3, _ := jpeg.Decode(file3)
    // 设置画布大小 1250 * 790
  jpg := image.NewRGBA(image.Rect(0, 0, 1250, 790))
  draw.Draw(jpg, jpg.Bounds(), img, img.Bounds().Min, draw.Over)       //首先将一个图片信息存入jpg
  draw.Draw(jpg, jpg.Bounds(), img3, img3.Bounds().Min.Sub(image.Pt(140, 0)), draw.Over) //将另外一张图片信息存入jpg
  draw.Draw(jpg, jpg.Bounds(), img2, img2.Bounds().Min.Sub(image.Pt(790, 315)), draw.Over)
  jpeg.Encode(file, jpg, nil)
}
  • 创建一张图片 res.jpg , 打开三张图片,分别是月亮,嫦娥,和背景图片
  • jpeg.Decode 将 月亮,嫦娥,和背景图片解码
  • image.NewRGBA

创建画布,设置画布大小 1250 * 790

  • draw.Draw

分别将月亮,嫦娥,和背景图片 画到画布上面,并设置好合适的位置

  • jpeg.Encode

将图片数据,回写到 res 的 io 中,生成 res.jpg 文件,效果如下图

image.png

案例 3 将图片做成字符画

将图片转成字符串也非常简单,思路简单如下几步:

  • 读取图片,成二进制流
  • 将二进制流通过 base64 加密成字符串
  • 再使用 base64 将字符串转成二进制流
  • 使用 “image/png” 的包解码出来,按照图片的宽高,咱们用字符来填充即可

上述第二步主要是得到一个字符串,这个字符串,可以写到文件中,也可以获取后,定义成 const,作为 demo

head.png 原图如下:

image.png

func imgToBase64()string{
  srcByte, err := ioutil.ReadFile("head.png")
  if err != nil {
    log.Fatal(err)
  }
  res := base64.StdEncoding.EncodeToString(srcByte)
  return res
}
func drawDecode(str string){
  // 例如知道某张图片的base64,那么就可以直接定义一个常量来进行处理
  //const head = `iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAIAAAD9b0jDAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAEnQAABJ0Ad5mH3gAAAFpSURBVEhLtZTblcMgDESpi4JcD9W4GRfjlTTSIBOcxTnJfOzyGF09QlLOH2iEHq2WUmo7fD8I17zft6l5Feo00bb7kcig+QB6VGkwzKSsDtUVTKKSargTU1ygekqoLWASBdTSiYZKzczwq2rbIxRwhIhWodzACUpzc7OdE0TrUNyoppUn5vJME7JWT0Mwa3A9mCnbVA8HaiMYqMtPam/tsBRIn3xMTH30Tr1xjtG3vvsMSnaSnvnyFfoV/RRqbaeuZy1OhXmpevRDqB3fieGx8oT+FkeFHa5/G1CHWvV7YuHyqvWcleYWwLxmYHlJReIEULdNY/UvXFMomo9C30BxOX7bOipBQXknBwwf1HSiptdBIsdNpaZUUOzuUblwW+tcknUK9YHqv6EQTBUEQqMEeifQvrxkckg/wN53ng07/fRVEQ8nW8mBcqc/qp4i7mgVrDzHw6B+CocpDcdkRSRY9ubjrmj/izrPP5x5Eu8xcV+2AAAAAElFTkSuQmCC`
    // 使用 png.Decode 解码 png 图片
    img, err := png.Decode(base64.NewDecoder(base64.StdEncoding, strings.NewReader(str)))
    if err != nil {
      log.Fatal(err)
    }
    levels := []string{" ", "$", "=", "@", "█"}
    for y := img.Bounds().Min.Y; y < img.Bounds().Max.Y; y++ {
      for x := img.Bounds().Min.X; x < img.Bounds().Max.X; x++ {
        c := color.GrayModel.Convert(img.At(x, y)).(color.Gray)
        level := c.Y / 51 // 51 * 5 = 255
        if level == 5 {
          level--
        }
        fmt.Print(levels[level])
      }
      fmt.Print("\n")
    }
}
  • imgToBase64

将图片二进制流通过 base64 加密得到 字符串

  • drawDecode

从字符串中解析出 png 图片,获取到 png 图片的属性,并使用自定义的字符进行填充

  • color.GrayModel.Convert

设置颜色模式

效果如下:

██████████████████████████████████████████████████████
████████████████████@ ████████████████████████████████
████████████████████@ ████████████████████████████████
████████████████████@ ████████████████████████████████
████████@ ███$$██   = ██$@   █=  @████████████████████
█████████=$█@ ██$=██$ ██$ ██$ @█@ ████████████████████
██████████$= ██@ ███@ ██$@██@ ███ @███████████████████
███████████ @██@ ███@ ██$@██@$███ @███████████████████
██████████$= ██@ ███@ ██$@██@$███ @███████████████████
█████████=$█=$██ =██  ██$@██@$███ @███████████████████
████████= ███ $██   @ ██$@██@$███ @███████████████████
██████████████████████████████████████████████████████
██████████████████████████████████████████████████████
██████████████████████████████████████████████████████
██████$█████████$ ███ ██████ ████=@████████████   ████
██████$██████@  @████ ██████ ████=@█████@      @██████
██████$████████$@████ ████@$  @      @██@$████████████
█           ███$@█$██ ██@@@= @$██=@█@@██==███$@███████
█ ████$████$█$    $@█ ██$█@@ ████=@█@@██$@███$@███████
█ ████$████$███ @██$█ @$@█$@ ████$@█@@██           @██
█ ████$████$██@  @█== $=████ █        $██████$@███████
█           ██=$@=@█=$ █████ ████ $███████ ██$@█ █████
█ ████$████$█@=$@███ @ @████ ███@=$@█████$@██$@█@ ████
██████$██████=█$@██ $█@ ████ ██@ ██ ████ @███$@██@ @██
██████$████████$@█  ███= ███ █@ ███@ @█=@████$@███@$██
██████$████████$@$=█████=$██ = ██████ @███@   ████████
██████████████████████████████████████████████████████
██████████████████████████████████████████████████████
██████████████████████████████████████████████████████
██████████████████████████████████████████████████████
██████████████████████████████████████████████████████

参考资料:

GO image 官方文档

欢迎点赞,关注,收藏

朋友们,你的支持和鼓励,是我坚持分享,提高质量的动力

image.png

好了,本次就到这里

技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。

我是阿兵云原生,欢迎点赞关注收藏,下次见~


相关文章
|
6月前
|
存储 Linux Windows
快乐生活,快乐分享,5款实用的小软件推荐
分享是一种神奇的东西,它使快乐增大,它使悲伤减小,坚持分享一些好用的软件给大家,今天继续为大家带来五款好用的小软件。
60 0
|
数据采集 Web App开发 XML
干了这碗“美丽汤”,网页解析倍儿爽
HTML 文档本身是结构化的文本,有一定的规则,通过它的结构可以简化信息提取。于是,就有了lxml、pyquery、BeautifulSoup等网页信息提取库。一般我们会用这些库来提取网页信息。
生活 | 七夕快乐!
今天是中国的七夕节!那就简单的祝大家情人节快乐!没有对象的自己new一个,或者画一个。
|
程序员
程序猿也浪漫
程序猿也浪漫
|
数据采集 数据挖掘 程序员
【每周一坑】程序猿的浪漫
长久以来,大家对程序员的印象是“呆板”、”内向”等,殊不知他们也有浪漫的一面。把找不到对象归因于职业性质,这个锅,面向对象的编程语言不背!(但这个报道真不是来黑程序员的吗……)
【代码分享】【像极了恋爱】甜甜的汤圆,祝丽姿元宵快乐(表白特效)
【代码分享】【像极了恋爱】甜甜的汤圆,祝丽姿元宵快乐(表白特效)
115 0
|
Windows
写文章狗屁不通,怎么办?跪求高人指点!
写文章狗屁不通,怎么办?跪求高人指点!
189 0
写文章狗屁不通,怎么办?跪求高人指点!
|
Python
最长情的告白就是陪伴【Python七夕祝福】——那些浪漫的开始
最长情的告白就是陪伴【Python七夕祝福】——那些浪漫的开始
166 0
最长情的告白就是陪伴【Python七夕祝福】——那些浪漫的开始
|
前端开发 程序员
程序猿的中秋原来可以这样过
程序猿的中秋原来可以这样过
104 0
程序猿的中秋原来可以这样过
|
Python
情人节快到了@!没想好送什么礼物吗?python为你打造一款表白神器,瞧好了你
前言马上情人节了,送什么给你女神呢。鲜花?口红?香水?还远远不够!再写一个告白程序,给她一个惊喜!那才刚刚好,保证是最特别的礼物! 我们做所有事情都要有一个思路, 写一个程序也不例外,本文代码分为了4个步骤 引用tkinter工具包 关闭所有窗口 定义不喜欢按钮的提示 窗口不能关 引用t...
2139 0