mirror of
https://github.com/coalaura/ffwebp.git
synced 2025-09-08 05:49:54 +00:00
effects
This commit is contained in:
16
internal/builtins/effects.go
Normal file
16
internal/builtins/effects.go
Normal file
@@ -0,0 +1,16 @@
|
||||
//go:build effects || core || full
|
||||
// +build effects core full
|
||||
|
||||
package builtins
|
||||
|
||||
import (
|
||||
_ "github.com/coalaura/ffwebp/internal/effects/blur"
|
||||
_ "github.com/coalaura/ffwebp/internal/effects/brightness"
|
||||
_ "github.com/coalaura/ffwebp/internal/effects/contrast"
|
||||
_ "github.com/coalaura/ffwebp/internal/effects/grayscale"
|
||||
_ "github.com/coalaura/ffwebp/internal/effects/hue"
|
||||
_ "github.com/coalaura/ffwebp/internal/effects/invert"
|
||||
_ "github.com/coalaura/ffwebp/internal/effects/saturation"
|
||||
_ "github.com/coalaura/ffwebp/internal/effects/sepia"
|
||||
_ "github.com/coalaura/ffwebp/internal/effects/sharpen"
|
||||
)
|
@@ -42,7 +42,7 @@ func (impl) Flags(flags []cli.Flag) []cli.Flag {
|
||||
return append(flags,
|
||||
&cli.IntFlag{
|
||||
Name: "avif.quality-alpha",
|
||||
Usage: "AVIF: alpha channel quality in range [0-100]",
|
||||
Usage: "AVIF: alpha channel quality (0-100)",
|
||||
Value: 60,
|
||||
Destination: &qualityA,
|
||||
Validator: func(v int) error {
|
||||
@@ -55,7 +55,7 @@ func (impl) Flags(flags []cli.Flag) []cli.Flag {
|
||||
},
|
||||
&cli.IntFlag{
|
||||
Name: "avif.speed",
|
||||
Usage: "AVIF: encoding speed in range [0-10] (0=slowest/best)",
|
||||
Usage: "AVIF: encoding speed (0=slowest/best, 10=fastest/worst)",
|
||||
Value: 6,
|
||||
Destination: &speed,
|
||||
Validator: func(v int) error {
|
||||
|
@@ -41,7 +41,7 @@ func (impl) Flags(flags []cli.Flag) []cli.Flag {
|
||||
Destination: &numColors,
|
||||
Validator: func(value int) error {
|
||||
if value < 1 || value > 256 {
|
||||
return fmt.Errorf("invalid number of colors: %d", value)
|
||||
return fmt.Errorf("invalid gif.colors: %d", value)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@@ -43,7 +43,7 @@ func (impl) Flags(flags []cli.Flag) []cli.Flag {
|
||||
Destination: &compression,
|
||||
Validator: func(value int) error {
|
||||
if value < 0 || value > 3 {
|
||||
return fmt.Errorf("invalid compression level: %d", value)
|
||||
return fmt.Errorf("invalid png.compression: %d", value)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@@ -46,7 +46,7 @@ func (impl) Flags(flags []cli.Flag) []cli.Flag {
|
||||
Destination: &compression,
|
||||
Validator: func(value int) error {
|
||||
if value < 0 || value > 4 {
|
||||
return fmt.Errorf("invalid compression: %d", value)
|
||||
return fmt.Errorf("invalid tiff.compression: %d", value)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
38
internal/effects/blur/blur.go
Normal file
38
internal/effects/blur/blur.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package blur
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"strconv"
|
||||
|
||||
"github.com/anthonynsimon/bild/blur"
|
||||
"github.com/coalaura/ffwebp/internal/effects"
|
||||
"github.com/coalaura/ffwebp/internal/logx"
|
||||
)
|
||||
|
||||
type impl struct{}
|
||||
|
||||
func init() {
|
||||
effects.Register(impl{})
|
||||
}
|
||||
|
||||
func (impl) String() string {
|
||||
return "blur"
|
||||
}
|
||||
|
||||
func (impl) Apply(img image.Image, args string) (image.Image, error) {
|
||||
var radius float64 = 3
|
||||
|
||||
if args != "" {
|
||||
f64, err := strconv.ParseFloat(args, 64)
|
||||
if err != nil || f64 <= 0 {
|
||||
return nil, fmt.Errorf("invalid blur radius: %s", args)
|
||||
}
|
||||
|
||||
radius = f64
|
||||
}
|
||||
|
||||
logx.Printf(" applying blur (radius=%.f)\n", radius)
|
||||
|
||||
return blur.Gaussian(img, radius), nil
|
||||
}
|
38
internal/effects/brightness/brightness.go
Normal file
38
internal/effects/brightness/brightness.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package brightness
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"strconv"
|
||||
|
||||
"github.com/anthonynsimon/bild/adjust"
|
||||
"github.com/coalaura/ffwebp/internal/effects"
|
||||
"github.com/coalaura/ffwebp/internal/logx"
|
||||
)
|
||||
|
||||
type impl struct{}
|
||||
|
||||
func init() {
|
||||
effects.Register(impl{})
|
||||
}
|
||||
|
||||
func (impl) String() string {
|
||||
return "brightness"
|
||||
}
|
||||
|
||||
func (impl) Apply(img image.Image, args string) (image.Image, error) {
|
||||
var change float64 = 0.1
|
||||
|
||||
if args != "" {
|
||||
f64, err := strconv.ParseFloat(args, 64)
|
||||
if err != nil || f64 < -1 || f64 > 1 || f64 == 0 {
|
||||
return nil, fmt.Errorf("invalid brightness change: %s", args)
|
||||
}
|
||||
|
||||
change = f64
|
||||
}
|
||||
|
||||
logx.Printf(" applying brightness (change=%.f)\n", change)
|
||||
|
||||
return adjust.Brightness(img, change), nil
|
||||
}
|
38
internal/effects/contrast/contrast.go
Normal file
38
internal/effects/contrast/contrast.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package contrast
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"strconv"
|
||||
|
||||
"github.com/anthonynsimon/bild/adjust"
|
||||
"github.com/coalaura/ffwebp/internal/effects"
|
||||
"github.com/coalaura/ffwebp/internal/logx"
|
||||
)
|
||||
|
||||
type impl struct{}
|
||||
|
||||
func init() {
|
||||
effects.Register(impl{})
|
||||
}
|
||||
|
||||
func (impl) String() string {
|
||||
return "contrast"
|
||||
}
|
||||
|
||||
func (impl) Apply(img image.Image, args string) (image.Image, error) {
|
||||
var change float64 = 0.1
|
||||
|
||||
if args != "" {
|
||||
f64, err := strconv.ParseFloat(args, 64)
|
||||
if err != nil || f64 < -1 || f64 > 1 || f64 == 0 {
|
||||
return nil, fmt.Errorf("invalid contrast change: %s", args)
|
||||
}
|
||||
|
||||
change = f64
|
||||
}
|
||||
|
||||
logx.Printf(" applying contrast (change=%.f)\n", change)
|
||||
|
||||
return adjust.Contrast(img, change), nil
|
||||
}
|
103
internal/effects/effects.go
Normal file
103
internal/effects/effects.go
Normal file
@@ -0,0 +1,103 @@
|
||||
package effects
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"strings"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
type Effect interface {
|
||||
String() string
|
||||
Apply(image.Image, string) (image.Image, error)
|
||||
}
|
||||
|
||||
type EffectConfig struct {
|
||||
Effect Effect
|
||||
Arguments string
|
||||
}
|
||||
|
||||
var (
|
||||
apply string
|
||||
names []string
|
||||
registry = make(map[string]Effect)
|
||||
)
|
||||
|
||||
func Register(e Effect) {
|
||||
name := e.String()
|
||||
|
||||
names = append(names, name)
|
||||
|
||||
registry[name] = e
|
||||
}
|
||||
|
||||
func HasEffects() bool {
|
||||
return len(registry) > 0
|
||||
}
|
||||
|
||||
func Flags(flags []cli.Flag) []cli.Flag {
|
||||
if len(registry) == 0 {
|
||||
return flags
|
||||
}
|
||||
|
||||
return append(flags,
|
||||
&cli.StringFlag{
|
||||
Name: "effects",
|
||||
Aliases: []string{"e"},
|
||||
Usage: fmt.Sprintf("list of effects to apply (%s)", strings.Join(names, ", ")),
|
||||
Value: "",
|
||||
Destination: &apply,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func ApplyAll(img image.Image) (image.Image, int, error) {
|
||||
if apply == "" {
|
||||
return img, 0, nil
|
||||
}
|
||||
|
||||
list, err := Parse()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
} else if len(list) == 0 {
|
||||
return img, 0, nil
|
||||
}
|
||||
|
||||
for _, e := range list {
|
||||
img, err = e.Effect.Apply(img, e.Arguments)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
}
|
||||
|
||||
return img, len(list), nil
|
||||
}
|
||||
|
||||
func Parse() ([]EffectConfig, error) {
|
||||
var result []EffectConfig
|
||||
|
||||
for entry := range strings.SplitSeq(apply, ",") {
|
||||
var (
|
||||
name = entry
|
||||
arguments string
|
||||
)
|
||||
|
||||
if index := strings.Index(entry, ":"); index != -1 {
|
||||
name = entry[:index]
|
||||
arguments = entry[index+1:]
|
||||
}
|
||||
|
||||
effect, ok := registry[name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid effect: %s", name)
|
||||
}
|
||||
|
||||
result = append(result, EffectConfig{
|
||||
Effect: effect,
|
||||
Arguments: arguments,
|
||||
})
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
25
internal/effects/grayscale/grayscale.go
Normal file
25
internal/effects/grayscale/grayscale.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package grayscale
|
||||
|
||||
import (
|
||||
"image"
|
||||
|
||||
"github.com/anthonynsimon/bild/effect"
|
||||
"github.com/coalaura/ffwebp/internal/effects"
|
||||
"github.com/coalaura/ffwebp/internal/logx"
|
||||
)
|
||||
|
||||
type impl struct{}
|
||||
|
||||
func init() {
|
||||
effects.Register(impl{})
|
||||
}
|
||||
|
||||
func (impl) String() string {
|
||||
return "grayscale"
|
||||
}
|
||||
|
||||
func (impl) Apply(img image.Image, _ string) (image.Image, error) {
|
||||
logx.Printf(" applying grayscale\n")
|
||||
|
||||
return effect.Grayscale(img), nil
|
||||
}
|
38
internal/effects/hue/hue.go
Normal file
38
internal/effects/hue/hue.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package hue
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"strconv"
|
||||
|
||||
"github.com/anthonynsimon/bild/adjust"
|
||||
"github.com/coalaura/ffwebp/internal/effects"
|
||||
"github.com/coalaura/ffwebp/internal/logx"
|
||||
)
|
||||
|
||||
type impl struct{}
|
||||
|
||||
func init() {
|
||||
effects.Register(impl{})
|
||||
}
|
||||
|
||||
func (impl) String() string {
|
||||
return "hue"
|
||||
}
|
||||
|
||||
func (impl) Apply(img image.Image, args string) (image.Image, error) {
|
||||
var change int64 = 10
|
||||
|
||||
if args != "" {
|
||||
i64, err := strconv.ParseInt(args, 10, 64)
|
||||
if err != nil || i64 < -360 || i64 > 360 || i64 == 0 {
|
||||
return nil, fmt.Errorf("invalid hue change: %s", args)
|
||||
}
|
||||
|
||||
change = i64
|
||||
}
|
||||
|
||||
logx.Printf(" applying hue (change=%d)\n", change)
|
||||
|
||||
return adjust.Hue(img, int(change)), nil
|
||||
}
|
25
internal/effects/invert/invert.go
Normal file
25
internal/effects/invert/invert.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package invert
|
||||
|
||||
import (
|
||||
"image"
|
||||
|
||||
"github.com/anthonynsimon/bild/effect"
|
||||
"github.com/coalaura/ffwebp/internal/effects"
|
||||
"github.com/coalaura/ffwebp/internal/logx"
|
||||
)
|
||||
|
||||
type impl struct{}
|
||||
|
||||
func init() {
|
||||
effects.Register(impl{})
|
||||
}
|
||||
|
||||
func (impl) String() string {
|
||||
return "invert"
|
||||
}
|
||||
|
||||
func (impl) Apply(img image.Image, _ string) (image.Image, error) {
|
||||
logx.Printf(" applying invert\n")
|
||||
|
||||
return effect.Invert(img), nil
|
||||
}
|
38
internal/effects/saturation/saturation.go
Normal file
38
internal/effects/saturation/saturation.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package saturation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"strconv"
|
||||
|
||||
"github.com/anthonynsimon/bild/adjust"
|
||||
"github.com/coalaura/ffwebp/internal/effects"
|
||||
"github.com/coalaura/ffwebp/internal/logx"
|
||||
)
|
||||
|
||||
type impl struct{}
|
||||
|
||||
func init() {
|
||||
effects.Register(impl{})
|
||||
}
|
||||
|
||||
func (impl) String() string {
|
||||
return "saturation"
|
||||
}
|
||||
|
||||
func (impl) Apply(img image.Image, args string) (image.Image, error) {
|
||||
var change float64 = 0.1
|
||||
|
||||
if args != "" {
|
||||
f64, err := strconv.ParseFloat(args, 64)
|
||||
if err != nil || f64 < -1 || f64 > 1 || f64 == 0 {
|
||||
return nil, fmt.Errorf("invalid saturation change: %s", args)
|
||||
}
|
||||
|
||||
change = f64
|
||||
}
|
||||
|
||||
logx.Printf(" applying saturation (change=%.f)\n", change)
|
||||
|
||||
return adjust.Saturation(img, change), nil
|
||||
}
|
25
internal/effects/sepia/grayscale.go
Normal file
25
internal/effects/sepia/grayscale.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package sepia
|
||||
|
||||
import (
|
||||
"image"
|
||||
|
||||
"github.com/anthonynsimon/bild/effect"
|
||||
"github.com/coalaura/ffwebp/internal/effects"
|
||||
"github.com/coalaura/ffwebp/internal/logx"
|
||||
)
|
||||
|
||||
type impl struct{}
|
||||
|
||||
func init() {
|
||||
effects.Register(impl{})
|
||||
}
|
||||
|
||||
func (impl) String() string {
|
||||
return "sepia"
|
||||
}
|
||||
|
||||
func (impl) Apply(img image.Image, _ string) (image.Image, error) {
|
||||
logx.Printf(" applying sepia\n")
|
||||
|
||||
return effect.Sepia(img), nil
|
||||
}
|
25
internal/effects/sharpen/sharpen.go
Normal file
25
internal/effects/sharpen/sharpen.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package sharpen
|
||||
|
||||
import (
|
||||
"image"
|
||||
|
||||
"github.com/anthonynsimon/bild/effect"
|
||||
"github.com/coalaura/ffwebp/internal/effects"
|
||||
"github.com/coalaura/ffwebp/internal/logx"
|
||||
)
|
||||
|
||||
type impl struct{}
|
||||
|
||||
func init() {
|
||||
effects.Register(impl{})
|
||||
}
|
||||
|
||||
func (impl) String() string {
|
||||
return "sharpen"
|
||||
}
|
||||
|
||||
func (impl) Apply(img image.Image, _ string) (image.Image, error) {
|
||||
logx.Printf(" applying sharpen\n")
|
||||
|
||||
return effect.Sharpen(img), nil
|
||||
}
|
Reference in New Issue
Block a user