diff options
author | Rob Watson <rfwatson@users.noreply.github.com> | 2019-05-25 13:46:14 +0200 |
---|---|---|
committer | Lauris BH <lauris@nix.lv> | 2019-05-25 14:46:14 +0300 |
commit | df2557835b2235b48d1ed979abb1a1d42607e96a (patch) | |
tree | 31ff762fc5c0023f7ddad6f7673b9a210e5021ed /modules | |
parent | 5f05aa13e00eb9f8098066c81d2cd916d91e9874 (diff) | |
download | gitea-df2557835b2235b48d1ed979abb1a1d42607e96a.tar.gz gitea-df2557835b2235b48d1ed979abb1a1d42607e96a.zip |
Improve handling of non-square avatars (#7025)
* Crop avatar before resizing (#1268)
Signed-off-by: Rob Watson <rfwatson@users.noreply.github.com>
* Fix spelling error
Signed-off-by: Rob Watson <rfwatson@users.noreply.github.com>
Diffstat (limited to 'modules')
-rw-r--r-- | modules/avatar/avatar.go | 50 | ||||
-rw-r--r-- | modules/avatar/avatar_test.go | 49 | ||||
-rw-r--r-- | modules/avatar/testdata/avatar.jpeg | bin | 0 -> 521 bytes | |||
-rw-r--r-- | modules/avatar/testdata/avatar.png | bin | 0 -> 159 bytes |
4 files changed, 99 insertions, 0 deletions
diff --git a/modules/avatar/avatar.go b/modules/avatar/avatar.go index f426978b32..cf3da6df5e 100644 --- a/modules/avatar/avatar.go +++ b/modules/avatar/avatar.go @@ -5,13 +5,20 @@ package avatar import ( + "bytes" "fmt" "image" "image/color/palette" + // Enable PNG support: + _ "image/png" "math/rand" "time" + "code.gitea.io/gitea/modules/setting" + "github.com/issue9/identicon" + "github.com/nfnt/resize" + "github.com/oliamb/cutter" ) // AvatarSize returns avatar's size @@ -42,3 +49,46 @@ func RandomImageSize(size int, data []byte) (image.Image, error) { func RandomImage(data []byte) (image.Image, error) { return RandomImageSize(AvatarSize, data) } + +// Prepare accepts a byte slice as input, validates it contains an image of an +// acceptable format, and crops and resizes it appropriately. +func Prepare(data []byte) (*image.Image, error) { + imgCfg, _, err := image.DecodeConfig(bytes.NewReader(data)) + if err != nil { + return nil, fmt.Errorf("DecodeConfig: %v", err) + } + if imgCfg.Width > setting.AvatarMaxWidth { + return nil, fmt.Errorf("Image width is too large: %d > %d", imgCfg.Width, setting.AvatarMaxWidth) + } + if imgCfg.Height > setting.AvatarMaxHeight { + return nil, fmt.Errorf("Image height is too large: %d > %d", imgCfg.Height, setting.AvatarMaxHeight) + } + + img, _, err := image.Decode(bytes.NewReader(data)) + if err != nil { + return nil, fmt.Errorf("Decode: %v", err) + } + + if imgCfg.Width != imgCfg.Height { + var newSize, ax, ay int + if imgCfg.Width > imgCfg.Height { + newSize = imgCfg.Height + ax = (imgCfg.Width - imgCfg.Height) / 2 + } else { + newSize = imgCfg.Width + ay = (imgCfg.Height - imgCfg.Width) / 2 + } + + img, err = cutter.Crop(img, cutter.Config{ + Width: newSize, + Height: newSize, + Anchor: image.Point{ax, ay}, + }) + if err != nil { + return nil, err + } + } + + img = resize.Resize(AvatarSize, AvatarSize, img, resize.NearestNeighbor) + return &img, nil +} diff --git a/modules/avatar/avatar_test.go b/modules/avatar/avatar_test.go index 9eff5bc2be..662d50fadd 100644 --- a/modules/avatar/avatar_test.go +++ b/modules/avatar/avatar_test.go @@ -5,8 +5,11 @@ package avatar import ( + "io/ioutil" "testing" + "code.gitea.io/gitea/modules/setting" + "github.com/stretchr/testify/assert" ) @@ -17,3 +20,49 @@ func Test_RandomImage(t *testing.T) { _, err = RandomImageSize(0, []byte("gogs@local")) assert.Error(t, err) } + +func Test_PrepareWithPNG(t *testing.T) { + setting.AvatarMaxWidth = 4096 + setting.AvatarMaxHeight = 4096 + + data, err := ioutil.ReadFile("testdata/avatar.png") + assert.NoError(t, err) + + imgPtr, err := Prepare(data) + assert.NoError(t, err) + + assert.Equal(t, 290, (*imgPtr).Bounds().Max.X) + assert.Equal(t, 290, (*imgPtr).Bounds().Max.Y) +} + +func Test_PrepareWithJPEG(t *testing.T) { + setting.AvatarMaxWidth = 4096 + setting.AvatarMaxHeight = 4096 + + data, err := ioutil.ReadFile("testdata/avatar.jpeg") + assert.NoError(t, err) + + imgPtr, err := Prepare(data) + assert.NoError(t, err) + + assert.Equal(t, 290, (*imgPtr).Bounds().Max.X) + assert.Equal(t, 290, (*imgPtr).Bounds().Max.Y) +} + +func Test_PrepareWithInvalidImage(t *testing.T) { + setting.AvatarMaxWidth = 5 + setting.AvatarMaxHeight = 5 + + _, err := Prepare([]byte{}) + assert.EqualError(t, err, "DecodeConfig: image: unknown format") +} +func Test_PrepareWithInvalidImageSize(t *testing.T) { + setting.AvatarMaxWidth = 5 + setting.AvatarMaxHeight = 5 + + data, err := ioutil.ReadFile("testdata/avatar.png") + assert.NoError(t, err) + + _, err = Prepare(data) + assert.EqualError(t, err, "Image width is too large: 10 > 5") +} diff --git a/modules/avatar/testdata/avatar.jpeg b/modules/avatar/testdata/avatar.jpeg Binary files differnew file mode 100644 index 0000000000..892b7baf78 --- /dev/null +++ b/modules/avatar/testdata/avatar.jpeg diff --git a/modules/avatar/testdata/avatar.png b/modules/avatar/testdata/avatar.png Binary files differnew file mode 100644 index 0000000000..c0f7922961 --- /dev/null +++ b/modules/avatar/testdata/avatar.png |