feat(misc): support vietnamese wheel beta text

This commit is contained in:
2026-07-06 14:28:54 +07:00
parent 0f4425fbc2
commit bb38eb3857
5 changed files with 120 additions and 9 deletions
@@ -0,0 +1,47 @@
DejaVu Sans font license
Source: https://dejavu-fonts.github.io/
Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved.
Bitstream Vera is a trademark of Bitstream, Inc.
DejaVu changes are in public domain.
Permission is hereby granted, free of charge, to any person obtaining a copy
of the fonts accompanying this license ("Fonts") and associated
documentation files (the "Font Software"), to reproduce and distribute the
Font Software, including without limitation the rights to use, copy, merge,
publish, distribute, and/or sell copies of the Font Software, and to permit
persons to whom the Font Software is furnished to do so, subject to the
following conditions:
The above copyright and trademark notices and this permission notice shall
be included in all copies of one or more of the Font Software typefaces.
The Font Software may be modified, altered, or added to, and in particular
the designs of glyphs or characters in the Fonts may be modified and
additional glyphs or characters may be added to the Fonts, only if the fonts
are renamed to names not containing either the words "Bitstream" or the word
"Vera".
This License becomes null and void to the extent applicable to Fonts or Font
Software that has been modified and distributed under the "Bitstream Vera"
names.
The Font Software may be sold as part of a larger software package but no
copy of one or more of the Font Software typefaces may be sold by itself.
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME
FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING
ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE
FONT SOFTWARE.
Except as contained in this notice, the names of Gnome, the Gnome
Foundation, and Bitstream Inc., shall not be used in advertising or
otherwise to promote the sale, use or other dealings in this Font Software
without prior written authorization from the Gnome Foundation or Bitstream
Inc., respectively.
Binary file not shown.
+26
View File
@@ -425,6 +425,32 @@ func TestWheelOfNamesBeta_RotatesOptionLabelsWithSlices(t *testing.T) {
}
}
func TestWheelOfNamesBeta_DisplayTextPreservesVietnamese(t *testing.T) {
input := "Tiếng Việt Đặng"
got := wheelBetaDisplayText(input, 32)
if got != input {
t.Fatalf("wheelBetaDisplayText() = %q, want %q", got, input)
}
if strings.Contains(got, "?") {
t.Fatalf("wheelBetaDisplayText() replaced Vietnamese with ?: %q", got)
}
}
func TestWheelOfNamesBeta_FontSupportsVietnameseGlyphs(t *testing.T) {
for _, r := range "Tiếng Việt Đặng Ơ Ư ấ ệ" {
if r == ' ' {
continue
}
glyphIndex, err := wheelBetaTextFont.GlyphIndex(nil, r)
if err != nil {
t.Fatalf("GlyphIndex(%q): %v", r, err)
}
if glyphIndex == 0 {
t.Fatalf("GlyphIndex(%q) = 0, want Vietnamese glyph support", r)
}
}
}
func countColorIndex(img *image.Paletted, bounds image.Rectangle, colorIndex byte) int {
bounds = bounds.Intersect(img.Bounds())
count := 0
+2 -2
View File
@@ -140,10 +140,10 @@ func renderWheelBetaFrameWithCelebration(options []string, winner int, rotation
if label == "" {
label = "CURRENT"
}
value := asciiWheelText(options[currentIndex], 28)
value := wheelBetaDisplayText(options[currentIndex], 28)
if reveal {
label = "RESULT"
value = asciiWheelText(options[winner], 28)
value = wheelBetaDisplayText(options[winner], 28)
}
drawStatusBand(img, label, value)
return img
@@ -1,20 +1,49 @@
package misc
import (
_ "embed"
"image"
"image/color"
"math"
"strings"
"unicode"
"golang.org/x/image/font"
"golang.org/x/image/font/basicfont"
"golang.org/x/image/font/opentype"
"golang.org/x/image/math/fixed"
)
const (
wheelBetaSliceLabelRadius = 64
wheelBetaFontSize = 10
wheelBetaFontDPI = 72
)
//go:embed fonts/dejavu-sans.ttf
var wheelBetaTextFontBytes []byte
var wheelBetaTextFont = mustWheelBetaTextFont()
func mustWheelBetaTextFont() *opentype.Font {
parsed, err := opentype.Parse(wheelBetaTextFontBytes)
if err != nil {
panic(err)
}
return parsed
}
func newWheelBetaTextFace() font.Face {
face, err := opentype.NewFace(wheelBetaTextFont, &opentype.FaceOptions{
Size: wheelBetaFontSize,
DPI: wheelBetaFontDPI,
Hinting: font.HintingFull,
})
if err != nil {
panic(err)
}
return face
}
func drawWheelSliceLabels(img *image.Paletted, options []string, rotation float64) {
if len(options) == 0 {
return
@@ -26,7 +55,7 @@ func drawWheelSliceLabels(img *image.Paletted, options []string, rotation float6
angle := rotation + (float64(idx)+0.5)*segment
centerX := cx + int(math.Round(math.Cos(angle)*float64(wheelBetaSliceLabelRadius)))
centerY := cy + int(math.Round(math.Sin(angle)*float64(wheelBetaSliceLabelRadius)))
text := asciiWheelText(option, limit)
text := wheelBetaDisplayText(option, limit)
drawRotatedCenteredTextAt(img, text, centerX+1, centerY+1, angle, wheelBetaPaperColorIndex)
drawRotatedCenteredTextAt(img, text, centerX, centerY, angle, wheelBetaInkColorIndex)
}
@@ -203,7 +232,10 @@ func drawCenteredText(img *image.Paletted, text string, baselineY int, colorInde
}
func drawCenteredTextAt(img *image.Paletted, text string, centerX, baselineY int, colorIndex byte) {
face := basicfont.Face7x13
face := newWheelBetaTextFace()
defer func() {
_ = face.Close()
}()
width := font.MeasureString(face, text).Ceil()
x := centerX - width/2
drawer := font.Drawer{
@@ -216,7 +248,10 @@ func drawCenteredTextAt(img *image.Paletted, text string, centerX, baselineY int
}
func drawRotatedCenteredTextAt(img *image.Paletted, text string, centerX, centerY int, angle float64, colorIndex byte) {
face := basicfont.Face7x13
face := newWheelBetaTextFace()
defer func() {
_ = face.Close()
}()
padding := 2
metrics := face.Metrics()
textWidth := font.MeasureString(face, text).Ceil()
@@ -247,17 +282,20 @@ func drawRotatedCenteredTextAt(img *image.Paletted, text string, centerX, center
}
}
func asciiWheelText(s string, limit int) string {
func wheelBetaDisplayText(s string, limit int) string {
var b strings.Builder
count := 0
for _, r := range s {
if b.Len() >= limit {
if count >= limit {
break
}
if r < 32 || r > 126 {
if unicode.IsControl(r) {
b.WriteByte('?')
count++
continue
}
b.WriteRune(r)
count++
}
out := strings.TrimSpace(b.String())
if out == "" {