mirror of
https://github.com/gitbucket/gitbucket.git
synced 2026-01-05 23:30:02 +01:00
Different style of avatar for groups.
This commit is contained in:
@@ -156,7 +156,11 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
RawData(FileUtil.getMimeType(image), new java.io.File(getUserUploadDir(userName), image))
|
||||
}.getOrElse{
|
||||
contentType = "image/png"
|
||||
TextAvatarUtil.textAvatar(account.fullName).getOrElse(Thread.currentThread.getContextClassLoader.getResourceAsStream("noimage.png"))
|
||||
(if (account.isGroupAccount) {
|
||||
TextAvatarUtil.textGroupAvatar(account.fullName)
|
||||
} else {
|
||||
TextAvatarUtil.textAvatar(account.fullName)
|
||||
}).getOrElse(Thread.currentThread.getContextClassLoader.getResourceAsStream("noimage.png"))
|
||||
}
|
||||
}.getOrElse{
|
||||
NotFound()
|
||||
|
||||
@@ -3,10 +3,22 @@ package gitbucket.core.util
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.awt.image.BufferedImage
|
||||
import javax.imageio.ImageIO
|
||||
import java.awt.{Color, Font, RenderingHints}
|
||||
import java.awt.{Color, Font, Graphics2D, RenderingHints}
|
||||
import java.awt.font.{FontRenderContext, TextLayout}
|
||||
import java.awt.geom.AffineTransform
|
||||
|
||||
|
||||
object TextAvatarUtil {
|
||||
private val iconSize = 200
|
||||
private val fontSize = 180
|
||||
private val roundSize = 60
|
||||
private val shadowSize = 20
|
||||
private val bgSaturation = 0.68f
|
||||
private val bgBlightness = 0.73f
|
||||
private val shadowBlightness = 0.23f
|
||||
private val font = new Font(Font.SANS_SERIF, Font.PLAIN, fontSize)
|
||||
private val transparent = new Color(0, 0, 0, 0)
|
||||
|
||||
// https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
|
||||
private def relativeLuminance(c: Color): Double = {
|
||||
val rgb = Seq(c.getRed, c.getGreen, c.getBlue).map{_/255.0}.map{x => if (x <= 0.03928) x / 12.92 else math.pow((x + 0.055) / 1.055, 2.4)}
|
||||
@@ -24,27 +36,37 @@ object TextAvatarUtil {
|
||||
if (contrastRatio(base, c1) > contrastRatio(base, c2)) c1 else c2
|
||||
}
|
||||
|
||||
private def textImage(w: Int, h: Int, drawText: String, font: Font, fontSize: Int, bgColor: Color, fgColor: Color): Array[Byte] = {
|
||||
val canvas = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB)
|
||||
val g = canvas.createGraphics()
|
||||
private def strToHue(text: String): Float = {
|
||||
Integer.parseInt(StringUtil.md5(text).substring(0, 2), 16) / 256f
|
||||
}
|
||||
|
||||
g.setColor(new Color(0, 0, 0, 0))
|
||||
g.fillRect(0, 0, w, h)
|
||||
g.setColor(bgColor)
|
||||
g.fillRoundRect(0, 0, w, h, 60, 60)
|
||||
|
||||
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
|
||||
|
||||
g.setColor(fgColor)
|
||||
val context = g.getFontRenderContext
|
||||
private def getCenterToDraw(drawText: String, font: Font, w: Int, h: Int): (Int, Int) = {
|
||||
val context = new FontRenderContext(new AffineTransform(), true, true)
|
||||
val txt = new TextLayout(drawText, font, context)
|
||||
|
||||
val bounds = txt.getBounds
|
||||
|
||||
val x: Int = ((w - bounds.getWidth) / 2 - bounds.getX).toInt
|
||||
val y: Int = ((h - bounds.getHeight) / 2 - bounds.getY).toInt
|
||||
(x, y)
|
||||
}
|
||||
|
||||
private def textImage(drawText: String, bgColor: Color, fgColor: Color): Array[Byte] = {
|
||||
val canvas = new BufferedImage(iconSize, iconSize, BufferedImage.TYPE_INT_ARGB)
|
||||
val g = canvas.createGraphics()
|
||||
val center = getCenterToDraw(drawText, font, iconSize, iconSize)
|
||||
|
||||
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
|
||||
|
||||
g.setColor(transparent)
|
||||
g.fillRect(0, 0, iconSize, iconSize)
|
||||
|
||||
g.setColor(bgColor)
|
||||
g.fillRoundRect(0, 0, iconSize, iconSize, roundSize, roundSize)
|
||||
|
||||
g.setColor(fgColor)
|
||||
g.setFont(font)
|
||||
g.drawString(drawText, x, y)
|
||||
g.drawString(drawText, center._1, center._2)
|
||||
|
||||
g.dispose()
|
||||
|
||||
@@ -55,18 +77,51 @@ object TextAvatarUtil {
|
||||
|
||||
def textAvatar(nameText: String): Option[Array[Byte]] = {
|
||||
val drawText = nameText.substring(0, 1)
|
||||
val md5 = StringUtil.md5(nameText)
|
||||
val hashedInt = Integer.parseInt(md5.substring(0, 2), 16)
|
||||
|
||||
val bgHue = hashedInt / 256f
|
||||
val bgSaturation = 0.68f
|
||||
val bgBlightness = 0.73f
|
||||
val bgHue = strToHue(nameText)
|
||||
val bgColor = Color.getHSBColor(bgHue, bgSaturation, bgBlightness)
|
||||
val fgColor = goodContrastColor(bgColor, Color.BLACK, Color.WHITE)
|
||||
|
||||
val size = (200, 200)
|
||||
val fontSize = 180
|
||||
val font = new Font(Font.SANS_SERIF, Font.PLAIN, fontSize)
|
||||
if (font.canDisplayUpTo(drawText) == -1) Some(textImage(size._1, size._2, drawText, font, fontSize, bgColor, fgColor)) else None
|
||||
if (font.canDisplayUpTo(drawText) == -1) Some(textImage(drawText, bgColor, fgColor)) else None
|
||||
}
|
||||
|
||||
private def textGroupImage(drawText: String, bgColor: Color, fgColor: Color, shadowColor: Color): Array[Byte] = {
|
||||
val canvas = new BufferedImage(iconSize, iconSize, BufferedImage.TYPE_INT_ARGB)
|
||||
val g = canvas.createGraphics()
|
||||
val center = getCenterToDraw(drawText, font, iconSize - shadowSize, iconSize - shadowSize)
|
||||
|
||||
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
|
||||
|
||||
g.setColor(transparent)
|
||||
g.fillRect(0, 0, iconSize, iconSize)
|
||||
|
||||
g.setColor(shadowColor)
|
||||
g.fillRect(shadowSize, shadowSize, iconSize, iconSize)
|
||||
|
||||
g.setColor(bgColor)
|
||||
g.fillRect(0, 0, iconSize - shadowSize, iconSize - shadowSize)
|
||||
|
||||
g.setColor(fgColor)
|
||||
|
||||
g.setFont(font)
|
||||
g.drawString(drawText, center._1, center._2)
|
||||
|
||||
g.dispose()
|
||||
|
||||
val stream = new ByteArrayOutputStream
|
||||
ImageIO.write(canvas, "png", stream)
|
||||
stream.toByteArray
|
||||
}
|
||||
|
||||
def textGroupAvatar(nameText: String): Option[Array[Byte]] = {
|
||||
val drawText = nameText.substring(0, 1)
|
||||
|
||||
val bgHue = strToHue(nameText)
|
||||
val bgColor = Color.getHSBColor(bgHue, bgSaturation, bgBlightness)
|
||||
val fgColor = goodContrastColor(bgColor, Color.BLACK, Color.WHITE)
|
||||
val shadowColor = Color.getHSBColor(bgHue, bgSaturation, shadowBlightness)
|
||||
|
||||
if (font.canDisplayUpTo(drawText) == -1) Some(textGroupImage(drawText, bgColor, fgColor, shadowColor)) else None
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user