/
crowd.go
109 lines (105 loc) · 2.97 KB
/
crowd.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package main
import (
"image"
"image/color"
"math/rand"
cli "github.com/jawher/mow.cli"
"github.com/sgreben/yeetgif/pkg/gifcmd"
"github.com/sgreben/yeetgif/pkg/imaging"
)
func CommandCrowd(cmd *cli.Cmd) {
cmd.Before = InputAndDuplicate
var (
n = cmd.IntOpt("n", 3, "crowd size")
rpx = gifcmd.Float{Value: 0.5}
rpy = gifcmd.Float{Value: 0.25}
rs = gifcmd.Float{Value: 0.25}
rr = gifcmd.Float{Value: 0.1}
ra = gifcmd.Float{Value: 0.0}
ro = gifcmd.Float{Value: 1.0}
rf = cmd.BoolOpt("flip", true, "🌀 flip")
)
cmd.VarOpt("x", &rpx, "🌀 x")
cmd.VarOpt("y", &rpy, "🌀 y")
cmd.VarOpt("s scale", &rs, "🌀 [0.0,1.0]")
cmd.VarOpt("r rotate", &rr, "🌀 [0.0,1.0]")
cmd.VarOpt("a alpha", &ra, "🌀 [0.0,1.0]")
cmd.VarOpt("o offset", &ro, "🌀 [0.0,1.0]")
cmd.Action = func() {
Crowd(images, *n, *rf, rpx.Value, rpy.Value, rs.Value, ra.Value, rr.Value, ro.Value)
AutoCrop(images, 0.0)
}
}
func Crowd(images []image.Image, k int, rf bool, rpx, rpy, rs, ra, rr, ro float64) {
p := make([]image.Point, k)
r := make([]float64, k)
s := make([]float64, k)
a := make([]float64, k)
o := make([]int, k)
f := make([]bool, k)
for j := range s {
s[j] = 1.0 - (rand.Float64() * rs)
r[j] = 360 * rr * 2 * (rand.Float64() - 0.5)
o[j] = rand.Intn(int(ro * float64(len(images)-1)))
a[j] = 1.0 - (rand.Float64() * ra)
f[j] = rf && (rand.Float32() < 0.5)
}
width, height := 0.0, 0.0
for i := range images {
for j := range r {
tmp := images[i]
if f[j] {
tmp = imaging.FlipH(tmp)
}
tmp = imaging.Rotate(tmp, r[j], color.Transparent)
b := tmp.Bounds()
if w := float64(b.Dx()) * s[j]; w > width {
width = w
}
if h := float64(b.Dy()) * s[j]; h > height {
height = h
}
}
}
mid := image.Point{
X: int(width / 2),
Y: int(height / 2),
}
var b, bOriginal image.Rectangle
bOriginal.Max.X = int(width)
bOriginal.Max.Y = int(height)
b.Max.X = bOriginal.Max.X
b.Max.Y = bOriginal.Max.Y
for j := range p {
p[j].X = int(s[j] * float64(width) * rpx * 2 * (rand.Float64() - 0.5))
p[j].Y = int(s[j] * float64(height) * rpy * 2 * (rand.Float64() - 0.5))
b = b.Union(bOriginal.Add(p[j]))
}
offset := b.Min
b = b.Sub(offset)
originals := images
images = make([]image.Image, len(originals))
crowd := func(i int) {
crowded := imaging.New(b.Dx(), b.Dy(), color.Transparent)
for j := range p {
iLayer := (o[j] + i) % len(images)
layer := originals[iLayer]
bLayer := layer.Bounds()
w, h := float64(bLayer.Dx())*s[j], float64(bLayer.Dy())*s[j]
if f[j] {
layer = imaging.FlipH(layer)
}
layer = imaging.Resize(layer, int(w), int(h), imaging.Lanczos)
layer = imaging.Rotate(layer, r[j], color.Transparent)
midLayer := imaging.AnchorPoint(layer, imaging.Center)
p := p[j].Sub(midLayer).Add(mid).Sub(offset)
crowded = imaging.Overlay(crowded, layer, p, a[j])
}
images[i] = crowded
}
overwrite := func(i int) {
originals[i] = images[i]
}
parallel(len(images), crowd, "crowd")
parallel(len(images), overwrite)
}