Skip to content

Instantly share code, notes, and snippets.

@setanarut
Created May 3, 2025 01:47
Show Gist options
  • Save setanarut/e325c04f9437262b0bb4acaed9c698a1 to your computer and use it in GitHub Desktop.
Save setanarut/e325c04f9437262b0bb4acaed9c698a1 to your computer and use it in GitHub Desktop.
FM effect
package main
import (
"image"
"image/color"
"math"
"github.com/anthonynsimon/bild/blend"
"github.com/anthonynsimon/bild/fcolor"
"github.com/anthonynsimon/bild/imgio"
"github.com/anthonynsimon/bild/transform"
"github.com/setanarut/apng"
)
func processImageFrames(img image.Image, freqMultiplier float64, frameCount int) []image.Image {
bounds := img.Bounds()
width, height := bounds.Max.X, bounds.Max.Y
frames := make([]image.Image, frameCount)
minOmega := 2 * math.Pi / (0.05 * float64(width))
baseOmega := minOmega * freqMultiplier
for frame := range frames {
destImg := image.NewRGBA(bounds)
frames[frame] = destImg
// Time progression - normalized value for the loop (between 0-1)
timeOffset := float64(frame) / float64(frameCount) * 2 * math.Pi * 1
for y := range height {
rf := 0.0
gf := 0.0
bf := 0.0
for x := range width {
r, g, b, _ := img.At(x, y).RGBA()
rf += float64(r)/65535.0 - 1
gf += float64(g)/65535.0 - 1
bf += float64(b)/65535.0 - 1
// Add time progression
rm := math.Cos(baseOmega*float64(x) + rf + timeOffset)
gm := math.Cos(baseOmega*float64(x) + gf + timeOffset)
bm := math.Cos(baseOmega*float64(x) + bf + timeOffset)
// Remap signal back to channel value
rv := uint8(min(max((rm+1)*127.5, 0), 255))
gv := uint8(min(max((gm+1)*127.5, 0), 255))
bv := uint8(min(max((bm+1)*127.5, 0), 255))
destImg.SetRGBA(x, y, color.RGBA{rv, gv, bv, 255})
}
}
}
for i := range frames {
frames[i] = blend.Blend(frames[i], img, HardMix)
frames[i] = transform.Resize(frames[i], width/2, height/2, transform.CatmullRom)
}
return frames
}
func main() {
img, _ := imgio.Open("input.jpg")
frames := processImageFrames(img, 5, 8)
apng.Save("out.png", frames, 7)
}
func HardMix(c1, c2 fcolor.RGBAF64) (result fcolor.RGBAF64) {
f := func(i, j float64) float64 {
if j < 1-i {
return 0
}
return 1
}
result.R = f(c1.R, c2.R)
result.G = f(c1.G, c2.G)
result.B = f(c1.B, c2.B)
result.A = 1
return result
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment