Draw a rectangle in Golang?

huangapple go评论106阅读模式
英文:

Draw a rectangle in Golang?

问题

我想绘制一个包含一些矩形、条形码的邮寄标签,然后生成一个PNG/PDF文件。

在Go语言中,除了逐像素地使用基本图形绘制形状之外,还有更好的方法吗?

英文:

I want to draw a mailing label with some rectangles, barcodes, and then finally generate a PNG/PDF file.

Is there is a better way to draw a shape in Go other than to do it with primitives - pixel by pixel?

答案1

得分: 54

标准的Go库并不提供原始的绘图或绘画功能。

它提供了颜色模型(image/color 包)和一个带有多个实现的 Image 接口(image 包)。博客文章 Go Image 包 是对此的很好介绍。

它还提供了一个能够合并图像的能力(例如在彼此上绘制图像)的 image/draw 包中的不同操作。这可以用于更多的事情,比起一开始听起来的要多。有一篇很好的博客文章介绍了 image/draw 包,展示了它的一些潜力:Go image/draw 包

另一个例子是开源游戏 Gopher's Labyrinth声明:我是作者),它具有图形界面,只使用标准的Go库来组装视图。

Draw a rectangle in Golang?

它是开源的,可以查看它的源代码来了解它是如何实现的。它具有可滚动的游戏视图,其中包含移动的图像/动画。

标准库还支持读写常见的图像格式,如 GIFJPEGPNG,并且支持其他格式:BMPRIFFTIFF,甚至 WEBP(仅限读取/解码)。

虽然标准库不提供绘制线条和矩形的支持,但在图像上绘制线条和矩形是相当简单的。给定一个支持使用 Set(x, y int, c color.Color) 方法更改像素的 img 图像(例如 image.RGBA 对我们来说非常完美),以及一个类型为 color.Colorcol

// HLine 绘制水平线
func HLine(x1, y, x2 int) {
	for ; x1 <= x2; x1++ {
		img.Set(x1, y, col)
	}
}

// VLine 绘制垂直线
func VLine(x, y1, y2 int) {
	for ; y1 <= y2; y1++ {
		img.Set(x, y1, col)
	}
}

// Rect 利用 HLine() 和 VLine() 绘制矩形
func Rect(x1, y1, x2, y2 int) {
	HLine(x1, y1, x2)
	HLine(x1, y2, x2)
	VLine(x1, y1, y2)
	VLine(x2, y1, y2)
}

使用这些简单的函数,下面是一个可运行的示例程序,它绘制一条线和一个矩形,并将图像保存为 .png 文件:

import (
	&quot;image&quot;
	&quot;image/color&quot;
	&quot;image/png&quot;
	&quot;os&quot;
)

var img = image.NewRGBA(image.Rect(0, 0, 100, 100))
var col color.Color

func main() {
	col = color.RGBA{255, 0, 0, 255} // 红色
	HLine(10, 20, 80)
	col = color.RGBA{0, 255, 0, 255} // 绿色
	Rect(10, 10, 80, 50)

	f, err := os.Create(&quot;draw.png&quot;)
	if err != nil {
		panic(err)
	}
	defer f.Close()
	png.Encode(f, img)
}

如果你想绘制文本,可以使用 Go 实现的 FreeType。还可以查看这个问题,了解如何在图像上绘制字符串的简单介绍:https://stackoverflow.com/questions/38299930/how-do-add-a-text-label-to-an-image-in-go

如果你想要更高级和更复杂的绘图功能,还有许多外部库可用,例如:

https://github.com/llgcode/draw2d

https://github.com/fogleman/gg

英文:

The standard Go library does not provide primitive drawing or painting capabilities.

What it provides is models for colors (image/color package) and an Image interface with several implementations (image package). The blog post The Go Image package is a good introduction to this.

It also provides a capability to combine images (e.g. draw them on each other) with different operations in the image/draw package. This can be used to a lot more than it sounds at first. There is a nice blog article about the image/draw package which showcases some of its potential: The Go image/draw package

Another example is the open-source game Gopher's Labyrinth (disclosure: I'm the author) which has a graphical interface and it uses nothing else just the standard Go library to assemble its view.

