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.
This commit is contained in:
Ralf Haferkamp
2024-10-14 15:16:48 +02:00
committed by Ralf Haferkamp
parent 08b33627b2
commit d0ce57dfc2
3 changed files with 55 additions and 25 deletions

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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))
}
})
}
}