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>
This commit is contained in:
parent
5f05aa13e0
commit
df2557835b
13 changed files with 454 additions and 19 deletions
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
BIN
modules/avatar/testdata/avatar.jpeg
vendored
Normal file
BIN
modules/avatar/testdata/avatar.jpeg
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 521 B |
BIN
modules/avatar/testdata/avatar.png
vendored
Normal file
BIN
modules/avatar/testdata/avatar.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 159 B |
Loading…
Add table
Add a link
Reference in a new issue