From e103b0dfae20ba07af9e283e82a5d73e38bef23a Mon Sep 17 00:00:00 2001 From: Edouard Paris Date: Tue, 10 Jul 2018 16:04:55 +0200 Subject: [PATCH 1/4] refac engine config --- config/config.go | 17 ++++++++++------ config/constants.go | 9 +++++++++ engine/backend/goimage.go | 22 ++++++++++---------- engine/backend/lilliput.go | 41 +++++++++++++++++++++++--------------- engine/config.go | 10 ---------- engine/config/config.go | 14 +++++++++++++ engine/engine.go | 9 +++++---- 7 files changed, 75 insertions(+), 47 deletions(-) delete mode 100644 engine/config.go create mode 100644 engine/config/config.go diff --git a/config/config.go b/config/config.go index 78a9eb0b..ae39d593 100644 --- a/config/config.go +++ b/config/config.go @@ -7,7 +7,7 @@ import ( "github.com/spf13/viper" "github.com/thoas/picfit/constants" - "github.com/thoas/picfit/engine" + engineconfig "github.com/thoas/picfit/engine/config" "github.com/thoas/picfit/kvstore" "github.com/thoas/picfit/logger" "github.com/thoas/picfit/storage" @@ -45,7 +45,7 @@ type Sentry struct { // Config is a struct to load configuration flags type Config struct { Debug bool - Engine *engine.Config + Engine *engineconfig.Config Sentry *Sentry SecretKey string `mapstructure:"secret_key"` Shard *Shard @@ -62,10 +62,15 @@ type Config struct { // DefaultConfig returns a default config instance func DefaultConfig() *Config { return &Config{ - Engine: &engine.Config{ - DefaultFormat: DefaultFormat, - Quality: DefaultQuality, - Format: "", + Engine: &engineconfig.Config{ + DefaultFormat: DefaultFormat, + Quality: DefaultQuality, + JpegQuality: DefaultQuality, + WebpQuality: DefaultQuality, + PngCompression: DefaultPngCompression, + MaxBufferSize: DefaultMaxBufferSize, + ImageBufferSize: DefaultImageBufferSize, + Format: "", }, Options: &Options{ EnableDelete: false, diff --git a/config/constants.go b/config/constants.go index 36d81431..c1f28747 100644 --- a/config/constants.go +++ b/config/constants.go @@ -24,3 +24,12 @@ const DefaultShardDepth = 0 // DefaultShardRestOnly is the default shard rest behaviour const DefaultShardRestOnly = true + +// DefaultPngCompression is the default compression for png. +const DefaultPngCompression = 0 + +// DefaultMaxBufferSize is the maximum size of buffer for lilliput +const DefaultMaxBufferSize = 8192 + +// DefaultImageBufferSize is the default image buffer size for lilliput +const DefaultImageBufferSize = 5 * 1024 * 1024 diff --git a/engine/backend/goimage.go b/engine/backend/goimage.go index 36bd1290..75013d7c 100644 --- a/engine/backend/goimage.go +++ b/engine/backend/goimage.go @@ -20,7 +20,7 @@ import ( "golang.org/x/image/tiff" ) -type GoImageEngine struct{} +type GoImage struct{} type ImageTransformation func(img image.Image) *image.NRGBA @@ -68,11 +68,11 @@ func imageToPaletted(img image.Image) *image.Paletted { return pm } -func (e *GoImageEngine) String() string { +func (e *GoImage) String() string { return "goimage" } -func (e *GoImageEngine) TransformGIF(img *imagefile.ImageFile, options *Options, trans Transformation) ([]byte, error) { +func (e *GoImage) TransformGIF(img *imagefile.ImageFile, options *Options, trans Transformation) ([]byte, error) { first, err := gif.Decode(bytes.NewReader(img.Source)) if err != nil { @@ -126,7 +126,7 @@ func (e *GoImageEngine) TransformGIF(img *imagefile.ImageFile, options *Options, return buf.Bytes(), nil } -func (e *GoImageEngine) Resize(img *imagefile.ImageFile, options *Options) ([]byte, error) { +func (e *GoImage) Resize(img *imagefile.ImageFile, options *Options) ([]byte, error) { if options.Format == imaging.GIF { content, err := e.TransformGIF(img, options, imaging.Resize) @@ -146,15 +146,15 @@ func (e *GoImageEngine) Resize(img *imagefile.ImageFile, options *Options) ([]by return e.transform(image, options, imaging.Resize) } -func (e *GoImageEngine) transform(img image.Image, options *Options, trans Transformation) ([]byte, error) { +func (e *GoImage) transform(img image.Image, options *Options, trans Transformation) ([]byte, error) { return e.ToBytes(scale(img, options, trans), options.Format, options.Quality) } -func (e *GoImageEngine) Source(img *imagefile.ImageFile) (image.Image, error) { +func (e *GoImage) Source(img *imagefile.ImageFile) (image.Image, error) { return decode(bytes.NewReader(img.Source)) } -func (e *GoImageEngine) Rotate(img *imagefile.ImageFile, options *Options) ([]byte, error) { +func (e *GoImage) Rotate(img *imagefile.ImageFile, options *Options) ([]byte, error) { image, err := e.Source(img) if err != nil { @@ -172,7 +172,7 @@ func (e *GoImageEngine) Rotate(img *imagefile.ImageFile, options *Options) ([]by return e.ToBytes(transform(image), options.Format, options.Quality) } -func (e *GoImageEngine) Flip(img *imagefile.ImageFile, options *Options) ([]byte, error) { +func (e *GoImage) Flip(img *imagefile.ImageFile, options *Options) ([]byte, error) { image, err := e.Source(img) if err != nil { @@ -190,7 +190,7 @@ func (e *GoImageEngine) Flip(img *imagefile.ImageFile, options *Options) ([]byte return e.ToBytes(transform(image), options.Format, options.Quality) } -func (e *GoImageEngine) Thumbnail(img *imagefile.ImageFile, options *Options) ([]byte, error) { +func (e *GoImage) Thumbnail(img *imagefile.ImageFile, options *Options) ([]byte, error) { if options.Format == imaging.GIF { content, err := e.TransformGIF(img, options, imaging.Thumbnail) @@ -210,7 +210,7 @@ func (e *GoImageEngine) Thumbnail(img *imagefile.ImageFile, options *Options) ([ return e.transform(image, options, imaging.Thumbnail) } -func (e *GoImageEngine) Fit(img *imagefile.ImageFile, options *Options) ([]byte, error) { +func (e *GoImage) Fit(img *imagefile.ImageFile, options *Options) ([]byte, error) { if options.Format == imaging.GIF { content, err := e.TransformGIF(img, options, imaging.Thumbnail) @@ -230,7 +230,7 @@ func (e *GoImageEngine) Fit(img *imagefile.ImageFile, options *Options) ([]byte, return e.transform(image, options, imaging.Fit) } -func (e *GoImageEngine) ToBytes(img image.Image, format imaging.Format, quality int) ([]byte, error) { +func (e *GoImage) ToBytes(img image.Image, format imaging.Format, quality int) ([]byte, error) { buf := &bytes.Buffer{} var err error diff --git a/engine/backend/lilliput.go b/engine/backend/lilliput.go index 30ede796..b84fddbd 100644 --- a/engine/backend/lilliput.go +++ b/engine/backend/lilliput.go @@ -7,63 +7,72 @@ import ( "github.com/discordapp/lilliput" "github.com/pkg/errors" + "github.com/thoas/picfit/engine/config" imagefile "github.com/thoas/picfit/image" ) -type LilliputEngine struct { - MaxBufferSize int +type Lilliput struct { + MaxBufferSize int + ImageBufferSize int + EncodeOptions map[int]int } -func NewLilliputEngine(maxBufferSize int) *LilliputEngine { - if maxBufferSize > 0 { - return &LilliputEngine{MaxBufferSize: maxBufferSize} - } - return &LilliputEngine{MaxBufferSize: 8192} +func NewLilliput(cfg config.Config) *Lilliput { + return &Lilliput{ + MaxBufferSize: cfg.MaxBufferSize, + ImageBufferSize: cfg.ImageBufferSize, + EncodeOptions: map[int]int{ + lilliput.JpegQuality: cfg.JpegQuality, + lilliput.PngCompression: cfg.PngCompression, + lilliput.WebpQuality: cfg.WebpQuality, + }} } // Resize resizes the image to the specified width and height and // returns the transformed image. If one of width or height is 0, // the image aspect ratio is preserved. -func (e *LilliputEngine) Resize(img *imagefile.ImageFile, options *Options) ([]byte, error) { +func (e *Lilliput) Resize(img *imagefile.ImageFile, options *Options) ([]byte, error) { opts := &lilliput.ImageOptions{ FileType: img.FilenameExt(), Width: options.Width, Height: options.Height, NormalizeOrientation: true, ResizeMethod: lilliput.ImageOpsResize, + EncodeOptions: e.EncodeOptions, } return e.transform(img, opts, options.Upscale) } -func (e *LilliputEngine) Rotate(img *imagefile.ImageFile, options *Options) ([]byte, error) { +func (e *Lilliput) Rotate(img *imagefile.ImageFile, options *Options) ([]byte, error) { return nil, MethodNotImplementedError } -func (e *LilliputEngine) Flip(img *imagefile.ImageFile, options *Options) ([]byte, error) { +func (e *Lilliput) Flip(img *imagefile.ImageFile, options *Options) ([]byte, error) { return nil, MethodNotImplementedError } // Thumbnail scales the image up or down using the specified resample filter, crops it // to the specified width and hight and returns the transformed image. -func (e *LilliputEngine) Thumbnail(img *imagefile.ImageFile, options *Options) ([]byte, error) { +func (e *Lilliput) Thumbnail(img *imagefile.ImageFile, options *Options) ([]byte, error) { opts := &lilliput.ImageOptions{ FileType: img.FilenameExt(), Width: options.Width, Height: options.Height, NormalizeOrientation: true, // Lilliput ImageOpsFit is a thumbnail operation - ResizeMethod: lilliput.ImageOpsFit, + ResizeMethod: lilliput.ImageOpsFit, + EncodeOptions: e.EncodeOptions, } return e.transform(img, opts, options.Upscale) } -func (e *LilliputEngine) Fit(img *imagefile.ImageFile, options *Options) ([]byte, error) { +func (e *Lilliput) Fit(img *imagefile.ImageFile, options *Options) ([]byte, error) { return nil, MethodNotImplementedError } -func (e *LilliputEngine) transform(img *imagefile.ImageFile, options *lilliput.ImageOptions, upscale bool) ([]byte, error) { +func (e *Lilliput) transform(img *imagefile.ImageFile, options *lilliput.ImageOptions, upscale bool) ([]byte, error) { decoder, err := lilliput.NewDecoder(img.Source) if err != nil { return nil, errors.WithStack(err) @@ -109,11 +118,11 @@ func (e *LilliputEngine) transform(img *imagefile.ImageFile, options *lilliput.I ops := lilliput.NewImageOps(e.MaxBufferSize) defer ops.Close() - outputImg := make([]byte, 50*1024*1024) + outputImg := make([]byte, e.ImageBufferSize) return ops.Transform(decoder, options, outputImg) } -func (e *LilliputEngine) String() string { +func (e *Lilliput) String() string { return "lilliput" } diff --git a/engine/config.go b/engine/config.go deleted file mode 100644 index 0dd76ac3..00000000 --- a/engine/config.go +++ /dev/null @@ -1,10 +0,0 @@ -package engine - -// Config is the engine config -type Config struct { - Backends []string `mapstructure:"backends"` - DefaultFormat string `mapstructure:"default_format"` - Format string `mapstructure:"format"` - Quality int `mapstructure:"quality"` - MaxBufferSize int `mapstructure:"max_buffer_size"` -} diff --git a/engine/config/config.go b/engine/config/config.go new file mode 100644 index 00000000..80af0403 --- /dev/null +++ b/engine/config/config.go @@ -0,0 +1,14 @@ +package config + +// Config is the engine config +type Config struct { + Backends []string `mapstructure:"backends"` + DefaultFormat string `mapstructure:"default_format"` + Format string `mapstructure:"format"` + Quality int `mapstructure:"quality"` + MaxBufferSize int `mapstructure:"max_buffer_size"` + ImageBufferSize int `mapstructure:"image_buffer_size"` + JpegQuality int `mapstructure:"jpeg_quality"` + PngCompression int `mapstructure:"jpeg_quality"` + WebpQuality int `mapstructure:"webp_quality"` +} diff --git a/engine/engine.go b/engine/engine.go index a5387d6f..3f77cad5 100644 --- a/engine/engine.go +++ b/engine/engine.go @@ -9,6 +9,7 @@ import ( "github.com/imdario/mergo" "github.com/thoas/picfit/engine/backend" + "github.com/thoas/picfit/engine/config" "github.com/thoas/picfit/image" ) @@ -41,18 +42,18 @@ const ( ) // New initializes an Engine -func New(cfg Config) *Engine { +func New(cfg config.Config) *Engine { var b []backend.Backend for i := range cfg.Backends { if cfg.Backends[i] == lilliputEngineType { - b = append(b, backend.NewLilliputEngine(cfg.MaxBufferSize)) + b = append(b, backend.NewLilliput(cfg)) } else if cfg.Backends[i] == goEngineType { - b = append(b, &backend.GoImageEngine{}) + b = append(b, &backend.GoImage{}) } } if len(b) == 0 { - b = append(b, &backend.GoImageEngine{}) + b = append(b, &backend.GoImage{}) } return &Engine{ From 5e1eb6591a10e938200aad6ceeb426d86f982c0f Mon Sep 17 00:00:00 2001 From: Edouard Paris Date: Tue, 10 Jul 2018 16:21:45 +0200 Subject: [PATCH 2/4] set default engine config --- config/config.go | 5 +---- config/constants.go | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/config/config.go b/config/config.go index ae39d593..274c176f 100644 --- a/config/config.go +++ b/config/config.go @@ -99,6 +99,7 @@ func load(content string, isPath bool) (*Config, error) { viper.SetDefault("shard", defaultConfig.Shard) viper.SetDefault("port", defaultConfig.Port) viper.SetDefault("kvstore", defaultConfig.KVStore) + viper.SetDefault("engine", defaultConfig.Engine) viper.SetEnvPrefix("picfit") var err error @@ -124,10 +125,6 @@ func load(content string, isPath bool) (*Config, error) { return nil, err } - if config.Engine == nil { - config.Engine = defaultConfig.Engine - } - return config, nil } diff --git a/config/constants.go b/config/constants.go index c1f28747..6a9df54f 100644 --- a/config/constants.go +++ b/config/constants.go @@ -32,4 +32,4 @@ const DefaultPngCompression = 0 const DefaultMaxBufferSize = 8192 // DefaultImageBufferSize is the default image buffer size for lilliput -const DefaultImageBufferSize = 5 * 1024 * 1024 +const DefaultImageBufferSize = 50 * 1024 * 1024 From 8d5517edf14d8d6deb16b024659dbf49978d4962 Mon Sep 17 00:00:00 2001 From: Edouard Paris Date: Tue, 10 Jul 2018 16:39:51 +0200 Subject: [PATCH 3/4] feat engine config defaults --- config/config.go | 6 +++--- config/constants.go | 9 --------- engine/backend/lilliput.go | 35 ++++++++++++++++++++++++++++++----- engine/config/constants.go | 13 +++++++++++++ 4 files changed, 46 insertions(+), 17 deletions(-) create mode 100644 engine/config/constants.go diff --git a/config/config.go b/config/config.go index 274c176f..a5462ba1 100644 --- a/config/config.go +++ b/config/config.go @@ -67,9 +67,9 @@ func DefaultConfig() *Config { Quality: DefaultQuality, JpegQuality: DefaultQuality, WebpQuality: DefaultQuality, - PngCompression: DefaultPngCompression, - MaxBufferSize: DefaultMaxBufferSize, - ImageBufferSize: DefaultImageBufferSize, + PngCompression: engineconfig.DefaultPngCompression, + MaxBufferSize: engineconfig.DefaultMaxBufferSize, + ImageBufferSize: engineconfig.DefaultImageBufferSize, Format: "", }, Options: &Options{ diff --git a/config/constants.go b/config/constants.go index 6a9df54f..36d81431 100644 --- a/config/constants.go +++ b/config/constants.go @@ -24,12 +24,3 @@ const DefaultShardDepth = 0 // DefaultShardRestOnly is the default shard rest behaviour const DefaultShardRestOnly = true - -// DefaultPngCompression is the default compression for png. -const DefaultPngCompression = 0 - -// DefaultMaxBufferSize is the maximum size of buffer for lilliput -const DefaultMaxBufferSize = 8192 - -// DefaultImageBufferSize is the default image buffer size for lilliput -const DefaultImageBufferSize = 50 * 1024 * 1024 diff --git a/engine/backend/lilliput.go b/engine/backend/lilliput.go index b84fddbd..7cd960e9 100644 --- a/engine/backend/lilliput.go +++ b/engine/backend/lilliput.go @@ -18,13 +18,38 @@ type Lilliput struct { } func NewLilliput(cfg config.Config) *Lilliput { + maxBufferSize := config.DefaultMaxBufferSize + if cfg.MaxBufferSize != 0 { + maxBufferSize = cfg.MaxBufferSize + } + + imageBufferSize := config.DefaultImageBufferSize + if cfg.ImageBufferSize != 0 { + imageBufferSize = cfg.ImageBufferSize + } + + jpegQuality := config.DefaultQuality + if cfg.JpegQuality != 0 { + jpegQuality = cfg.JpegQuality + } + + webpQuality := config.DefaultQuality + if cfg.WebpQuality != 0 { + webpQuality = cfg.WebpQuality + } + + pngCompression := config.DefaultPngCompression + if cfg.PngCompression != 0 { + pngCompression = cfg.PngCompression + } + return &Lilliput{ - MaxBufferSize: cfg.MaxBufferSize, - ImageBufferSize: cfg.ImageBufferSize, + MaxBufferSize: maxBufferSize, + ImageBufferSize: imageBufferSize, EncodeOptions: map[int]int{ - lilliput.JpegQuality: cfg.JpegQuality, - lilliput.PngCompression: cfg.PngCompression, - lilliput.WebpQuality: cfg.WebpQuality, + lilliput.JpegQuality: jpegQuality, + lilliput.PngCompression: pngCompression, + lilliput.WebpQuality: webpQuality, }} } diff --git a/engine/config/constants.go b/engine/config/constants.go new file mode 100644 index 00000000..96e7dd52 --- /dev/null +++ b/engine/config/constants.go @@ -0,0 +1,13 @@ +package config + +// DefaultQuality is the default quality +const DefaultQuality = 85 + +// DefaultPngCompression is the default compression for png. +const DefaultPngCompression = 0 + +// DefaultMaxBufferSize is the maximum size of buffer for lilliput +const DefaultMaxBufferSize = 8192 + +// DefaultImageBufferSize is the default image buffer size for lilliput +const DefaultImageBufferSize = 50 * 1024 * 1024 From 3fd93390f21460476297fc8fcc045c2f4c046bfd Mon Sep 17 00:00:00 2001 From: Edouard Paris Date: Tue, 10 Jul 2018 17:05:12 +0200 Subject: [PATCH 4/4] fix wrong tag --- engine/config/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/config/config.go b/engine/config/config.go index 80af0403..dce7a483 100644 --- a/engine/config/config.go +++ b/engine/config/config.go @@ -9,6 +9,6 @@ type Config struct { MaxBufferSize int `mapstructure:"max_buffer_size"` ImageBufferSize int `mapstructure:"image_buffer_size"` JpegQuality int `mapstructure:"jpeg_quality"` - PngCompression int `mapstructure:"jpeg_quality"` + PngCompression int `mapstructure:"png_compression"` WebpQuality int `mapstructure:"webp_quality"` }