mirror of
				https://codeberg.org/forgejo/forgejo.git
				synced 2025-10-20 17:12:25 +00:00 
			
		
		
		
	minio/sha256-simd provides additional acceleration for SHA256 using AVX512, SHA Extensions for x86 and ARM64 for ARM. It provides a drop-in replacement for crypto/sha256 and if the extensions are not available it falls back to standard crypto/sha256. --------- Signed-off-by: Andrew Thornton <art27@cantab.net> Co-authored-by: John Olheiser <john.olheiser@gmail.com>
		
			
				
	
	
		
			141 lines
		
	
	
	
		
			3.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			141 lines
		
	
	
	
		
			3.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2021 The Gitea Authors. All rights reserved.
 | |
| // SPDX-License-Identifier: MIT
 | |
| 
 | |
| // Copied and modified from https://github.com/issue9/identicon/ (MIT License)
 | |
| // Generate pseudo-random avatars by IP, E-mail, etc.
 | |
| 
 | |
| package identicon
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"image"
 | |
| 	"image/color"
 | |
| 
 | |
| 	"github.com/minio/sha256-simd"
 | |
| )
 | |
| 
 | |
| const minImageSize = 16
 | |
| 
 | |
| // Identicon is used to generate pseudo-random avatars
 | |
| type Identicon struct {
 | |
| 	foreColors []color.Color
 | |
| 	backColor  color.Color
 | |
| 	size       int
 | |
| 	rect       image.Rectangle
 | |
| }
 | |
| 
 | |
| // New returns an Identicon struct with the correct settings
 | |
| // size image size
 | |
| // back background color
 | |
| // fore all possible foreground colors. only one foreground color will be picked randomly for one image
 | |
| func New(size int, back color.Color, fore ...color.Color) (*Identicon, error) {
 | |
| 	if len(fore) == 0 {
 | |
| 		return nil, fmt.Errorf("foreground is not set")
 | |
| 	}
 | |
| 
 | |
| 	if size < minImageSize {
 | |
| 		return nil, fmt.Errorf("size %d is smaller than min size %d", size, minImageSize)
 | |
| 	}
 | |
| 
 | |
| 	return &Identicon{
 | |
| 		foreColors: fore,
 | |
| 		backColor:  back,
 | |
| 		size:       size,
 | |
| 		rect:       image.Rect(0, 0, size, size),
 | |
| 	}, nil
 | |
| }
 | |
| 
 | |
| // Make generates an avatar by data
 | |
| func (i *Identicon) Make(data []byte) image.Image {
 | |
| 	h := sha256.New()
 | |
| 	h.Write(data)
 | |
| 	sum := h.Sum(nil)
 | |
| 
 | |
| 	b1 := int(sum[0]+sum[1]+sum[2]) % len(blocks)
 | |
| 	b2 := int(sum[3]+sum[4]+sum[5]) % len(blocks)
 | |
| 	c := int(sum[6]+sum[7]+sum[8]) % len(centerBlocks)
 | |
| 	b1Angle := int(sum[9]+sum[10]) % 4
 | |
| 	b2Angle := int(sum[11]+sum[12]) % 4
 | |
| 	foreColor := int(sum[11]+sum[12]+sum[15]) % len(i.foreColors)
 | |
| 
 | |
| 	return i.render(c, b1, b2, b1Angle, b2Angle, foreColor)
 | |
| }
 | |
| 
 | |
| func (i *Identicon) render(c, b1, b2, b1Angle, b2Angle, foreColor int) image.Image {
 | |
| 	p := image.NewPaletted(i.rect, []color.Color{i.backColor, i.foreColors[foreColor]})
 | |
| 	drawBlocks(p, i.size, centerBlocks[c], blocks[b1], blocks[b2], b1Angle, b2Angle)
 | |
| 	return p
 | |
| }
 | |
| 
 | |
| /*
 | |
| # Algorithm
 | |
| 
 | |
| Origin: An image is splitted into 9 areas
 | |
| 
 | |
| ```
 | |
|   -------------
 | |
|   | 1 | 2 | 3 |
 | |
|   -------------
 | |
|   | 4 | 5 | 6 |
 | |
|   -------------
 | |
|   | 7 | 8 | 9 |
 | |
|   -------------
 | |
| ```
 | |
| 
 | |
| Area 1/3/9/7 use a 90-degree rotating pattern.
 | |
| Area 1/3/9/7 use another 90-degree rotating pattern.
 | |
| Area 5 uses a random pattern.
 | |
| 
 | |
| The Patched Fix: make the image left-right mirrored to get rid of something like "swastika"
 | |
| */
 | |
| 
 | |
| // draw blocks to the paletted
 | |
| // c: the block drawer for the center block
 | |
| // b1,b2: the block drawers for other blocks (around the center block)
 | |
| // b1Angle,b2Angle: the angle for the rotation of b1/b2
 | |
| func drawBlocks(p *image.Paletted, size int, c, b1, b2 blockFunc, b1Angle, b2Angle int) {
 | |
| 	nextAngle := func(a int) int {
 | |
| 		return (a + 1) % 4
 | |
| 	}
 | |
| 
 | |
| 	padding := (size % 3) / 2 // in cased the size can not be aligned by 3 blocks.
 | |
| 
 | |
| 	blockSize := size / 3
 | |
| 	twoBlockSize := 2 * blockSize
 | |
| 
 | |
| 	// center
 | |
| 	c(p, blockSize+padding, blockSize+padding, blockSize, 0)
 | |
| 
 | |
| 	// left top (1)
 | |
| 	b1(p, 0+padding, 0+padding, blockSize, b1Angle)
 | |
| 	// center top (2)
 | |
| 	b2(p, blockSize+padding, 0+padding, blockSize, b2Angle)
 | |
| 
 | |
| 	b1Angle = nextAngle(b1Angle)
 | |
| 	b2Angle = nextAngle(b2Angle)
 | |
| 	// right top (3)
 | |
| 	// b1(p, twoBlockSize+padding, 0+padding, blockSize, b1Angle)
 | |
| 	// right middle (6)
 | |
| 	// b2(p, twoBlockSize+padding, blockSize+padding, blockSize, b2Angle)
 | |
| 
 | |
| 	b1Angle = nextAngle(b1Angle)
 | |
| 	b2Angle = nextAngle(b2Angle)
 | |
| 	// right bottom (9)
 | |
| 	// b1(p, twoBlockSize+padding, twoBlockSize+padding, blockSize, b1Angle)
 | |
| 	// center bottom (8)
 | |
| 	b2(p, blockSize+padding, twoBlockSize+padding, blockSize, b2Angle)
 | |
| 
 | |
| 	b1Angle = nextAngle(b1Angle)
 | |
| 	b2Angle = nextAngle(b2Angle)
 | |
| 	// lef bottom (7)
 | |
| 	b1(p, 0+padding, twoBlockSize+padding, blockSize, b1Angle)
 | |
| 	// left middle (4)
 | |
| 	b2(p, 0+padding, blockSize+padding, blockSize, b2Angle)
 | |
| 
 | |
| 	// then we make it left-right mirror, so we didn't draw 3/6/9 before
 | |
| 	for x := 0; x < size/2; x++ {
 | |
| 		for y := 0; y < size; y++ {
 | |
| 			p.SetColorIndex(size-x, y, p.ColorIndexAt(x, y))
 | |
| 		}
 | |
| 	}
 | |
| }
 |