From d0ce57dfc277863b36933818389879e5f27ed5ff Mon Sep 17 00:00:00 2001 From: Ralf Haferkamp Date: Mon, 14 Oct 2024 15:16:48 +0200 Subject: [PATCH] refactor(thumbnails): merge processor into generator Processor is now part of the generator. This should make it possible to implement thumbnail generators that do not depend on the 'imaging' module. --- .../thumbnails/pkg/thumbnail/generator.go | 54 +++++++++++++++---- .../thumbnails/pkg/thumbnail/thumbnail.go | 12 ++--- .../pkg/thumbnail/thumbnail_test.go | 14 +++-- 3 files changed, 55 insertions(+), 25 deletions(-) diff --git a/services/thumbnails/pkg/thumbnail/generator.go b/services/thumbnails/pkg/thumbnail/generator.go index 177aad17a4..463daddcea 100644 --- a/services/thumbnails/pkg/thumbnail/generator.go +++ b/services/thumbnails/pkg/thumbnail/generator.go @@ -13,27 +13,59 @@ import ( // Generator generates a web friendly file version. type Generator interface { - Generate(size image.Rectangle, img interface{}, processor Processor) (interface{}, error) + Generate(size image.Rectangle, img interface{}) (interface{}, error) + ProcessorID() string } // SimpleGenerator is the default image generator and is used for all image types expect gif. -type SimpleGenerator struct{} +type SimpleGenerator struct { + processor Processor +} + +func NewSimpleGenerator(filetype, process string) (SimpleGenerator, error) { + processor, err := ProcessorFor(filetype, process) + if err != nil { + return SimpleGenerator{}, err + } + return SimpleGenerator{processor: processor}, nil +} + +// ProcessorID returns the processor identification. +func (g SimpleGenerator) ProcessorID() string { + return g.processor.ID() +} // Generate generates a alternative image version. -func (g SimpleGenerator) Generate(size image.Rectangle, img interface{}, processor Processor) (interface{}, error) { +func (g SimpleGenerator) Generate(size image.Rectangle, img interface{}) (interface{}, error) { m, ok := img.(image.Image) if !ok { return nil, errors.ErrInvalidType } - return processor.Process(m, size.Dx(), size.Dy(), imaging.Lanczos), nil + return g.processor.Process(m, size.Dx(), size.Dy(), imaging.Lanczos), nil } // GifGenerator is used to create a web friendly version of the provided gif image. -type GifGenerator struct{} +type GifGenerator struct { + processor Processor +} + +func NewGifGenerator(filetype, process string) (GifGenerator, error) { + processor, err := ProcessorFor(filetype, process) + if err != nil { + return GifGenerator{}, err + } + return GifGenerator{processor: processor}, nil + +} + +// ProcessorID returns the processor identification. +func (g GifGenerator) ProcessorID() string { + return g.processor.ID() +} // Generate generates a alternative gif version. -func (g GifGenerator) Generate(size image.Rectangle, img interface{}, processor Processor) (interface{}, error) { +func (g GifGenerator) Generate(size image.Rectangle, img interface{}) (interface{}, error) { // Code inspired by https://github.com/willnorris/gifresize/blob/db93a7e1dcb1c279f7eeb99cc6d90b9e2e23e871/gifresize.go m, ok := img.(*gif.GIF) @@ -49,7 +81,7 @@ func (g GifGenerator) Generate(size image.Rectangle, img interface{}, processor bounds := frame.Bounds() prev := tmp draw.Draw(tmp, bounds, frame, bounds.Min, draw.Over) - processed := processor.Process(tmp, size.Dx(), size.Dy(), imaging.Lanczos) + processed := g.processor.Process(tmp, size.Dx(), size.Dy(), imaging.Lanczos) m.Image[i] = g.imageToPaletted(processed, frame.Palette) switch m.Disposal[i] { @@ -72,14 +104,14 @@ func (g GifGenerator) imageToPaletted(img image.Image, p color.Palette) *image.P return pm } -// GeneratorForType returns the generator for a given file type +// GeneratorFor returns the generator for a given file type // or nil if the type is not supported. -func GeneratorForType(fileType string) (Generator, error) { +func GeneratorFor(fileType, processorID string) (Generator, error) { switch strings.ToLower(fileType) { case typePng, typeJpg, typeJpeg, typeGgs: - return SimpleGenerator{}, nil + return NewSimpleGenerator(fileType, processorID) case typeGif: - return GifGenerator{}, nil + return NewGifGenerator(fileType, processorID) default: return nil, errors.ErrNoEncoderForType } diff --git a/services/thumbnails/pkg/thumbnail/thumbnail.go b/services/thumbnails/pkg/thumbnail/thumbnail.go index 48ffab36bd..adbb13d6c4 100644 --- a/services/thumbnails/pkg/thumbnail/thumbnail.go +++ b/services/thumbnails/pkg/thumbnail/thumbnail.go @@ -35,7 +35,6 @@ type Request struct { Encoder Encoder Generator Generator Checksum string - Processor Processor } // Manager is responsible for generating thumbnails @@ -86,7 +85,7 @@ func (s SimpleManager) Generate(r Request, img interface{}) (string, error) { return "", errors.ErrImageTooLarge } - thumbnail, err := r.Generator.Generate(match, img, r.Processor) + thumbnail, err := r.Generator.Generate(match, img) if err != nil { return "", err } @@ -120,7 +119,7 @@ func mapToStorageRequest(r Request) storage.Request { Checksum: r.Checksum, Resolution: r.Resolution, Types: r.Encoder.Types(), - Characteristic: r.Processor.ID(), + Characteristic: r.Generator.ProcessorID(), } } @@ -136,7 +135,7 @@ func IsMimeTypeSupported(m string) bool { // PrepareRequest prepare the request based on image parameters func PrepareRequest(width, height int, tType, checksum, pID string) (Request, error) { - generator, err := GeneratorForType(tType) + generator, err := GeneratorFor(tType, pID) if err != nil { return Request{}, err } @@ -144,16 +143,11 @@ func PrepareRequest(width, height int, tType, checksum, pID string) (Request, er if err != nil { return Request{}, err } - processor, err := ProcessorFor(pID, tType) - if err != nil { - return Request{}, err - } return Request{ Resolution: image.Rect(0, 0, width, height), Generator: generator, Encoder: encoder, Checksum: checksum, - Processor: processor, }, nil } diff --git a/services/thumbnails/pkg/thumbnail/thumbnail_test.go b/services/thumbnails/pkg/thumbnail/thumbnail_test.go index 2a046e15f5..660d2c8dad 100644 --- a/services/thumbnails/pkg/thumbnail/thumbnail_test.go +++ b/services/thumbnails/pkg/thumbnail/thumbnail_test.go @@ -1,15 +1,17 @@ package thumbnail import ( - "github.com/owncloud/ocis/v2/services/thumbnails/pkg/errors" - "github.com/owncloud/ocis/v2/services/thumbnails/pkg/preprocessor" - "github.com/stretchr/testify/assert" "image" "os" "path" "path/filepath" + "reflect" "testing" + "github.com/owncloud/ocis/v2/services/thumbnails/pkg/errors" + "github.com/owncloud/ocis/v2/services/thumbnails/pkg/preprocessor" + "github.com/stretchr/testify/assert" + "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" @@ -131,11 +133,13 @@ func TestPrepareRequest(t *testing.T) { t.Errorf("PrepareRequest() error = %v, wantErr %v", err, tt.wantErr) return } - // funcs are not reflactable, ignore - if diff := cmp.Diff(tt.want, got, cmpopts.IgnoreFields(Request{}, "Processor")); diff != "" { + if diff := cmp.Diff(tt.want, got, cmpopts.IgnoreFields(Request{}, "Generator")); diff != "" { t.Errorf("PrepareRequest(): %v", diff) } + if reflect.TypeOf(got.Generator) != reflect.TypeOf(tt.want.Generator) { + t.Errorf("PrepareRequest() = %v, want %v", reflect.TypeOf(got.Generator), reflect.TypeOf(tt.want.Generator)) + } }) } }