Browse Source

Add resizing images

feature/add-image-processing
Roman Zipp 3 years ago
parent
commit
d0d3e72ed9
  1. 4
      go.mod
  2. 8
      go.sum
  3. 16
      pipelines/executable_step.go
  4. 22
      pipelines/executable_step_test.go
  5. 41
      pipelines/pipeline.go
  6. 42
      pipelines/pipeline_test.go
  7. BIN
      tests/files/900x900.jpg

4
go.mod

@ -4,6 +4,7 @@ go 1.17
require (
github.com/bxcodec/faker/v3 v3.7.0
github.com/disintegration/imaging v1.6.2
github.com/gorilla/mux v1.8.0
github.com/spf13/afero v1.8.0
github.com/stretchr/testify v1.7.0
@ -14,7 +15,8 @@ require (
github.com/kr/pretty v0.3.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rogpeppe/go-internal v1.8.1-0.20211023094830-115ce09fd6b4 // indirect
golang.org/x/text v0.3.4 // indirect
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 // indirect
golang.org/x/text v0.3.6 // indirect
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
)

8
go.sum

@ -51,6 +51,8 @@ github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnht
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@ -177,6 +179,9 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ=
golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@ -288,8 +293,9 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=

16
pipelines/executable_step.go

@ -1,7 +1,12 @@
package pipelines
import (
"github.com/disintegration/imaging"
"image"
)
type IExecutableStep interface {
Execute()
Execute(src image.Image) (image.Image, error)
}
// Resize image
@ -15,8 +20,9 @@ type ResizeImageStep struct {
} `json:"options"`
}
func (s ResizeImageStep) Execute() {
// TODO
func (s ResizeImageStep) Execute(src image.Image) (image.Image, error) {
src = imaging.Resize(src, s.Options.Width, s.Options.Height, imaging.Linear)
return src, nil
}
// Compress image
@ -28,6 +34,6 @@ type CompressImageStep struct {
} `json:"options"`
}
func (s CompressImageStep) Execute() {
// TODO
func (s CompressImageStep) Execute(src image.Image) (image.Image, error) {
return src, nil
}

22
pipelines/executable_step_test.go

@ -78,3 +78,25 @@ func TestDeserializeMissingOptions(t *testing.T) {
assert.EqualError(t, err, "unexpected end of JSON input")
})
}
func TestLoadingImage(t *testing.T) {
const Payload string = `{
"name": "example pipeline",
"type": 0,
"removeMetadata": false,
"steps": [
{
"name": "resize image",
"type": 0
}
]
}`
t.Run("Loading image from filesystem to pipeline is successful", func(t *testing.T) {
values := DeserializePipelines([][]byte{[]byte(Payload)})
_, err := values[0].GetSteps()[0].GetExecutable()
assert.EqualError(t, err, "unexpected end of JSON input")
})
}

41
pipelines/pipeline.go

@ -1,8 +1,12 @@
package pipelines
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"github.com/disintegration/imaging"
"github.com/geplauder/lithium/storage"
"io/fs"
"log"
"os"
@ -23,6 +27,7 @@ type IPipeline interface {
GetSlug() string
GetType() PipelineType
GetSteps() []Step
Run(string, string, storage.IStorageProvider) (string, error)
}
type Pipeline struct {
@ -33,6 +38,42 @@ type Pipeline struct {
Steps []Step `json:"steps" faker:"-"`
}
func (p Pipeline) Run(srcPath, bucketName string, storageProvider storage.IStorageProvider) (string, error) {
fmt.Println("path: ", storageProvider.GetPath(bucketName, srcPath))
src, err := imaging.Open(storageProvider.GetPath(bucketName, srcPath))
if err != nil {
return "", errors.New(fmt.Sprintf("error opening file for processing: %s", err))
}
for _, step := range p.GetSteps() {
runner, err := step.GetExecutable()
if err != nil {
return "", err
}
src, err = runner.Execute(src)
if err != nil {
return "", err
}
}
// encode image to io buffer
buffer := new(bytes.Buffer)
if err := imaging.Encode(buffer, src, imaging.JPEG); err != nil {
return "", err
}
const fileName = "output.jpg" // TODO make variable
_, err = storageProvider.StoreRaw(bucketName, fileName, buffer.Bytes())
if err != nil {
return "", err
}
return fileName, nil
}
func (p Pipeline) GetName() string {
return p.Name
}

42
pipelines/pipeline_test.go

@ -1,6 +1,9 @@
package pipelines
import (
"github.com/geplauder/lithium/storage"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
@ -57,3 +60,42 @@ func TestVideoPipelineDeserialization(t *testing.T) {
assert.Equal(t, Video, values[0].GetType())
})
}
func TestResizeImage(t *testing.T) {
const Payload string = `{
"name": "example pipeline",
"type": 1,
"removeMetadata": false,
"steps": [
{
"name": "resize image",
"type": 0,
"options": {
"width": 1280,
"height": 720,
"upscale": false
}
}
]
}`
const Bucket string = "pipeline_test_01"
t.Run("Image resizing is successful", func(t *testing.T) {
wd, _ := os.Getwd()
pipe := DeserializePipelines([][]byte{[]byte(Payload)})[0]
storageProvider := storage.GetFileSystemStorageProvider("test", "..")
_, err := storageProvider.StoreExisting(Bucket, "source.jpg", filepath.Join(wd, "../tests/files/900x900.jpg"))
assert.Nil(t, err, "Test file should be readable")
assert.FileExists(t, storageProvider.GetPath(Bucket, "source.jpg"))
dest, err := pipe.Run("source.jpg", Bucket, storageProvider)
assert.Nil(t, err)
assert.FileExists(t, storageProvider.GetPath(Bucket, dest))
// clean up
os.Remove(storageProvider.GetPath(Bucket, "source.jpg"))
os.Remove(storageProvider.GetPath(Bucket, dest))
})
}

BIN
tests/files/900x900.jpg

After

Width: 900  |  Height: 900  |  Size: 75 KiB

Loading…
Cancel
Save