Draw a rectangle in Golang?

It's open source, check out its sources how it is done. It has a scrollable game view with moving images/animations in it.

The standard library also supports reading and writing common image formats like GIF, JPEG, PNG, and support for other formats are available out of the box: BMP, RIFF, TIFF and even WEBP (only a reader/decoder).

Although support is not given by the standard library, it is fairly easy to draw lines and rectangles on an image. Given an img image which supports changing a pixel with a method: Set(x, y int, c color.Color) (for example image.RGBA is perfect for us) and a col of type color.Color:

// HLine draws a horizontal line
func HLine(x1, y, x2 int) {
	for ; x1 &lt;= x2; x1++ {
		img.Set(x1, y, col)
	}
}

// VLine draws a veritcal line
func VLine(x, y1, y2 int) {
	for ; y1 &lt;= y2; y1++ {
		img.Set(x, y1, col)
	}
}

// Rect draws a rectangle utilizing HLine() and VLine()
func Rect(x1, y1, x2, y2 int) {
	HLine(x1, y1, x2)
	HLine(x1, y2, x2)
	VLine(x1, y1, y2)
	VLine(x2, y1, y2)
}

Using these simple functions here is a runnable example program which draws a line and a rectangle and saves the image into a .png file:

import (
	&quot;image&quot;
	&quot;image/color&quot;
	&quot;image/png&quot;
	&quot;os&quot;
)

var img = image.NewRGBA(image.Rect(0, 0, 100, 100))
var col color.Color

func main() {
	col = color.RGBA{255, 0, 0, 255} // Red
	HLine(10, 20, 80)
	col = color.RGBA{0, 255, 0, 255} // Green
	Rect(10, 10, 80, 50)

	f, err := os.Create(&quot;draw.png&quot;)
	if err != nil {
		panic(err)
	}
	defer f.Close()
	png.Encode(f, img)
}

If you want to draw texts, you can use the Go implementation of FreeType. Also check out this question for a simple introduction to drawing strings on images: https://stackoverflow.com/questions/38299930/how-do-add-a-text-label-to-an-image-in-go

If you want advanced and more complex drawing capabilities, there are also many external libraries available, for example:

https://github.com/llgcode/draw2d

https://github.com/fogleman/gg

答案2

得分: 15

这里我们使用标准的golang库绘制了两个矩形。

// https://blog.golang.org/go-imagedraw-package

package main

import (
	"image"
	"image/color"
	"image/draw"
	"image/png"
	"os"
)

func main() {

	new_png_file := "/tmp/two_rectangles.png" // 输出图像保存在这里

	myimage := image.NewRGBA(image.Rect(0, 0, 220, 220)) // 背景矩形的 x1,y1, x2,y2
	mygreen := color.RGBA{0, 100, 0, 255} // R, G, B, Alpha

	// 用颜色 mygreen 填充整个背景
	draw.Draw(myimage, myimage.Bounds(), &image.Uniform{mygreen}, image.ZP, draw.Src)

	red_rect := image.Rect(60, 80, 120, 160) // 我们在上面的矩形上绘制的第二个矩形的几何形状
	myred := color.RGBA{200, 0, 0, 255}

	// 在绿色表面上创建一个红色矩形
	draw.Draw(myimage, red_rect, &image.Uniform{myred}, image.ZP, draw.Src)

	myfile, err := os.Create(new_png_file) // ... 现在让我们保存输出图像
	if err != nil {
		panic(err)
	}
	defer myfile.Close()
	png.Encode(myfile, myimage) // 输出文件 /tmp/two_rectangles.png
}

以上代码将生成一个名为 /tmp/two_rectangles.png 的 png 文件,其中包含我们的两个矩形:

Draw a rectangle in Golang?

以下代码将使用矩形创建一个棋盘图像:

package main

import (
	"fmt"
	"image"
	"image/color"
	"image/draw"
	"image/png"
	"os"
)

