web-dev-qa-db-fra.com

Dessiner un rectangle à Golang?

Je veux dessiner une étiquette de publipostage avec des rectangles, des codes à barres, puis enfin générer un fichier PNG/PDF.

Existe-t-il une meilleure façon de dessiner une forme dans Go que de le faire avec des primitives - pixel par pixel?

22
Fakeer

La bibliothèque Go standard ne fournit pas de capacités de dessin ou de peinture primitives.

Il fournit des modèles de couleurs ( image/color package) et une interface Image avec plusieurs implémentations ( image package). Le billet de blog Le package Go Image est une bonne introduction à cela.

Il offre également la possibilité de combiner des images (par exemple, les dessiner les unes sur les autres) avec différentes opérations dans le package image/draw . Cela peut être utilisé pour beaucoup plus qu'il n'y paraît au premier abord. Il y a un bel article de blog sur le package image/draw Qui présente une partie de son potentiel: Le package Go image/draw

Un autre exemple est le jeu open source Labyrinthe de Gopher ( divulgation: je suis l'auteur) qui a une interface graphique et qui n'utilise rien d'autre que la bibliothèque standard Go pour assembler sa vue.

Gopher's Labyrinth Screenshot

C'est open source, consultez ses sources comment c'est fait. Il a une vue de jeu déroulante avec des images/animations en mouvement.

La bibliothèque standard prend également en charge la lecture et l'écriture de formats d'image courants tels que GIF , JPEG , PNG , et la prise en charge d'autres formats est disponible immédiatement: BMP , RIFF , TIFF et même WEBP (uniquement un lecteur/décodeur).

Bien que le support ne soit pas fourni par la bibliothèque standard, il est assez facile de dessiner des lignes et des rectangles sur une image. Étant donné une image img qui prend en charge la modification d'un pixel avec une méthode: Set(x, y int, c color.Color) (par exemple image.RGBA est parfait pour nous) et un col de 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)
}

En utilisant ces fonctions simples, voici un exemple de programme exécutable qui dessine une ligne et un rectangle et enregistre l'image dans un fichier .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)
}

Si vous voulez dessiner des textes, vous pouvez utiliser le implémentation Go de FreeType . Consultez également cette question pour une introduction simple au dessin de chaînes sur des images: Comment ajouter une simple étiquette de texte à une image dans Go?

Si vous voulez des capacités de dessin avancées et plus complexes, il y a aussi de nombreuses bibliothèques externes disponibles, par exemple:

https://github.com/llgcode/draw2d

https://github.com/fogleman/gg

41
icza

Voici comment dessiner deux rectangles à l'aide des bibliothèques de golang standard

// 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 lives here

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

    // backfill entire surface with green
    draw.Draw(myimage, myimage.Bounds(), &image.Uniform{mygreen}, image.ZP, draw.Src)

    red_rect := image.Rect(60, 80, 120, 160) //  geometry of 2nd 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 imag
    if err != nil {
        panic(err)
    }
    png.Encode(myfile, myimage)   // output file /tmp/two_rectangles.png
}

ci-dessus va générer un fichier png avec nos deux rectangles:

le code suivant créera une image d'échiquier à partir de rectangles

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}   // 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
}

5
Scott Stensland

Vous recherchez probablement le package draw2d . À partir de leur github readme:

Les opérations dans draw2d incluent le tracé et le remplissage de polygones, d'arcs, de courbes de Bézier, le dessin d'images et le rendu de texte avec des polices TrueType. Toutes les opérations de dessin peuvent être transformées par des transformations affines (échelle, rotation, translation).

Le code suivant dessine un rectangle noir et l'écrit dans un .png fichier. Il utilise la version 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)
}

Veuillez consulter la page github pour la dernière version.

5
Rick Smith

Mon noob a tiré sur le dessin d'un rectangle d'une épaisseur de ligne donnée. Encore primitif

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)
}
1
Fakeer