You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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