Paulo Henrique Rodrigues Pinheiro

Um blog sobre programação para programadores!


Arte generativa com fórmula simples em Go

Gerando imagens legais, ou arte generativa com uma fórmula simples em Go (Golang)

Imagem de uma fórmula matemática grafitada em vários locais de Campinas

Inspiração

Essa imagem, que me persegue por várias ruas do Centro de Campinas, me faz pensar em alguma forma de desenhar através de um programa.Em outros momentos já vinha testando alguma coisa:

https://paulohrpinheiro.xyz/texts/go/2019-02-18-gerando-imagens-em-go-com-biblioteca-padrao.html

https://github.com/paulohrpinheiro/generative-art

Explorando essa fórmula, da maneira que costumo, cheguei a uma redução bem interessante:


C + C * X * Y

Em que C é uma constante qualquer, e o par X, Y, coordenadas da imagem gerada em um tamanho predeterminado (em geral 1000 pontos) a partir da origem (0,0). Mas o interessante é colorir essas imagens, para isso é usado resultado dessa conta módulo M, em que M é o máximo de cores que se deseja usar.

O programa

PS: usei range no loop for, coisa que só está disponível na versão 1.22rc1, futuramente 1.22!


package main

import (
    "flag"
    "image"
    "image/color/palette"
    "image/png"
    "os"
)

const (
    defaultImageSize = 1000
    defaultMaxColors = 150
    defaultConstant  = 10
    defaultFileName  = "formula.png"
)

func main() {
    fileName := flag.String("filename", defaultFileName, "filename to save image (.png)")
    imageSize := flag.Int("size", defaultImageSize, "size of image")
    constant := flag.Int("constant", defaultConstant, "constant for formula (c): c-c*x*y")
    maxColors := flag.Int("colors", len(palette.WebSafe), "number of colors")

    flag.Parse()

    rect := image.Rect(0, 0, *imageSize, *imageSize)
    img := image.NewPaletted(rect, palette.WebSafe)

    for x := range *imageSize {
        for y := range *imageSize {
            value := (*constant - *constant*x*y)
            color := uint8(value % *maxColors)

            img.SetColorIndex(x, y, color)
        }
    }

    f, err := os.Create(*fileName)
    if err != nil {
        panic(err)
    }

    defer f.Close()
    png.Encode(f, img)
}

Duas coisas que aprendi nessa empreitada, foram o pacote flag e o image/color/palette.

Ao invés de construir minha própria paleta de cores como vinha fazendo há algum tempo, agora uso a paleta palette.WebSafe. Outra opção pronta é a palette.Plan9:

https://pkg.go.dev/image/color/palette

O pacote flag permite uma maneira rápida (e não sofisticada) de capturar argumentos em linha de comando, como por exemplo:


go run formula.go -filename formula-colors:50-constant:10-size:10.png -colors 50

Em caso de parâmetro errado:


$ go run formula.go -nada-a-ver
flag provided but not defined: -nada-a-ver
Usage of /tmp/go-build942068976/b001/exe/formula:
  -colors int
        number of colors (default 216)
  -constant int
        constant for formula (c): c-c*x*y (default 10)
  -filename string
        filename to save image (.png) (default "formula.png")
  -size int
        size of image (default 1000)
exit status 2

Algumas imagens

Mudando os parâmetros tem-se resultados interessantemente diferentes (ou não) :)

colors:100 constant:10

colors:100 constant:10

colors:216 constant:10

colors:216 constant:10

colors:80 constant:10

colors:80 constant:10

colors:60 constant:10

colors:60 constant:10

colors:90 constant:10

colors:90 constant:10

colors:200 constant:10

colors:200 constant:10

colors:70 constant:10

colors:70 constant:10