func main() {

	new_png_file := "/tmp/chessboard.png" // 输出图像保存在这里
	board_num_pixels := 240

	myimage := image.NewRGBA(image.Rect(0, 0, board_num_pixels, board_num_pixels))
	colors := make(map[int]color.RGBA, 2)

	colors[0] = color.RGBA{0, 100, 0, 255}   // 绿色
	colors[1] = color.RGBA{50, 205, 50, 255} // 青柠绿

	index_color := 0
	size_board := 8
	size_block := int(board_num_pixels / size_board)
	loc_x := 0

	for curr_x := 0; curr_x < size_board; curr_x++ {

		loc_y := 0
		for curr_y := 0; curr_y < size_board; curr_y++ {

			draw.Draw(myimage, image.Rect(loc_x, loc_y, loc_x+size_block, loc_y+size_block),
				&image.Uniform{colors[index_color]}, image.ZP, draw.Src)

			loc_y += size_block
			index_color = 1 - index_color // 从 0 切换到 1 切换到 0 切换到 1 ...
		}
		loc_x += size_block
		index_color = 1 - index_color // 从 0 切换到 1 切换到 0 切换到 1 ...
	}
	myfile, err := os.Create(new_png_file)
	if err != nil {
		panic(err.Error())
	}
	defer myfile.Close()
	png.Encode(myfile, myimage) // ... 保存图像
	fmt.Println("firefox ", new_png_file) // 查看图像问题:firefox /tmp/chessboard.png
}

Draw a rectangle in Golang?

英文:

Here we draw two rectangles using standard golang libraries

// https://blog.golang.org/go-imagedraw-package
package main
import (
&quot;image&quot;
&quot;image/color&quot;
&quot;image/draw&quot;
&quot;image/png&quot;
&quot;os&quot;
)
func main() {
new_png_file := &quot;/tmp/two_rectangles.png&quot; // output image will live here
myimage := image.NewRGBA(image.Rect(0, 0, 220, 220)) // x1,y1,  x2,y2 of background rectangle
mygreen := color.RGBA{0, 100, 0, 255}  //  R, G, B, Alpha
// backfill entire background surface with color mygreen
draw.Draw(myimage, myimage.Bounds(), &amp;image.Uniform{mygreen}, image.ZP, draw.Src)
red_rect := image.Rect(60, 80, 120, 160) //  geometry of 2nd rectangle which we draw atop above rectangle
myred := color.RGBA{200, 0, 0, 255}
// create a red rectangle atop the green surface
draw.Draw(myimage, red_rect, &amp;image.Uniform{myred}, image.ZP, draw.Src)
myfile, err := os.Create(new_png_file)     // ... now lets save output image
if err != nil {
panic(err)
}
defer myfile.Close()
png.Encode(myfile, myimage)   // output file /tmp/two_rectangles.png
}

above will generate a png file /tmp/two_rectangles.png with our two rectangles :

Draw a rectangle in Golang?

following code will create a chessboard image from rectangles

package main
import (
&quot;fmt&quot;
&quot;image&quot;
&quot;image/color&quot;
&quot;image/draw&quot;
&quot;image/png&quot;
&quot;os&quot;
)
func main() {
new_png_file := &quot;/tmp/chessboard.png&quot; // output image lives here
board_num_pixels := 240
myimage := image.NewRGBA(image.Rect(0, 0, board_num_pixels, board_num_pixels))
colors := make(map[int]color.RGBA, 2)
colors[0] = color.RGBA{0, 100, 0, 255}   // green
colors[1] = color.RGBA{50, 205, 50, 255} // limegreen
index_color := 0
size_board := 8
size_block := int(board_num_pixels / size_board)
loc_x := 0
for curr_x := 0; curr_x &lt; size_board; curr_x++ {
loc_y := 0
for curr_y := 0; curr_y &lt; size_board; curr_y++ {
draw.Draw(myimage, image.Rect(loc_x, loc_y, loc_x+size_block, loc_y+size_block),
&amp;image.Uniform{colors[index_color]}, image.ZP, draw.Src)
loc_y += size_block
index_color = 1 - index_color // toggle from 0 to 1 to 0 to 1 to ...
}
loc_x += size_block
index_color = 1 - index_color // toggle from 0 to 1 to 0 to 1 to ...
}
myfile, err := os.Create(new_png_file) 
if err != nil {
panic(err.Error())
}
defer myfile.Close()
png.Encode(myfile, myimage) // ... save image
fmt.Println(&quot;firefox &quot;, new_png_file) // view image issue : firefox  /tmp/chessboard.png
}

Draw a rectangle in Golang?

答案3

得分: 5

你可能正在寻找draw2d包。根据他们在github上的自述文件:

draw2d中的操作包括绘制多边形、弧线、贝塞尔曲线、绘制图像和使用TrueType字体进行文本渲染。所有绘图操作都可以通过仿射变换(缩放、旋转、平移)进行转换。

以下代码绘制了一个黑色矩形并将其写入.png文件。它使用的是v1版本(go get -u github.com/llgcode/draw2d)。

package main

import (
        "github.com/llgcode/draw2d/draw2dimg"

        "image"
        "image/color"
)

func main() {
        i := image.NewRGBA(image.Rect(0, 0, 200, 200))
        gc := draw2dimg.NewGraphicContext(i)
        gc.Save()
        gc.SetStrokeColor(color.Black)
        gc.SetFillColor(color.Black)
        draw2d.Rect(gc, 10, 10, 100, 100)
        gc.FillStroke()
        gc.Restore()

        draw2dimg.SaveToPngFile("yay-rectangle.png", i)
}

请参考github页面获取最新版本的信息。

英文:

You are probably looking for the draw2d package. From their github readme:

>Operations in draw2d include stroking and filling polygons, arcs, Bézier curves, drawing images and text rendering with truetype fonts. All drawing operations can be transformed by affine transformations (scale, rotation, translation).

The following code draws a black rectangle and writes it to a .png file. It is using the v1 release (go get -u github.com/llgcode/draw2d).

package main
import (
&quot;github.com/llgcode/draw2d/draw2dimg&quot;
&quot;image&quot;
&quot;image/color&quot;
)
func main() {
i := image.NewRGBA(image.Rect(0, 0, 200, 200))
gc := draw2dimg.NewGraphicContext(i)
gc.Save()
gc.SetStrokeColor(color.Black)
gc.SetFillColor(color.Black)
draw2d.Rect(gc, 10, 10, 100, 100)
gc.FillStroke()
gc.Restore()
draw2dimg.SaveToPngFile(&quot;yay-rectangle.png&quot;, i)
}

Please consult the github page for the newest version.

答案4

得分: 3

我来帮你翻译代码部分:

import (
    "os"
    "image"
    "image/png"
    _ "image/jpeg"
    "image/color"
    "image/draw"
)

func drawRectangle(img draw.Image, color color.Color, x1, y1, x2, y2 int) {
    for i := x1; i < x2; i++ {
        img.Set(i, y1, color)
        img.Set(i, y2, color)
    }

    for i := y1; i <= y2; i++ {
        img.Set(x1, i, color)
        img.Set(x2, i, color)
    }
}

func addRectangleToFace(img draw.Image, rect image.Rectangle) draw.Image {
    myColor := color.RGBA{255, 0, 255, 255}

    min := rect.Min
    max := rect.Max

    drawRectangle(img, myColor, min.X, min.Y, max.X, max.Y)

    return img
}

func getImageFromFilePath(filePath string) (draw.Image, error) {

    // 读取文件
    f, err := os.Open(filePath)
    if err != nil {
        return nil, err
    }
    defer f.Close()

    // 转换为image.Image
    orig, _, err := image.Decode(f)

    // 转换为可用的image
    b := orig.Bounds()
    img := image.NewRGBA(image.Rect(0, 0, b.Dx(), b.Dy()))
    draw.Draw(img, img.Bounds(), orig, b.Min, draw.Src)

    return img, err
}

func main() {
    // 读取文件并转换
    src, err := getImageFromFilePath("src.png")
    if err != nil {
        panic(err.Error())
    }

    myRectangle := image.Rect(10, 20, 30, 40)

    dst := addRectangleToFace(src, myRectangle)

    outputFile, err := os.Create("dst.png")
    if err != nil {
        panic(err.Error())
    }

    png.Encode(outputFile, dst)

    outputFile.Close()
}

