我希望绘制一张带有矩形、条形码的邮标签,并最终生成PNG/PDF文件。
在Go语言中,除了逐像素使用原始图形绘制,是否存在更好的绘制形状的方式?
在Go语言中,除了逐像素使用原始图形绘制,是否存在更好的绘制形状的方式?
标准的Go库没有提供原始的绘图或绘画功能。
它提供了颜色模型(image/color
包)和一个带有多个实现的Image
接口(image
包)。博客文章The Go Image package是对此的很好介绍。
它还提供了一种组合图像(例如,在彼此上绘制它们)并使用image/draw
包中的不同操作的能力。这可以用于比它听起来更多的东西。有一篇关于image/draw
包的不错的博客文章,展示了它的一些潜力:The Go image/draw package
Set(x, y int, c color.Color)
(例如image.RGBA
非常适合我们)更改像素的img
图像和类型为color.Color
的col
:// HLine draws a horizontal line
func HLine(x1, y, x2 int) {
for ; x1 <= x2; x1++ {
img.Set(x1, y, col)
}
}
// VLine draws a veritcal line
func VLine(x, y1, y2 int) {
for ; y1 <= 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)
}
.png
文件:import (
"image"
"image/color"
"image/png"
"os"
)
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("draw.png")
if err != nil {
panic(err)
}
defer f.Close()
png.Encode(f, img)
}
如果您想绘制文本,可以使用FreeType的Go实现。此外,请参阅这个问题,了解在图像上绘制字符串的简单介绍:如何在Go中向图像添加简单的文本标签?
如果您需要高级和更复杂的绘图功能,还有许多外部库可供选择,例如:
这里我们使用标准的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" // 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(), &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, &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
}
上述代码将生成一个png文件/tmp/two_rectangles.png
,其中包含我们的两个矩形:
以下代码将从矩形创建一个棋盘图像。
package main
import (
"fmt"
"image"
"image/color"
"image/draw"
"image/png"
"os"
)
func main() {
new_png_file := "/tmp/chessboard.png" // 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 < 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 // 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("firefox ", new_png_file) // view image issue : firefox /tmp/chessboard.png
}
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)
}
./main.go:16: undefined: draw2d in draw2d.Rect
。相反,github页面上的示例是可行的。 - iacopoimport (
"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) {
// 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("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()
}
我尝试绘制给定线宽度的矩形,但是仍很原始。
func Rect(x1, y1, x2, y2, thickness int, img *image.RGBA) {
col := color.RGBA{0, 0, 0, 255}
for t:=0; t<thickness; t++ {
// draw horizontal lines
for x := x1; x<= x2; x++ {
img.Set(x, y1+t, col)
img.Set(x, y2-t, col)
}
// draw vertical lines
for y := y1; y <= 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)
}