From c84d4c97bdcf2bae68e9b0e44ecaecc6b54d0026 Mon Sep 17 00:00:00 2001 From: Roman Zipp Date: Thu, 20 Jan 2022 18:13:27 +0100 Subject: [PATCH] Add image flip step --- config/example.json | 6 ++- pipelines/executable_step.go | 24 +++++++++++ pipelines/pipeline_test.go | 84 +++++++++++++++++++++++++++++++++++- pipelines/step.go | 8 ++++ 4 files changed, 120 insertions(+), 2 deletions(-) diff --git a/config/example.json b/config/example.json index e6600bc..eb65944 100644 --- a/config/example.json +++ b/config/example.json @@ -21,8 +21,12 @@ } }, { - "name": "grayscale", + "name": "flip image", "type": 2 + }, + { + "name": "grayscale", + "type": 3 } ], "output": { diff --git a/pipelines/executable_step.go b/pipelines/executable_step.go index 5ad7ef4..518b839 100644 --- a/pipelines/executable_step.go +++ b/pipelines/executable_step.go @@ -1,6 +1,8 @@ package pipelines import ( + "errors" + "fmt" "github.com/disintegration/imaging" "image" ) @@ -39,6 +41,28 @@ func (s RotateImageStep) Execute(src image.Image) (image.Image, error) { return src, nil } +// Flip image + +type FlipImageStep struct { + Step + Options struct { + Direction string `json:"direction"` + } `json:"options"` +} + +func (s FlipImageStep) Execute(src image.Image) (image.Image, error) { + switch s.Options.Direction { + case "h": + src = imaging.FlipH(src) + case "v": + src = imaging.FlipH(src) + default: + return src, errors.New(fmt.Sprintf("invalid flip direction: %s", s.Options.Direction)) + } + + return src, nil +} + // Grayscale image type GrayscaleImageStep struct { diff --git a/pipelines/pipeline_test.go b/pipelines/pipeline_test.go index 3665f0f..4bee961 100644 --- a/pipelines/pipeline_test.go +++ b/pipelines/pipeline_test.go @@ -190,6 +190,88 @@ func TestExecuteSteps(t *testing.T) { os.Remove(storageProvider.GetPath(Bucket, dest)) }) + t.Run("Image flip step is successful", func(t *testing.T) { + const Bucket string = "pipeline_test_06" + const Payload string = `{ + "name": "example pipeline", + "type": 1, + "removeMetadata": false, + "steps": [ + { + "name": "flip image", + "type": 2, + "options": { + "direction": "h" + } + } + ] + }` + + wd, _ := os.Getwd() + pipe := DeserializePipelines([][]byte{[]byte(Payload)})[0] + + storageProvider := storage.GetFileSystemStorageProvider("test", "..") + + // copy test file to storage bucket + _, err := storageProvider.StoreExisting(Bucket, "source.jpg", filepath.Join(wd, "../tests/files/800x500.jpg")) + assert.Nil(t, err, "Test file should be readable") + assert.FileExists(t, storageProvider.GetPath(Bucket, "source.jpg")) + + // run pipeline steps + dest, err := pipe.Run("source.jpg", Bucket, storageProvider) + assert.Nil(t, err) + assert.FileExists(t, storageProvider.GetPath(Bucket, dest)) + + // read image config + file, err := storageProvider.OpenFile(Bucket, dest) + assert.Nil(t, err) + + imgConf, _, err := image.DecodeConfig(file) + assert.Nil(t, err) + + assert.Equal(t, 800, imgConf.Width) + assert.Equal(t, 500, imgConf.Height) + + // clean up + os.Remove(storageProvider.GetPath(Bucket, "source.jpg")) + os.Remove(storageProvider.GetPath(Bucket, dest)) + }) + + t.Run("Image flip step direction validation is successful", func(t *testing.T) { + const Bucket string = "pipeline_test_06" + const Payload string = `{ + "name": "example pipeline", + "type": 1, + "removeMetadata": false, + "steps": [ + { + "name": "flip image", + "type": 2, + "options": { + "direction": "f" + } + } + ] + }` + + wd, _ := os.Getwd() + pipe := DeserializePipelines([][]byte{[]byte(Payload)})[0] + + storageProvider := storage.GetFileSystemStorageProvider("test", "..") + + // copy test file to storage bucket + _, err := storageProvider.StoreExisting(Bucket, "source.jpg", filepath.Join(wd, "../tests/files/800x500.jpg")) + assert.Nil(t, err, "Test file should be readable") + assert.FileExists(t, storageProvider.GetPath(Bucket, "source.jpg")) + + // run pipeline steps + _, err = pipe.Run("source.jpg", Bucket, storageProvider) + assert.EqualError(t, err, "invalid flip direction: f") + + // clean up + os.Remove(storageProvider.GetPath(Bucket, "source.jpg")) + }) + t.Run("Image grayscale step is successful", func(t *testing.T) { const Bucket string = "pipeline_test_05" const Payload string = `{ @@ -199,7 +281,7 @@ func TestExecuteSteps(t *testing.T) { "steps": [ { "name": "grayscale", - "type": 2 + "type": 3 } ] }` diff --git a/pipelines/step.go b/pipelines/step.go index 919c685..9d60844 100644 --- a/pipelines/step.go +++ b/pipelines/step.go @@ -10,6 +10,7 @@ type StepType int const ( TypeResizeImageStep StepType = iota TypeRotateImageStep + TypeFlipImageStep TypeGrayscaleImageStep ) @@ -36,6 +37,13 @@ func (s Step) GetExecutable() (IExecutableStep, error) { } return step, nil + case TypeFlipImageStep: + step := FlipImageStep{} + if err := json.Unmarshal(s.Options, &step.Options); err != nil { + return nil, err + } + return step, nil + case TypeGrayscaleImageStep: return GrayscaleImageStep{}, nil }