这段代码的作用是从现有图片上绘制一个矩形(只有边框)。它使用了imageimage/draw包来进行图像处理。代码中的drawRectangle函数用于绘制矩形的边框,addRectangleToFace函数用于将矩形添加到图像上,getImageFromFilePath函数用于从文件路径获取图像。在main函数中,它读取名为"src.png"的文件并将其转换为图像,然后在图像上添加一个矩形,并将结果保存为"dst.png"文件。

你提供的代码中还包含了一个结果图片的链接,但我无法在文本中显示图片。如果你有其他问题,可以继续问我。

英文:

I got here because I wanted to draw a rectangle (just the border) on from an existing picture. It adds to @Fakeer response the reading and writing on disk.

import (
&quot;os&quot;
&quot;image&quot;
&quot;image/png&quot;
_ &quot;image/jpeg&quot;
&quot;image/color&quot;
&quot;image/draw&quot;
)
func drawRectangle(img draw.Image, color color.Color, x1, y1, x2, y2 int) {
for i:= x1; i&lt;x2; i++ {
img.Set(i, y1, color)
img.Set(i, y2, color)
}
for i:= y1; i&lt;=y2; i++ {
img.Set(x1, i, color)
img.Set(x2, i, color)
}
}
func addRectangleToFace(img draw.Image, rect image.Rectangle) (draw.Image) {
myColor := color.RGBA{255, 0, 255, 255}
min := rect.Min
max := rect.Max
drawRectangle(img, myColor, min.X, min.Y, max.X, max.Y)
return img
}
func getImageFromFilePath(filePath string) (draw.Image, error) {
// read file
f, err := os.Open(filePath)
if err != nil {
return nil, err
}
defer f.Close()
// convert as image.Image
orig, _, err := image.Decode(f)
// convert as usable image
b := orig.Bounds()
img := image.NewRGBA(image.Rect(0, 0, b.Dx(), b.Dy()))
draw.Draw(img, img.Bounds(), orig, b.Min, draw.Src)
return img, err
}
func main() {
// read file and convert it
src, err := getImageFromFilePath(&quot;src.png&quot;)
if err != nil {
panic(err.Error())
}
myRectangle := image.Rect(10, 20, 30, 40)
dst := addRectangleToFace(src, myRectangle)
outputFile, err := os.Create(&quot;dst.png&quot;)
if err != nil {
panic(err.Error())
}
png.Encode(outputFile, dst)
outputFile.Close()
}

Which gives the following result:
Draw a rectangle in Golang?

答案5

得分: 0

我尝试画一个给定线条粗细的矩形,但还很原始。

func Rect(x1, y1, x2, y2, thickness int, img *image.RGBA) {
    col := color.RGBA{0, 0, 0, 255}

    for t := 0; t < thickness; t++ {
        // 画水平线
        for x := x1; x <= x2; x++ {
            img.Set(x, y1+t, col)
            img.Set(x, y2-t, col)
        }
        // 画垂直线
        for y := y1; y <= y2; y++ {
            img.Set(x1+t, y, col)
            img.Set(x2-t, y, col)
        }
    }
}

// 测试处理程序
func draw(w http.ResponseWriter, r *http.Request) {
    img := image.NewRGBA(image.Rect(0, 0, 1200, 1800))
    Rect(5, 5, 1195, 1795, 2, img)
    png.Encode(w, img)
}

以上是给定线条粗细的矩形绘制的代码。

英文:

My noob shot at drawing a rectangle of given line thickness. Still primitive

func Rect(x1, y1, x2, y2, thickness int, img *image.RGBA) {
col := color.RGBA{0, 0, 0, 255}
for t:=0; t&lt;thickness; t++ {
// draw horizontal lines
for x := x1; x&lt;= x2; x++ {
img.Set(x, y1+t, col)
img.Set(x, y2-t, col)
}
// draw vertical lines
for y := y1; y &lt;= y2; y++ {
img.Set(x1+t, y, col)
img.Set(x2-t, y, col)
}
}
}
// handler to test
func draw(w http.ResponseWriter, r *http.Request) {
img := image.NewRGBA(image.Rect(0, 0, 1200, 1800))
Rect(5, 5, 1195, 1795, 2, img)
png.Encode(w, img)
}

huangapple
  • 本文由 发表于 2015年3月12日 00:40:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/28992396.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定