You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
93 lines
2.3 KiB
93 lines
2.3 KiB
3 years ago
|
package main
|
||
|
|
||
|
// imports
|
||
|
import (
|
||
|
"github.com/fogleman/gg"
|
||
|
"image"
|
||
|
"image/color"
|
||
|
"math/rand"
|
||
|
)
|
||
|
|
||
|
// imports
|
||
|
|
||
|
type UserParams struct {
|
||
|
StrokeRatio float64
|
||
|
DestWidth int
|
||
|
DestHeight int
|
||
|
InitialAlpha float64
|
||
|
StrokeReduction float64
|
||
|
AlphaIncrease float64
|
||
|
StrokeInversionThreshold float64
|
||
|
StrokeJitter int
|
||
|
MinEdgeCount int
|
||
|
MaxEdgeCount int
|
||
|
}
|
||
|
|
||
|
type Sketch struct {
|
||
|
UserParams // embed for easier access
|
||
|
source image.Image
|
||
|
dc *gg.Context
|
||
|
sourceWidth int
|
||
|
sourceHeight int
|
||
|
strokeSize float64
|
||
|
initialStrokeSize float64
|
||
|
}
|
||
|
|
||
|
func NewSketch(source image.Image, userParams UserParams) *Sketch {
|
||
|
s := &Sketch{UserParams: userParams}
|
||
|
bounds := source.Bounds()
|
||
|
s.sourceWidth, s.sourceHeight = bounds.Max.X, bounds.Max.Y
|
||
|
s.initialStrokeSize = s.StrokeRatio * float64(s.DestWidth)
|
||
|
s.strokeSize = s.initialStrokeSize
|
||
|
|
||
|
canvas := gg.NewContext(s.DestWidth, s.DestHeight)
|
||
|
canvas.SetColor(color.Black)
|
||
|
canvas.DrawRectangle(0, 0, float64(s.DestWidth), float64(s.DestHeight))
|
||
|
canvas.FillPreserve()
|
||
|
|
||
|
s.source = source
|
||
|
s.dc = canvas
|
||
|
return s
|
||
|
}
|
||
|
|
||
|
func (s *Sketch) Update() {
|
||
|
rndX := rand.Float64() * float64(s.sourceWidth)
|
||
|
rndY := rand.Float64() * float64(s.sourceHeight)
|
||
|
r, g, b := rgb255(s.source.At(int(rndX), int(rndY)))
|
||
|
|
||
|
destX := rndX * float64(s.DestWidth) / float64(s.sourceWidth)
|
||
|
destX += float64(randRange(s.StrokeJitter))
|
||
|
destY := rndY * float64(s.DestHeight) / float64(s.sourceHeight)
|
||
|
destY += float64(randRange(s.StrokeJitter))
|
||
|
edges := s.MinEdgeCount + rand.Intn(s.MaxEdgeCount-s.MinEdgeCount+1)
|
||
|
|
||
|
s.dc.SetRGBA255(r, g, b, int(s.InitialAlpha))
|
||
|
s.dc.DrawRegularPolygon(edges, destX, destY, s.strokeSize, rand.Float64())
|
||
|
s.dc.FillPreserve()
|
||
|
|
||
|
if s.strokeSize <= s.StrokeInversionThreshold*s.initialStrokeSize {
|
||
|
if (r+g+b)/3 < 128 {
|
||
|
s.dc.SetRGBA255(255, 255, 255, int(s.InitialAlpha*2))
|
||
|
} else {
|
||
|
s.dc.SetRGBA255(0, 0, 0, int(s.InitialAlpha*2))
|
||
|
}
|
||
|
}
|
||
|
s.dc.Stroke()
|
||
|
|
||
|
s.strokeSize -= s.StrokeReduction * s.strokeSize
|
||
|
s.InitialAlpha += s.AlphaIncrease
|
||
|
}
|
||
|
|
||
|
func (s *Sketch) Output() image.Image {
|
||
|
return s.dc.Image()
|
||
|
}
|
||
|
|
||
|
func rgb255(c color.Color) (r, g, b int) {
|
||
|
r0, g0, b0, _ := c.RGBA()
|
||
|
return int(r0 / 257), int(g0 / 257), int(b0 / 257)
|
||
|
}
|
||
|
|
||
|
func randRange(max int) int {
|
||
|
return -max + rand.Intn(2*max)
|
||
|
}
|