Fonts
Fonts is a package that provides helpers to access font details, easily retrieve font bytes and proxy font requests.
This package has ZERO 3rd-party dependencies.
For now, Google Fonts is supported, but other fonts are planned.
Motivation
When working with images, PDFs or any other format that requires us to embed fonts, we can decide to download the fonts and embed them directly into our application.
However, if our application could use multiple different fonts which are decided at runtime, then there are a couple complications:
- There is no easy way to know what fonts are available and what variants they have. Google Fonts provides an API, but you can only receive a dump of all FONT details.
- It becomes tedious to download the font bytes during runtime, and manage caching.
This package helps to simplify this process
Reference
See https://pkg.go.dev/github.com/go-swiss/fonts
How to use
Proxy Google Font Requests
The Proxy()
function returns a http.Handler
that will proxy all requests to the Google Fonts server.
It takes a path, which is used when generating the urls of the font bytes
For example, if you want to proxy requests on example.com/fonts
:
http.Handle("/fonts", http.StripPrefix("/fonts", google.Proxy("/fonts")))
Get Font Details
To get the details of a Google Font, use the GetFontDetails
function:
package main
import (
"fmt"
"context"
"github.com/go-swiss/fonts/google"
)
func main() {
ctx := context.Background()
details, err := google.GetFontDetails(ctx, "Roboto")
if err != nil {
panic(err)
}
fmt.Printf("Family: %s\nVariants: %v", details.Family, details.Variants)
}
Family: Roboto
Variants: [100 100italic 300 300italic regular italic 500 500italic 700 700italic 900 900italic]
Get Font Bytes
To get the bytes
of a font, use the GetFontBytes
method. This will download the font bytes from the appropriate URL.
family := "Open Sans"
variant := "900"
fontBytes, err := google.GetFontBytes(ctx, family, variant, nil)
if errors.Is(err, fonts.ErrMissingVariant) {
fontBytes, err = google.GetFontBytes(ctx, family, "regular", nil)
}
if err != nil {
panic(err)
}
font, err := opentype.Parse(fontBytes)
if err != nil {
panic(err)
}
// Do something with the font
Caching Responses
In our application it is possible that we need to frequetnly get fonts. To reduce duplicate requests, a fonts.Cache
implementation can be passed as the 4th parameter to the GetFontBytes
function.
Here is an example using https://github.com/ReneKroon/ttlcache
package main
import (
"time"
"github.com/ReneKroon/ttlcache/v2"
)
type cache struct {
c *ttlcache.Cache
}
func (c cache) Get(key string) ([]byte, bool) {
fontInterface, err := c.c.Get(key)
if err != nil {
return nil, false
}
fontBytes, ok := fontInterface.([]byte)
return fontBytes, ok
}
func (c cache) Set(key string, val []byte) {
c.c.Set(key, val)
}
func main() {
c := ttlcache.NewCache()
c.SetTTL(time.Duration(20 * time.Second))
c.SetCacheSizeLimit(64)
fontBytes, err := google.GetFontBytes(config.Context, family, variant, cache{c})
if err != nil {
panic(err)
}
font, err := opentype.Parse(fontBytes)
if err != nil {
panic(err)
}
// Do something with the font
}
Contributing
Feature requests and Pull Requests are welcome!
If working locally, the google/all
directory can be refreshed by running go generate
. See generate/main.go
for details.