github.com/gitbundle/modules@v0.0.0-20231025071548-85b91c5c3b01/avatar/avatar.go (about)

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