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?
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.
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 <= 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)
}
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 (
"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)
}
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: How to add a simple 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: