Skip to content

Commit bcf3513

Browse files
committed
Add custom font
Custom font could be used together with system font. This commit also adds pi.LoadFontData which could be used to load font from PNG file into another font instance.
1 parent 7c12b05 commit bcf3513

File tree

5 files changed

+71
-5
lines changed

5 files changed

+71
-5
lines changed

examples/print/main.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ var resources embed.FS
1212

1313
func main() {
1414
pi.Resources = resources
15+
pi.CustomFont.Width = 6 // set the width of all characters below 128 (ascii)
1516
pi.Draw = func() {
16-
pi.Print("HELLO,\nWORLD!", 50, 58, 9) // print two lines of yellow text using system font
17+
pi.Print("HELLO,\nMY NAME IS", 45, 58, 9) // print two lines of yellow text using system font
18+
pi.CustomFont.Print("PI\u0082", 45, 70, 12) // print blue text with special character using custom font
1719
}
1820
pi.MustRun()
1921
}

pi.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ func Boot() error {
117117
return err
118118
}
119119

120-
if err := loadFontData(systemFontPNG, systemFont.Data[:]); err != nil {
120+
if err := LoadFontData(systemFontPNG, systemFont.Data[:]); err != nil {
121121
return err
122122
}
123123

@@ -175,6 +175,10 @@ func loadResources(resources fs.ReadFileFS) error {
175175
return err
176176
}
177177

178+
if err := loadCustomFont(resources); err != nil {
179+
return err
180+
}
181+
178182
return nil
179183
}
180184

pi_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,18 @@ func TestBoot(t *testing.T) {
110110
assert.Equal(t, img.Palette, pi.Palette)
111111
})
112112

113+
t.Run("should load custom-font.png", func(t *testing.T) {
114+
pi.Reset()
115+
pi.Resources = fstest.MapFS{
116+
"custom-font.png": &fstest.MapFile{Data: customFontPng},
117+
}
118+
// when
119+
err := pi.Boot()
120+
// then
121+
require.NoError(t, err)
122+
assert.Equal(t, uint8(0xf), pi.CustomFont.Data[0])
123+
})
124+
113125
t.Run("should reset draw state", func(t *testing.T) {
114126
pi.Reset()
115127
require.NoError(t, pi.Boot())

print.go

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ package pi
66
import (
77
"bytes"
88
_ "embed"
9+
"errors"
910
"fmt"
11+
"io/fs"
1012

1113
"github.com/elgopher/pi/image"
1214
"github.com/elgopher/pi/internal/font"
@@ -18,6 +20,12 @@ var systemFont = Font{
1820
Height: 6,
1921
}
2022

23+
var CustomFont = Font{
24+
Width: 4,
25+
WidthSpecial: 8,
26+
Height: 6,
27+
}
28+
2129
//go:embed internal/system-font.png
2230
var systemFontPNG []byte
2331

@@ -96,15 +104,15 @@ func (f Font) printRune(r rune, sx, sy int, color byte) int {
96104
}
97105
}
98106

99-
// loadFontData loads font-sheet (png image) and converts
107+
// LoadFontData loads font-sheet (png image) and converts
100108
// it to font data. Image must be 128x128. Each char is 8x8.
101109
// Char 0 is in the top-left corner. Char 1 to the right.
102110
//
103111
// This function can be used if you want to use 3rd font:
104112
//
105113
// myFont := pi.Font{Width:4, WidthSpecial:8,Height: 8}
106-
// pi.loadFontData(png, myFont.Data[:])
107-
func loadFontData(png []byte, out []byte) error {
114+
// pi.LoadFontData(png, myFont.Data[:])
115+
func LoadFontData(png []byte, out []byte) error {
108116
img, err := image.DecodePNG(bytes.NewReader(png))
109117
if err != nil {
110118
return fmt.Errorf("decoding font failed: %w", err)
@@ -117,6 +125,19 @@ func loadFontData(png []byte, out []byte) error {
117125
return nil
118126
}
119127

128+
func loadCustomFont(resources fs.ReadFileFS) error {
129+
fileContents, err := resources.ReadFile("custom-font.png")
130+
if errors.Is(err, fs.ErrNotExist) {
131+
return nil
132+
}
133+
134+
if err != nil {
135+
return fmt.Errorf("error loading custom-font.png file: %w", err)
136+
}
137+
138+
return LoadFontData(fileContents, CustomFont.Data[:])
139+
}
140+
120141
// Print prints text on the screen using system font. It takes into consideration
121142
// clipping region and camera position.
122143
//

print_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,3 +145,30 @@ func assertScreenEqual(t *testing.T, file string) {
145145
fmt.Println("Screenshot taken", screenshot)
146146
}
147147
}
148+
149+
//go:embed internal/testimage/print/custom-font.png
150+
var customFontPng []byte
151+
152+
//go:embed internal/testimage/print/custom-font-too-small.png
153+
var customFontTooSmall []byte
154+
155+
func TestLoadFontData(t *testing.T) {
156+
t.Run("should return error when font png is invalid", func(t *testing.T) {
157+
font := pi.Font{}
158+
err := pi.LoadFontData(make([]byte, 0), font.Data[:])
159+
require.Error(t, err)
160+
})
161+
162+
t.Run("should return error when png is valid but too small", func(t *testing.T) {
163+
font := pi.Font{}
164+
err := pi.LoadFontData(customFontTooSmall, font.Data[:])
165+
require.Error(t, err)
166+
})
167+
168+
t.Run("should decode png file into font data", func(t *testing.T) {
169+
font := pi.Font{}
170+
err := pi.LoadFontData(customFontPng, font.Data[:])
171+
require.NoError(t, err)
172+
assert.Equal(t, byte(0b00001111), font.Data[0])
173+
})
174+
}

0 commit comments

Comments
 (0)