Compare commits
5 Commits
8d99b9b26d
...
v0.5.1
Author | SHA1 | Date | |
---|---|---|---|
![]() |
3ab6d94944 | ||
fe94e38589 | |||
![]() |
878e3d7c05 | ||
![]() |
eca7e24906 | ||
![]() |
e149469c6c |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1 +1,3 @@
|
|||||||
barnsley-fern
|
barnsley-fern
|
||||||
|
barnsley-fern-go
|
||||||
|
barnsley-fern.png
|
||||||
|
8
Makefile
Normal file
8
Makefile
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
.PHONY: build, clean
|
||||||
|
|
||||||
|
build:
|
||||||
|
go build -v
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f barnsley-fern-go barnsley-fern.png
|
||||||
|
|
@@ -1,12 +1,12 @@
|
|||||||
# barnsley-fern-go
|
# barnsley-fern-go
|
||||||
Implementation of Barnsley Fern in Go
|
Implementation of Barnsley Fern in Go
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
From the root of the repository
|
From the root of the repository
|
||||||
```bash
|
```bash
|
||||||
go build barnsley-fern.go
|
go build
|
||||||
./barnsley-fern
|
./barnsley-fern-go
|
||||||
```
|
```
|
||||||
or simply
|
or simply
|
||||||
```
|
```
|
||||||
@@ -15,3 +15,5 @@ go run barnsley-fern.go
|
|||||||
This will generate an image in current directory.
|
This will generate an image in current directory.
|
||||||
|
|
||||||
See **./barnsley-fern --help** for available flags.
|
See **./barnsley-fern --help** for available flags.
|
||||||
|
|
||||||
|
Image on this page was generated with **./barnsley-fern-go -x 500 -y 500 -c 3 -out example/barnsley-fern.png**
|
||||||
|
@@ -1,40 +1,12 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
|
||||||
"image/png"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func createImage(h, v int) *image.RGBA {
|
func drawBarnsleyFern(img *image.RGBA, colorfunc colorFunc, dots int) {
|
||||||
rect := image.Rectangle{
|
|
||||||
image.Point{0, 0},
|
|
||||||
image.Point{h, v},
|
|
||||||
}
|
|
||||||
return image.NewRGBA(rect)
|
|
||||||
}
|
|
||||||
|
|
||||||
func fillBackground(img *image.RGBA, c color.Color) {
|
|
||||||
rect := img.Bounds()
|
|
||||||
for x := 0; x < rect.Max.X; x++ {
|
|
||||||
for y := 0; y < rect.Max.Y; y++ {
|
|
||||||
img.Set(x, y, c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func min(a, b float64) float64 {
|
|
||||||
if a > b {
|
|
||||||
a = b
|
|
||||||
}
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
func drawBarnsleyFern(img *image.RGBA, c color.Color, dots int) {
|
|
||||||
var (
|
var (
|
||||||
x, y, tmpx, tmpy, r, maxy, maxx, scale, yoffset, xoffset float64
|
x, y, tmpx, tmpy, r, maxy, maxx, scale, yoffset, xoffset float64
|
||||||
)
|
)
|
||||||
@@ -43,7 +15,7 @@ func drawBarnsleyFern(img *image.RGBA, c color.Color, dots int) {
|
|||||||
scale = min(maxx, maxy)
|
scale = min(maxx, maxy)
|
||||||
yoffset = scale / 10 // отступы 10% сверху и снизу
|
yoffset = scale / 10 // отступы 10% сверху и снизу
|
||||||
scale = scale - yoffset*2 // масштаб самого папоротника
|
scale = scale - yoffset*2 // масштаб самого папоротника
|
||||||
xoffset = (maxx - scale) / 2 // равные отступы с двух сторон
|
xoffset = (maxx - scale) / 2 // равные отступы по сторонам
|
||||||
|
|
||||||
x, y = 0.5, 0.0
|
x, y = 0.5, 0.0
|
||||||
for dots > 0 {
|
for dots > 0 {
|
||||||
@@ -68,39 +40,16 @@ func drawBarnsleyFern(img *image.RGBA, c color.Color, dots int) {
|
|||||||
}
|
}
|
||||||
// рисуем точку
|
// рисуем точку
|
||||||
x, y = tmpx, tmpy
|
x, y = tmpx, tmpy
|
||||||
img.Set(int(xoffset+x*scale), int(maxy-yoffset-y*scale), c)
|
|
||||||
|
color := colorfunc(x, y, time.Now())
|
||||||
|
|
||||||
|
img.Set(int(xoffset+x*scale), int(maxy-yoffset-y*scale), color)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func min(a, b float64) float64 {
|
||||||
var (
|
if a > b {
|
||||||
filename string = "barnsley_fern.png"
|
a = b
|
||||||
h = flag.Int("h", 1920, "размер картинки по горизонтали")
|
|
||||||
v = flag.Int("v", 1080, "размер картинки по вертикали")
|
|
||||||
dots = flag.Int("d", 100000, "сколько точек рисовать")
|
|
||||||
img *image.RGBA
|
|
||||||
f *os.File
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
img = createImage(*h, *v)
|
|
||||||
|
|
||||||
fillBackground(img, color.White)
|
|
||||||
drawBarnsleyFern(img, color.RGBA{0, 153, 0, 255}, *dots)
|
|
||||||
|
|
||||||
f, err = os.Create(filename)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("не удалось создать файл %s: %v", filename, err)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
return a
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
if err = png.Encode(f, img); err != nil {
|
|
||||||
fmt.Printf("не удалось сохранить изображение: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("done...")
|
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 61 KiB |
47
color.go
Normal file
47
color.go
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"image/color"
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type colorFunc func(float64, float64, time.Time) color.Color
|
||||||
|
|
||||||
|
func newColorFunc(c colormode) colorFunc {
|
||||||
|
start := time.Now()
|
||||||
|
return func(x, y float64, t time.Time) color.Color {
|
||||||
|
var (
|
||||||
|
r, g, b, a uint8
|
||||||
|
)
|
||||||
|
|
||||||
|
switch c {
|
||||||
|
case crandom:
|
||||||
|
r = uint8(rand.Intn(256))
|
||||||
|
g = uint8(rand.Intn(256))
|
||||||
|
b = uint8(rand.Intn(256))
|
||||||
|
a = 255
|
||||||
|
|
||||||
|
case ctimed:
|
||||||
|
n := time.Since(start).Nanoseconds()
|
||||||
|
|
||||||
|
r = uint8(n % 256)
|
||||||
|
g = uint8((n + 128) % 256)
|
||||||
|
//b = uint8((n + 1) % 256)
|
||||||
|
|
||||||
|
a = 255
|
||||||
|
|
||||||
|
case crainbow:
|
||||||
|
r = uint8(y * 256)
|
||||||
|
g = uint8(x * 256)
|
||||||
|
b = uint8(((y - x) - min(x, y)) * 256)
|
||||||
|
|
||||||
|
a = 255
|
||||||
|
|
||||||
|
default:
|
||||||
|
r, g, b, a = 0, 153, 0, 255
|
||||||
|
}
|
||||||
|
|
||||||
|
return color.RGBA{r, g, b, a}
|
||||||
|
}
|
||||||
|
}
|
BIN
example/barnsley-fern.png
Normal file
BIN
example/barnsley-fern.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 57 KiB |
2
go.mod
2
go.mod
@@ -1,3 +1,5 @@
|
|||||||
module code.uint32.ru/dmitry/barnsley-fern-go
|
module code.uint32.ru/dmitry/barnsley-fern-go
|
||||||
|
|
||||||
go 1.24.1
|
go 1.24.1
|
||||||
|
|
||||||
|
require github.com/AlexEidt/Vidio v1.5.1 // indirect
|
||||||
|
2
go.sum
Normal file
2
go.sum
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
github.com/AlexEidt/Vidio v1.5.1 h1:tovwvtgQagUz1vifiL9OeWkg1fP/XUzFazFKh7tFtaE=
|
||||||
|
github.com/AlexEidt/Vidio v1.5.1/go.mod h1:djhIMnWMqPrC3X6nB6ymGX6uWWlgw+VayYGKE1bNwmI=
|
68
image.go
Normal file
68
image.go
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"image"
|
||||||
|
"image/color"
|
||||||
|
"image/jpeg"
|
||||||
|
"image/png"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errEncodeImage = errors.New("не удалось создать изображение")
|
||||||
|
errUnknownFormat = errors.New("неизвестный формат изображения")
|
||||||
|
)
|
||||||
|
|
||||||
|
func createBarnsleyFernImage(s *settings, w io.Writer) error {
|
||||||
|
img := newImageWithBackGround(s.X, s.Y, s.BG)
|
||||||
|
|
||||||
|
drawBarnsleyFern(img, newColorFunc(s.CM), s.Dots)
|
||||||
|
|
||||||
|
switch s.OM {
|
||||||
|
case outputjpeg:
|
||||||
|
opts := &jpeg.Options{
|
||||||
|
Quality: 100,
|
||||||
|
}
|
||||||
|
if err := jpeg.Encode(w, img, opts); err != nil {
|
||||||
|
return errors.Join(errEncodeImage, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case outputpng:
|
||||||
|
if err := png.Encode(w, img); err != nil {
|
||||||
|
return errors.Join(errEncodeImage, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("%w: %d", errUnknownFormat, s.OM)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newImageWithBackGround(x, y int, background color.Color) *image.RGBA {
|
||||||
|
img := createImage(x, y)
|
||||||
|
|
||||||
|
fillBackground(img, background)
|
||||||
|
|
||||||
|
return img
|
||||||
|
}
|
||||||
|
|
||||||
|
func createImage(x, y int) *image.RGBA {
|
||||||
|
rect := image.Rectangle{
|
||||||
|
image.Point{0, 0},
|
||||||
|
image.Point{x, y},
|
||||||
|
}
|
||||||
|
|
||||||
|
return image.NewRGBA(rect)
|
||||||
|
}
|
||||||
|
|
||||||
|
func fillBackground(img *image.RGBA, c color.Color) {
|
||||||
|
rect := img.Bounds()
|
||||||
|
for x := range rect.Max.X {
|
||||||
|
for y := range rect.Max.Y {
|
||||||
|
img.Set(x, y, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
35
main.go
Normal file
35
main.go
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
exitCode := run()
|
||||||
|
os.Exit(exitCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func run() int {
|
||||||
|
s := parseSettings()
|
||||||
|
|
||||||
|
file, err := os.Create(s.Fname)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("ошибка открытия файла", err)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := createBarnsleyFernImage(s, file); err != nil {
|
||||||
|
fmt.Println("ошибка создания изображения:", err)
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := file.Close(); err != nil {
|
||||||
|
fmt.Println("ошибка закрытия файла:", err)
|
||||||
|
return 3
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("done")
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
63
settings.go
Normal file
63
settings.go
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"image/color"
|
||||||
|
)
|
||||||
|
|
||||||
|
type colormode int
|
||||||
|
|
||||||
|
const (
|
||||||
|
cdefault colormode = iota
|
||||||
|
crandom
|
||||||
|
ctimed
|
||||||
|
crainbow
|
||||||
|
)
|
||||||
|
|
||||||
|
type outputmode int
|
||||||
|
|
||||||
|
const (
|
||||||
|
outputpng outputmode = iota
|
||||||
|
outputjpeg
|
||||||
|
)
|
||||||
|
|
||||||
|
type settings struct {
|
||||||
|
X, Y int // image size
|
||||||
|
Dots int // dots to draw for single image
|
||||||
|
BG color.Color // background color
|
||||||
|
CM colormode // settings for colorFunc
|
||||||
|
OM outputmode // what to output
|
||||||
|
Fname string // filename for output
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseSettings() *settings {
|
||||||
|
var (
|
||||||
|
x, y int
|
||||||
|
dots int
|
||||||
|
cmode int
|
||||||
|
output int
|
||||||
|
fname string
|
||||||
|
)
|
||||||
|
|
||||||
|
flag.IntVar(&x, "x", 1920, "размер картинки по горизонтали")
|
||||||
|
flag.IntVar(&y, "y", 1080, "размер картинки по вертикали")
|
||||||
|
flag.IntVar(&dots, "d", 100000, "сколько точек рисовать")
|
||||||
|
flag.IntVar(&cmode, "c", 0, "color mode: 0 - default green, 1 - random, 2 - timed, 3 - rainbow")
|
||||||
|
flag.IntVar(&output, "o", 0, fmt.Sprintf("режим вывода: %d - png, %d - jpeg", outputpng, outputjpeg))
|
||||||
|
flag.StringVar(&fname, "out", "barnsley-fern.png", "полный путь файла для записи изображения")
|
||||||
|
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
s := &settings{
|
||||||
|
X: x,
|
||||||
|
Y: y,
|
||||||
|
Dots: dots,
|
||||||
|
BG: color.White,
|
||||||
|
CM: colormode(cmode),
|
||||||
|
OM: outputmode(output),
|
||||||
|
Fname: fname,
|
||||||
|
}
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
Reference in New Issue
Block a user