diff --git a/services/thumbnails/pkg/preprocessor/preprocessor.go b/services/thumbnails/pkg/preprocessor/preprocessor.go index 4254c1a68b..d4626b11e2 100644 --- a/services/thumbnails/pkg/preprocessor/preprocessor.go +++ b/services/thumbnails/pkg/preprocessor/preprocessor.go @@ -27,18 +27,6 @@ type FileConverter interface { Convert(r io.Reader) (interface{}, error) } -// ImageDecoder is a converter for the image file -type ImageDecoder struct{} - -// Convert reads the image file and returns the thumbnail image -func (i ImageDecoder) Convert(r io.Reader) (interface{}, error) { - img, err := imaging.Decode(r, imaging.AutoOrientation(true)) - if err != nil { - return nil, errors.Wrap(err, `could not decode the image`) - } - return img, nil -} - // GifDecoder is a converter for the gif file type GifDecoder struct{} diff --git a/services/thumbnails/pkg/preprocessor/preprocessor_imaging.go b/services/thumbnails/pkg/preprocessor/preprocessor_imaging.go new file mode 100644 index 0000000000..99c7d91a83 --- /dev/null +++ b/services/thumbnails/pkg/preprocessor/preprocessor_imaging.go @@ -0,0 +1,20 @@ +package preprocessor + +import ( + "io" + + "github.com/kovidgoyal/imaging" + "github.com/pkg/errors" +) + +// ImageDecoder is a converter for the image file +type ImageDecoder struct{} + +// Convert reads the image file and returns the thumbnail image +func (i ImageDecoder) Convert(r io.Reader) (interface{}, error) { + img, err := imaging.Decode(r, imaging.AutoOrientation(true)) + if err != nil { + return nil, errors.Wrap(err, `could not decode the image`) + } + return img, nil +} diff --git a/services/thumbnails/pkg/thumbnail/encoding.go b/services/thumbnails/pkg/thumbnail/encoding.go index 2cf22ba360..917642db98 100644 --- a/services/thumbnails/pkg/thumbnail/encoding.go +++ b/services/thumbnails/pkg/thumbnail/encoding.go @@ -1,10 +1,7 @@ package thumbnail import ( - "image" "image/gif" - "image/jpeg" - "image/png" "io" "strings" @@ -29,50 +26,6 @@ type Encoder interface { MimeType() string } -// PngEncoder encodes to png -type PngEncoder struct{} - -// Encode encodes to png format -func (e PngEncoder) Encode(w io.Writer, img interface{}) error { - m, ok := img.(image.Image) - if !ok { - return errors.ErrInvalidType - } - return png.Encode(w, m) -} - -// Types returns the png suffix -func (e PngEncoder) Types() []string { - return []string{typePng} -} - -// MimeType returns the mimetype for png files. -func (e PngEncoder) MimeType() string { - return "image/png" -} - -// JpegEncoder encodes to jpg -type JpegEncoder struct{} - -// Encode encodes to jpg -func (e JpegEncoder) Encode(w io.Writer, img interface{}) error { - m, ok := img.(image.Image) - if !ok { - return errors.ErrInvalidType - } - return jpeg.Encode(w, m, nil) -} - -// Types returns the jpg suffixes. -func (e JpegEncoder) Types() []string { - return []string{typeJpeg, typeJpg} -} - -// MimeType returns the mimetype for jpg files. -func (e JpegEncoder) MimeType() string { - return "image/jpeg" -} - // GifEncoder encodes to gif type GifEncoder struct{} diff --git a/services/thumbnails/pkg/thumbnail/encoding_imaging.go b/services/thumbnails/pkg/thumbnail/encoding_imaging.go new file mode 100644 index 0000000000..7ae2c09b6b --- /dev/null +++ b/services/thumbnails/pkg/thumbnail/encoding_imaging.go @@ -0,0 +1,54 @@ +package thumbnail + +import ( + "image" + "image/jpeg" + "image/png" + "io" + + "github.com/owncloud/ocis/v2/services/thumbnails/pkg/errors" +) + +// PngEncoder encodes to png +type PngEncoder struct{} + +// Encode encodes to png format +func (e PngEncoder) Encode(w io.Writer, img interface{}) error { + m, ok := img.(image.Image) + if !ok { + return errors.ErrInvalidType + } + return png.Encode(w, m) +} + +// Types returns the png suffix +func (e PngEncoder) Types() []string { + return []string{typePng} +} + +// MimeType returns the mimetype for png files. +func (e PngEncoder) MimeType() string { + return "image/png" +} + +// JpegEncoder encodes to jpg +type JpegEncoder struct{} + +// Encode encodes to jpg +func (e JpegEncoder) Encode(w io.Writer, img interface{}) error { + m, ok := img.(image.Image) + if !ok { + return errors.ErrInvalidType + } + return jpeg.Encode(w, m, nil) +} + +// Types returns the jpg suffixes. +func (e JpegEncoder) Types() []string { + return []string{typeJpeg, typeJpg} +} + +// MimeType returns the mimetype for jpg files. +func (e JpegEncoder) MimeType() string { + return "image/jpeg" +} diff --git a/services/thumbnails/pkg/thumbnail/generator.go b/services/thumbnails/pkg/thumbnail/generator.go index 463daddcea..9c90d33f38 100644 --- a/services/thumbnails/pkg/thumbnail/generator.go +++ b/services/thumbnails/pkg/thumbnail/generator.go @@ -14,44 +14,17 @@ import ( // Generator generates a web friendly file version. type Generator interface { Generate(size image.Rectangle, img interface{}) (interface{}, error) + Dimensions(img interface{}) (image.Rectangle, error) ProcessorID() string } -// SimpleGenerator is the default image generator and is used for all image types expect gif. -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{}) (interface{}, error) { - m, ok := img.(image.Image) - if !ok { - return nil, errors.ErrInvalidType - } - - 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 { processor Processor } func NewGifGenerator(filetype, process string) (GifGenerator, error) { - processor, err := ProcessorFor(filetype, process) + processor, err := ProcessorFor(process, filetype) if err != nil { return GifGenerator{}, err } @@ -97,6 +70,14 @@ func (g GifGenerator) Generate(size image.Rectangle, img interface{}) (interface return m, nil } +func (g GifGenerator) Dimensions(img interface{}) (image.Rectangle, error) { + m, ok := img.(*gif.GIF) + if !ok { + return image.Rectangle{}, errors.ErrInvalidType + } + return m.Image[0].Bounds(), nil +} + func (g GifGenerator) imageToPaletted(img image.Image, p color.Palette) *image.Paletted { b := img.Bounds() pm := image.NewPaletted(b, p) diff --git a/services/thumbnails/pkg/thumbnail/generator_simple.go b/services/thumbnails/pkg/thumbnail/generator_simple.go new file mode 100644 index 0000000000..d23af905d7 --- /dev/null +++ b/services/thumbnails/pkg/thumbnail/generator_simple.go @@ -0,0 +1,44 @@ +package thumbnail + +import ( + "image" + + "github.com/kovidgoyal/imaging" + "github.com/owncloud/ocis/v2/services/thumbnails/pkg/errors" +) + +// SimpleGenerator is the default image generator and is used for all image types expect gif. +type SimpleGenerator struct { + processor Processor +} + +func NewSimpleGenerator(filetype, process string) (SimpleGenerator, error) { + processor, err := ProcessorFor(process, filetype) + 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{}) (interface{}, error) { + m, ok := img.(image.Image) + if !ok { + return nil, errors.ErrInvalidType + } + + return g.processor.Process(m, size.Dx(), size.Dy(), imaging.Lanczos), nil +} + +func (g SimpleGenerator) Dimensions(img interface{}) (image.Rectangle, error) { + m, ok := img.(image.Image) + if !ok { + return image.Rectangle{}, errors.ErrInvalidType + } + return m.Bounds(), nil +} diff --git a/services/thumbnails/pkg/thumbnail/thumbnail.go b/services/thumbnails/pkg/thumbnail/thumbnail.go index adbb13d6c4..68559e5ea9 100644 --- a/services/thumbnails/pkg/thumbnail/thumbnail.go +++ b/services/thumbnails/pkg/thumbnail/thumbnail.go @@ -3,7 +3,6 @@ package thumbnail import ( "bytes" "image" - "image/gif" "mime" "github.com/owncloud/ocis/v2/ocis-pkg/log" @@ -70,15 +69,12 @@ type SimpleManager struct { // Generate creates a thumbnail and stores it func (s SimpleManager) Generate(r Request, img interface{}) (string, error) { var match image.Rectangle - var inputDimensions image.Rectangle - switch m := img.(type) { - case *gif.GIF: - match = s.resolutions.ClosestMatch(r.Resolution, m.Image[0].Bounds()) - inputDimensions = m.Image[0].Bounds() - case image.Image: - match = s.resolutions.ClosestMatch(r.Resolution, m.Bounds()) - inputDimensions = m.Bounds() + + inputDimensions, err := r.Generator.Dimensions(img) + if err != nil { + return "", err } + match = s.resolutions.ClosestMatch(r.Resolution, inputDimensions) // validate max input image dimensions - 6016x4000 if inputDimensions.Size().X > s.maxDimension.X || inputDimensions.Size().Y > s.maxDimension.Y { diff --git a/services/thumbnails/pkg/thumbnail/thumbnail_test.go b/services/thumbnails/pkg/thumbnail/thumbnail_test.go index 660d2c8dad..9998b69aea 100644 --- a/services/thumbnails/pkg/thumbnail/thumbnail_test.go +++ b/services/thumbnails/pkg/thumbnail/thumbnail_test.go @@ -183,6 +183,10 @@ func TestPreviewGenerationTooBigImage(t *testing.T) { ext := path.Ext(tt.fileName) req.Encoder, _ = EncoderForType(ext) + req.Generator, err = GeneratorFor(ext, "fit") + if err != nil { + return + } generate, err := sut.Generate(req, convert) if err != nil { return