summaryrefslogtreecommitdiffstats
path: root/modules
diff options
context:
space:
mode:
authorRob Watson <rfwatson@users.noreply.github.com>2019-05-25 13:46:14 +0200
committerLauris BH <lauris@nix.lv>2019-05-25 14:46:14 +0300
commitdf2557835b2235b48d1ed979abb1a1d42607e96a (patch)
tree31ff762fc5c0023f7ddad6f7673b9a210e5021ed /modules
parent5f05aa13e00eb9f8098066c81d2cd916d91e9874 (diff)
downloadgitea-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.go50
-rw-r--r--modules/avatar/avatar_test.go49
-rw-r--r--modules/avatar/testdata/avatar.jpegbin0 -> 521 bytes
-rw-r--r--modules/avatar/testdata/avatar.pngbin0 -> 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
new file mode 100644
index 0000000000..892b7baf78
--- /dev/null
+++ b/modules/avatar/testdata/avatar.jpeg
Binary files differ
diff --git a/modules/avatar/testdata/avatar.png b/modules/avatar/testdata/avatar.png
new file mode 100644
index 0000000000..c0f7922961
--- /dev/null
+++ b/modules/avatar/testdata/avatar.png
Binary files differ