From c9f6b961f93bc625f5bc40763155e280e4ae0914 Mon Sep 17 00:00:00 2001 From: Christian Richter Date: Fri, 24 Nov 2023 15:10:51 +0100 Subject: [PATCH] Add geogebra previews Co-authored-by: Florian Schade Signed-off-by: Christian Richter --- .../pkg/preprocessor/preprocessor.go | 34 +++++++++++ .../pkg/preprocessor/preprocessor_test.go | 57 +++++++++++++++++++ services/thumbnails/pkg/thumbnail/encoding.go | 2 +- .../thumbnails/pkg/thumbnail/generator.go | 12 +--- 4 files changed, 93 insertions(+), 12 deletions(-) create mode 100644 services/thumbnails/pkg/preprocessor/preprocessor_test.go diff --git a/services/thumbnails/pkg/preprocessor/preprocessor.go b/services/thumbnails/pkg/preprocessor/preprocessor.go index 2f6346ec74..e03e52e5da 100644 --- a/services/thumbnails/pkg/preprocessor/preprocessor.go +++ b/services/thumbnails/pkg/preprocessor/preprocessor.go @@ -1,8 +1,10 @@ package preprocessor import ( + "archive/zip" "bufio" "bytes" + "fmt" "image" "image/draw" "image/gif" @@ -44,6 +46,36 @@ func (i GifDecoder) Convert(r io.Reader) (interface{}, error) { return img, nil } +type GgsDecoder struct{} + +func (g GgsDecoder) Convert(r io.Reader) (interface{}, error) { + geogebraThumbnail := "_slide0/geogebra_thumbnail.png" + var buf bytes.Buffer + _, err := io.Copy(&buf, r) + if err != nil { + return nil, err + } + zipReader, err := zip.NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len())) + if err != nil { + return nil, err + } + for _, file := range zipReader.File { + if file.Name == geogebraThumbnail { + thumbnail, err := file.Open() + if err != nil { + return nil, err + } + + img, err := imaging.Decode(thumbnail, imaging.AutoOrientation(true)) + if err != nil { + return nil, errors.Wrap(err, `could not decode the image`) + } + return img, nil + } + } + return nil, errors.New(fmt.Sprintf("%s not found", geogebraThumbnail)) +} + type AudioDecoder struct{} func (i AudioDecoder) Convert(r io.Reader) (interface{}, error) { @@ -223,6 +255,8 @@ func ForType(mimeType string, opts map[string]interface{}) FileConverter { return TxtToImageConverter{ fontLoader: fontLoader, } + case "application/vnd.geogebra.slides": + return GgsDecoder{} case "image/gif": return GifDecoder{} case "audio/flac": diff --git a/services/thumbnails/pkg/preprocessor/preprocessor_test.go b/services/thumbnails/pkg/preprocessor/preprocessor_test.go new file mode 100644 index 0000000000..c96c41ec2b --- /dev/null +++ b/services/thumbnails/pkg/preprocessor/preprocessor_test.go @@ -0,0 +1,57 @@ +package preprocessor + +import ( + "bytes" + "image" + "io" + "reflect" + + "testing" +) + +// implement tests for the following structs and functions: +// ImageDecoder +// GifDecoder +// GgsDecoder + +// TestImageDecoderConvert tests the function Convert of the struct ImageDecoder +func TestImageDecoderConvert(t *testing.T) { + type args struct { + r io.Reader + } + tests := []struct { + name string + i ImageDecoder + args args + want interface{} + wantErr bool + }{ + { + name: "Test successful convert image", + args: args{ + r: bytes.NewReader([]byte("")), + }, + want: image.Image{}, + wantErr: false, + }, + { + name: "Test unsuccessful convert image", + args: args{ + r: bytes.NewReader([]byte("")), + }, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + i := ImageDecoder{} + got, err := i.Convert(tt.args.r) + if (err != nil) != tt.wantErr { + t.Errorf("%q. ImageDecoder.Convert() error = %v, wantErr %v", tt.name, err, tt.wantErr) + return + } + if !reflect.DeepEqual(reflect.TypeOf(got), reflect.TypeOf(tt.want)) { + t.Errorf("%q. ImageDecoder.Convert() = %v, want %v", tt.name, got, tt.want) + } + } +} diff --git a/services/thumbnails/pkg/thumbnail/encoding.go b/services/thumbnails/pkg/thumbnail/encoding.go index af7fd349b0..65b5b17373 100644 --- a/services/thumbnails/pkg/thumbnail/encoding.go +++ b/services/thumbnails/pkg/thumbnail/encoding.go @@ -103,7 +103,7 @@ func (e GifEncoder) MimeType() string { // or nil if the type is not supported. func EncoderForType(fileType string) (Encoder, error) { switch strings.ToLower(fileType) { - case typePng: + case typePng, typeGgs: return PngEncoder{}, nil case typeJpg, typeJpeg: return JpegEncoder{}, nil diff --git a/services/thumbnails/pkg/thumbnail/generator.go b/services/thumbnails/pkg/thumbnail/generator.go index 8ae2d3a726..64aa086dff 100644 --- a/services/thumbnails/pkg/thumbnail/generator.go +++ b/services/thumbnails/pkg/thumbnail/generator.go @@ -71,24 +71,14 @@ func (g GifGenerator) imageToPaletted(img image.Image, p color.Palette) *image.P return pm } -// GgsGenerator is used to create a web friendly version of the provided ggs image. -type GgsGenerator struct{} - -func (g GgsGenerator) Generate(size image.Rectangle, img interface{}, processor Processor) (interface{}, error) { - // TODO: write zip extractor, get image from zip, process image, return image - return nil, nil -} - // GeneratorForType returns the generator for a given file type // or nil if the type is not supported. func GeneratorForType(fileType string) (Generator, error) { switch strings.ToLower(fileType) { - case typePng, typeJpg, typeJpeg: + case typePng, typeJpg, typeJpeg, typeGgs: return SimpleGenerator{}, nil case typeGif: return GifGenerator{}, nil - case typeGgs: - return GgsGenerator{}, nil default: return nil, ErrNoEncoderForType }