Dessiner un rectangle à Golang?

est la seule façon de dessiner une forme dans Go avec une certaine largeur de ligne pour le faire avec des primitives pixel par pixel?

je veux dessiner un label avec quelques rectangles et codes-barres, générer et sortir un PNG/PDF.

18
demandé sur Fakeer 2015-03-11 19:40:40

4 réponses

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

Ce qu'il fournit des modèles pour les couleurs (image/color paquet) et un Image interface avec plusieurs implémentations (image paquet). Le blog le paquet Image Go est une bonne introduction à ce.

il permet également de combiner des images (par ex. les dessiner sur chaque autres), avec des opérations dans le image/draw package. Cela peut être utilisé à beaucoup plus que cela ne semble au début. Il ya un bel article de blog sur le image/draw package qui met en vedette certains de ses potentiels: Go image/tirage paquet

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

Gopher's Labyrinth Screenshot

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

la bibliothèque standard prend également en charge la lecture et l'écriture de formats d'image communs comme GIF, JPEG,PNG, et le support d'autres formats sont disponibles de la boîte: BMP, RIFF, TIFF et même WEBP (seulement 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. Compte tenu de l' img image 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)
}

utilisation de ces fonctions simples voici un exemple de programme exécutable qui dessine une ligne et un rectangle et sauve l'image dans un .png fichier:

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 mise en œuvre de FreeType. Consultez également cette question pour une introduction simple au dessin des chaînes sur les images:comment ajouter une étiquette de texte simple à 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 disponible, par exemple:

http://github.com/llgcode/draw2d/

https://github.com/fogleman/gg

36
répondu icza 2018-08-01 07:26:54

vous cherchez probablement le draw2d paquet. De leur github readme:

les opérations de draw2d incluent le Strike et le remplissage des polygones, des arcs, des courbes de Bézier, le dessin des 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 le v1 libération (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)
}

consultez la page github pour la nouvelle version.

4
répondu Rick Smith 2017-05-15 15:28:52

Voici comment dessiner deux rectangles en utilisant les bibliothèques 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"

    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, _ := os.Create(new_png_file)     // ... now lets save imag
    png.Encode(myfile, myimage)
}

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

le code suivant va créer 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
}

3
répondu Scott Stensland 2018-07-16 01:59:49

ma prise de vue noob à dessiner un rectangle d'épaisseur de ligne donnée. Encore primitive

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)
}
0
répondu Fakeer 2015-03-15 03:56:43