Skip to content

Commit

Permalink
Release 1.23.5
Browse files Browse the repository at this point in the history
- update docs
- faster RNG for noise, fried
- faster HSLA/RGBA conversion
  • Loading branch information
sgreben committed Dec 6, 2018
1 parent dcb6e6b commit 3d05ef8
Show file tree
Hide file tree
Showing 15 changed files with 125 additions and 31 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
APP=gif
NAME := yeetgif
REPOSITORY := quay.io/sergey_grebenshchikov/$(NAME)
VERSION := 1.23.4
VERSION := 1.23.5
VERSION_COMMIT := $(VERSION)-$(shell printf "%s" "$$(git rev-parse HEAD)" | cut -c 1-8)

PACKAGES := $(shell go list -f {{.Dir}} ./...)
Expand Down Expand Up @@ -48,7 +48,7 @@ doc/roll.gif:
<doc/eggplant.png gif roll > doc/roll.gif

doc/wobble.gif:
<doc/eggplant.png gif -n 30 wobble -a 10 -f 2 > doc/wobble.gif
gif -r emoji -s 128 eggplant | gif -n 30 wobble -a 10 -f 2 > doc/wobble.gif

doc/rain.gif:
gif -r emoji -s 64 aubergine | gif -r rain | gif optimize -n --kb=999 > doc/rain.gif
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,14 @@ Either from [the releases page](https://github.com/sgreben/yeetgif/releases/late

```sh
# Linux
curl -L https://github.com/sgreben/yeetgif/releases/download/1.23.4/gif_1.23.4_linux_x86_64.tar.gz | tar xz
curl -L https://github.com/sgreben/yeetgif/releases/download/1.23.5/gif_1.23.5_linux_x86_64.tar.gz | tar xz

# OS X
curl -L https://github.com/sgreben/yeetgif/releases/download/1.23.4/gif_1.23.4_osx_x86_64.tar.gz | tar xz
curl -L https://github.com/sgreben/yeetgif/releases/download/1.23.5/gif_1.23.5_osx_x86_64.tar.gz | tar xz

# Windows
curl -LO https://github.com/sgreben/yeetgif/releases/download/1.23.4/gif_1.23.4_windows_x86_64.zip
unzip gif_1.23.4_windows_x86_64.zip
curl -LO https://github.com/sgreben/yeetgif/releases/download/1.23.5/gif_1.23.5_windows_x86_64.zip
unzip gif_1.23.5_windows_x86_64.zip
```

**NOTE**: To use the `optimize` command, you'll also need the [`giflossy`](https://github.com/kornelski/giflossy) fork of `gifsicle` installed:
Expand Down Expand Up @@ -338,7 +338,7 @@ Options:
-x (default [1])
-y (default [1])
-m, --mode one of [mul add sub pow sin] (default add)
-c, --center (default 0.2183000524405257)
-c, --center (default 0.7680623638504513)
```

### resize
Expand Down
2 changes: 1 addition & 1 deletion cmd/gif/erase.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func Erase(images []image.Image, x, y int, t, wh, ws, wl float64) {
sample := images[i].At(x, y)
r, g, b, _ := sample.RGBA()
sh, ss, sl, _ := imaging.HSLA(color.RGBA{uint8(r), uint8(g), uint8(b), 0})
images[i] = imaging.AdjustHSLAFunc(images[i], func(_, _ int, h, s, l, a *float64) {
images[i] = imaging.AdjustHSLAFunc(images[i], func(_, _ int, h, s, l, a *float64, _ *int) {
dist := math.Sqrt((wh*sqr(*h-sh) + ws*sqr(*s-ss) + wl*sqr(*l-sl)) / (wh + ws + wl))
if dist < t/2 {
*a = 0
Expand Down
2 changes: 2 additions & 0 deletions cmd/gif/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ var (
)

func main() {
startProfile()
defer stopProfile()
app.VarOpt("d delay-ms", &delay, "Frame delay in milliseconds")
app.Before = func() {
config.Raw = *raw
Expand Down
11 changes: 6 additions & 5 deletions cmd/gif/noise.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ package main

import (
"image"
"math/rand"

"github.com/sgreben/yeetgif/pkg/gifmath"

cli "github.com/jawher/mow.cli"
"github.com/sgreben/yeetgif/pkg/gifcmd"
Expand Down Expand Up @@ -32,10 +33,10 @@ func Noise(images []image.Image, noiseF, noise1F, noise2F, noise3F func(float64)
noise := func(i int) {
t := float64(i) / n
noise, noise1, noise2, noise3 := noiseF(t), noise1F(t), noise2F(t), noise3F(t)
images[i] = imaging.AdjustHSLAFunc(images[i], func(x, y int, h, s, l, a *float64) {
*h = *h + noise*noise1*rand.Float64()
*s = *s + noise*noise2*rand.Float64()
*l = *l + noise*noise3*rand.Float64()
images[i] = imaging.AdjustHSLAFunc(images[i], func(x, y int, h, s, l, a *float64, seed *int) {
*h = *h + noise*noise1*float64(gifmath.RandomFloat32Signed(seed))
*s = *s + noise*noise2*float64(gifmath.RandomFloat32Signed(seed))
*l = *l + noise*noise3*float64(gifmath.RandomFloat32Signed(seed))
})
}
parallel(len(images), noise, "noise")
Expand Down
6 changes: 6 additions & 0 deletions cmd/gif/profile_disabled.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// +build !profile

package main

func startProfile() {}
func stopProfile() {}
34 changes: 34 additions & 0 deletions cmd/gif/profile_enabled.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// +build profile

package main

import (
"log"
"os"
"runtime/pprof"
)

var (
cpuProfile *os.File
memProfile *os.File
)

func startProfile() {
var err error
cpuProfile, err := os.Create("yeetgif-cpu.profile")
if err != nil {
log.Fatal(err)
}
pprof.StartCPUProfile(cpuProfile)
memProfile, err := os.Create("yeetgif-mem.profile")
if err != nil {
log.Fatal(err)
}
pprof.WriteHeapProfile(memProfile)
}

func stopProfile() {
pprof.StopCPUProfile()
cpuProfile.Close()
memProfile.Close()
}
2 changes: 1 addition & 1 deletion cmd/gif/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func Scan(images []image.Image, f func(x, y, t float64, h, s, l, a *float64)) {
b := images[i].Bounds()
bw := float64(b.Dx())
bh := float64(b.Dy())
images[i] = imaging.AdjustHSLAFunc(images[i], func(x, y int, h, s, l, a *float64) {
images[i] = imaging.AdjustHSLAFunc(images[i], func(x, y int, h, s, l, a *float64, _ *int) {
xf := float64(x-b.Min.X) / bw
yf := float64(y-b.Min.Y) / bh
f(xf, yf, t, h, s, l, a)
Expand Down
5 changes: 2 additions & 3 deletions cmd/gif/woke.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,13 @@ func CommandWoke(cmd *cli.Cmd) {
alphaT := at.Value
alphaP := ap.Value
alphaV := alpha.Value
flare = imaging.AdjustHSLAFunc(flare, func(_, _ int, h, s, l, a *float64) {
flare = imaging.AdjustHSLAFunc(flare, func(_, _ int, h, s, l, a *float64, _ *int) {
*a = math.Pow(*a, alphaP) * alphaV
if *a < alphaT {
*a = 0
return
} else {
*a = (*a - alphaT) / (1.0 - alphaT)
}
*a = (*a - alphaT) / (1.0 - alphaT)
*l = (*l) * lightness.Value
if changeHue {
*h += hue.Value
Expand Down
Binary file modified doc/terminal.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/terminal.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/wobble.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 14 additions & 1 deletion pkg/gifmath/math.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
package gifmath

import "math/big"
import (
"math"
"math/big"
)

func LCM(a, b int) int {
var an, bn, z big.Int
an.SetInt64(int64(a))
bn.SetInt64(int64(b))
return int(z.Mul(z.Div(&bn, z.GCD(nil, nil, &an, &bn)), &an).Int64())
}

func RandomFloat32Signed(seed *int) float32 {
*seed *= 16807
return math.Float32frombits((uint32(*seed)>>9)|0x40000000) - 3.0
}

func RandomFloat32Unsigned(seed *int) float32 {
*seed *= 16807
return math.Float32frombits((uint32(*seed)>>9)|0x3f800000) - 1.0
}
17 changes: 12 additions & 5 deletions pkg/imaging/adjust.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,19 +117,25 @@ func AdjustGamma(img image.Image, gamma float64) *image.NRGBA {
return adjustLUT(img, lut)
}

func randomFloat32Signed(seed *int) float32 {
*seed *= 16807
return math.Float32frombits((uint32(*seed)>>9)|0x40000000) - 3.0
}

func AdjustNoiseHSL(img image.Image, hn, sn, ln float64) *image.NRGBA {
src := newScanner(img)
dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h))
parallel(0, src.h, func(ys <-chan int) {
seed := rand.Int()
for y := range ys {
i := y * dst.Stride
src.scan(0, y, src.w, y+1, dst.Pix[i:i+src.w*4])
for x := 0; x < src.w; x++ {
r, g, b := dst.Pix[i+0], dst.Pix[i+1], dst.Pix[i+2]
h, s, l, _ := HSLA(color.RGBA{R: r, G: g, B: b})
h += hn * (2*rand.Float64() - 1)
s += sn * (2*rand.Float64() - 1)
l += ln * (2*rand.Float64() - 1)
h += hn * float64(randomFloat32Signed(&seed))
s += sn * float64(randomFloat32Signed(&seed))
l += ln * float64(randomFloat32Signed(&seed))
c := RGBA(h, s, l, 0)
dst.Pix[i+0] = c.R
dst.Pix[i+1] = c.G
Expand Down Expand Up @@ -243,17 +249,18 @@ func AdjustHSL(img image.Image, weight float64, h, s, l float64) *image.NRGBA {
return dst
}

func AdjustHSLAFunc(img image.Image, f func(x, y int, h, s, l, a *float64)) *image.NRGBA {
func AdjustHSLAFunc(img image.Image, f func(x, y int, h, s, l, a *float64, seed *int)) *image.NRGBA {
src := newScanner(img)
dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h))
parallel(0, src.h, func(ys <-chan int) {
seed := rand.Int()
for y := range ys {
i := y * dst.Stride
src.scan(0, y, src.w, y+1, dst.Pix[i:i+src.w*4])
for x := 0; x < src.w; x++ {
r, g, b, a0 := dst.Pix[i+0], dst.Pix[i+1], dst.Pix[i+2], dst.Pix[i+3]
h, s, l, a := HSLA(color.RGBA{R: r, G: g, B: b, A: a0})
f(x, y, &h, &s, &l, &a)
f(x, y, &h, &s, &l, &a, &seed)
c := RGBA(h, s, l, a)
dst.Pix[i+0] = c.R
dst.Pix[i+1] = c.G
Expand Down
48 changes: 40 additions & 8 deletions pkg/imaging/hsl.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,36 @@ import (
"math"
)

var byteToFloat [256]float64

func init() {
for i := 0; i <= 0xFF; i++ {
byteToFloat[i] = float64(i) / 0xFF
}
}

func HSLA(c color.RGBA) (h, s, l, a float64) {
r := float64(c.R) / 255.0
g := float64(c.G) / 255.0
b := float64(c.B) / 255.0
a = float64(c.A) / 255.0
r := byteToFloat[c.R]
g := byteToFloat[c.G]
b := byteToFloat[c.B]
a = byteToFloat[c.A]

max := math.Max(math.Max(r, g), b)
min := math.Min(math.Min(r, g), b)
maxByte := c.R
if c.G > maxByte {
maxByte = c.G
}
if c.B > maxByte {
maxByte = c.B
}
max := byteToFloat[maxByte]
minByte := c.R
if c.G < minByte {
minByte = c.G
}
if c.B < minByte {
minByte = c.B
}
min := byteToFloat[minByte]
l = (max + min) / 2
delta := max - min
if delta != 0 {
Expand Down Expand Up @@ -50,8 +72,18 @@ func RGBA(h, s, l, a float64) (c color.RGBA) {
case h > 1:
h = h - math.Floor(h)
}
s = math.Max(0, math.Min(s, 1))
l = math.Max(0, math.Min(l, 1))
switch {
case s < 0:
s = 0
case s > 1:
s = 1
}
switch {
case l < 0:
l = 0
case l > 1:
l = 1
}
c.A = uint8(255 * a)
if s == 0 {
c.R = uint8(255 * l)
Expand Down

0 comments on commit 3d05ef8

Please sign in to comment.