code.gitea.io/gitea@v1.19.3/modules/avatar/avatar.go (about) 1 // Copyright 2014 The Gogs Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package avatar 5 6 import ( 7 "bytes" 8 "fmt" 9 "image" 10 "image/color" 11 12 _ "image/gif" // for processing gif images 13 _ "image/jpeg" // for processing jpeg images 14 _ "image/png" // for processing png images 15 16 "code.gitea.io/gitea/modules/avatar/identicon" 17 "code.gitea.io/gitea/modules/setting" 18 19 "github.com/nfnt/resize" 20 "github.com/oliamb/cutter" 21 ) 22 23 // AvatarSize returns avatar's size 24 const AvatarSize = 290 25 26 // RandomImageSize generates and returns a random avatar image unique to input data 27 // in custom size (height and width). 28 func RandomImageSize(size int, data []byte) (image.Image, error) { 29 // we use white as background, and use dark colors to draw blocks 30 imgMaker, err := identicon.New(size, color.White, identicon.DarkColors...) 31 if err != nil { 32 return nil, fmt.Errorf("identicon.New: %w", err) 33 } 34 return imgMaker.Make(data), nil 35 } 36 37 // RandomImage generates and returns a random avatar image unique to input data 38 // in default size (height and width). 39 func RandomImage(data []byte) (image.Image, error) { 40 return RandomImageSize(AvatarSize, data) 41 } 42 43 // Prepare accepts a byte slice as input, validates it contains an image of an 44 // acceptable format, and crops and resizes it appropriately. 45 func Prepare(data []byte) (*image.Image, error) { 46 imgCfg, _, err := image.DecodeConfig(bytes.NewReader(data)) 47 if err != nil { 48 return nil, fmt.Errorf("DecodeConfig: %w", err) 49 } 50 if imgCfg.Width > setting.Avatar.MaxWidth { 51 return nil, fmt.Errorf("Image width is too large: %d > %d", imgCfg.Width, setting.Avatar.MaxWidth) 52 } 53 if imgCfg.Height > setting.Avatar.MaxHeight { 54 return nil, fmt.Errorf("Image height is too large: %d > %d", imgCfg.Height, setting.Avatar.MaxHeight) 55 } 56 57 img, _, err := image.Decode(bytes.NewReader(data)) 58 if err != nil { 59 return nil, fmt.Errorf("Decode: %w", err) 60 } 61 62 if imgCfg.Width != imgCfg.Height { 63 var newSize, ax, ay int 64 if imgCfg.Width > imgCfg.Height { 65 newSize = imgCfg.Height 66 ax = (imgCfg.Width - imgCfg.Height) / 2 67 } else { 68 newSize = imgCfg.Width 69 ay = (imgCfg.Height - imgCfg.Width) / 2 70 } 71 72 img, err = cutter.Crop(img, cutter.Config{ 73 Width: newSize, 74 Height: newSize, 75 Anchor: image.Point{ax, ay}, 76 }) 77 if err != nil { 78 return nil, err 79 } 80 } 81 82 img = resize.Resize(AvatarSize, AvatarSize, img, resize.Bilinear) 83 return &img, nil 84 }