275 lines
5.9 KiB
Go
275 lines
5.9 KiB
Go
// d2fonts holds fonts for renderings
|
|
|
|
// TODO write a script to do this as part of CI
|
|
// Currently using an online converter: https://dopiaza.org/tools/datauri/index.php
|
|
package d2fonts
|
|
|
|
import (
|
|
"embed"
|
|
"encoding/base64"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
fontlib "oss.terrastruct.com/d2/lib/font"
|
|
)
|
|
|
|
type FontFamily string
|
|
type FontStyle string
|
|
|
|
type Font struct {
|
|
Family FontFamily
|
|
Style FontStyle
|
|
Size int
|
|
}
|
|
|
|
func (f FontFamily) Font(size int, style FontStyle) Font {
|
|
return Font{
|
|
Family: f,
|
|
Style: style,
|
|
Size: size,
|
|
}
|
|
}
|
|
|
|
func (f Font) GetEncodedSubset(cutSet string) string {
|
|
fontString, err := fontlib.Subset(FontFaces[f], cutSet)
|
|
if err != nil {
|
|
// If subset fails, return full encoding
|
|
fontString = FontEncodings[f]
|
|
}
|
|
return fontString
|
|
}
|
|
|
|
const (
|
|
FONT_SIZE_XS = 13
|
|
FONT_SIZE_S = 14
|
|
FONT_SIZE_M = 16
|
|
FONT_SIZE_L = 20
|
|
FONT_SIZE_XL = 24
|
|
FONT_SIZE_XXL = 28
|
|
FONT_SIZE_XXXL = 32
|
|
|
|
FONT_STYLE_REGULAR FontStyle = "regular"
|
|
FONT_STYLE_BOLD FontStyle = "bold"
|
|
FONT_STYLE_ITALIC FontStyle = "italic"
|
|
|
|
SourceSansPro FontFamily = "SourceSansPro"
|
|
SourceCodePro FontFamily = "SourceCodePro"
|
|
HandDrawn FontFamily = "HandDrawn"
|
|
)
|
|
|
|
var FontSizes = []int{
|
|
FONT_SIZE_XS,
|
|
FONT_SIZE_S,
|
|
FONT_SIZE_M,
|
|
FONT_SIZE_L,
|
|
FONT_SIZE_XL,
|
|
FONT_SIZE_XXL,
|
|
FONT_SIZE_XXXL,
|
|
}
|
|
|
|
var FontStyles = []FontStyle{
|
|
FONT_STYLE_REGULAR,
|
|
FONT_STYLE_BOLD,
|
|
FONT_STYLE_ITALIC,
|
|
}
|
|
|
|
var FontFamilies = []FontFamily{
|
|
SourceSansPro,
|
|
SourceCodePro,
|
|
HandDrawn,
|
|
}
|
|
|
|
//go:embed encoded/SourceSansPro-Regular.txt
|
|
var sourceSansProRegularBase64 string
|
|
|
|
//go:embed encoded/SourceSansPro-Bold.txt
|
|
var sourceSansProBoldBase64 string
|
|
|
|
//go:embed encoded/SourceSansPro-Italic.txt
|
|
var sourceSansProItalicBase64 string
|
|
|
|
//go:embed encoded/SourceCodePro-Regular.txt
|
|
var sourceCodeProRegularBase64 string
|
|
|
|
//go:embed encoded/SourceCodePro-Bold.txt
|
|
var sourceCodeProBoldBase64 string
|
|
|
|
//go:embed encoded/SourceCodePro-Italic.txt
|
|
var sourceCodeProItalicBase64 string
|
|
|
|
//go:embed encoded/ArchitectsDaughter-Regular.txt
|
|
var architectsDaughterRegularBase64 string
|
|
|
|
//go:embed encoded/FuzzyBubbles-Bold.txt
|
|
var fuzzyBubblesBoldBase64 string
|
|
|
|
//go:embed ttf/*
|
|
var fontFacesFS embed.FS
|
|
|
|
var FontEncodings map[Font]string
|
|
var FontFaces map[Font][]byte
|
|
|
|
func init() {
|
|
FontEncodings = map[Font]string{
|
|
{
|
|
Family: SourceSansPro,
|
|
Style: FONT_STYLE_REGULAR,
|
|
}: sourceSansProRegularBase64,
|
|
{
|
|
Family: SourceSansPro,
|
|
Style: FONT_STYLE_BOLD,
|
|
}: sourceSansProBoldBase64,
|
|
{
|
|
Family: SourceSansPro,
|
|
Style: FONT_STYLE_ITALIC,
|
|
}: sourceSansProItalicBase64,
|
|
{
|
|
Family: SourceCodePro,
|
|
Style: FONT_STYLE_REGULAR,
|
|
}: sourceCodeProRegularBase64,
|
|
{
|
|
Family: SourceCodePro,
|
|
Style: FONT_STYLE_BOLD,
|
|
}: sourceCodeProBoldBase64,
|
|
{
|
|
Family: SourceCodePro,
|
|
Style: FONT_STYLE_ITALIC,
|
|
}: sourceCodeProItalicBase64,
|
|
{
|
|
Family: HandDrawn,
|
|
Style: FONT_STYLE_REGULAR,
|
|
}: architectsDaughterRegularBase64,
|
|
{
|
|
Family: HandDrawn,
|
|
Style: FONT_STYLE_ITALIC,
|
|
// This font has no italic, so just reuse regular
|
|
}: architectsDaughterRegularBase64,
|
|
{
|
|
Family: HandDrawn,
|
|
Style: FONT_STYLE_BOLD,
|
|
}: fuzzyBubblesBoldBase64,
|
|
}
|
|
|
|
for k, v := range FontEncodings {
|
|
FontEncodings[k] = strings.TrimSuffix(v, "\n")
|
|
}
|
|
|
|
FontFaces = map[Font][]byte{}
|
|
b, err := fontFacesFS.ReadFile("ttf/SourceSansPro-Regular.ttf")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
FontFaces[Font{
|
|
Family: SourceSansPro,
|
|
Style: FONT_STYLE_REGULAR,
|
|
}] = b
|
|
b, err = fontFacesFS.ReadFile("ttf/SourceCodePro-Regular.ttf")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
FontFaces[Font{
|
|
Family: SourceCodePro,
|
|
Style: FONT_STYLE_REGULAR,
|
|
}] = b
|
|
b, err = fontFacesFS.ReadFile("ttf/SourceCodePro-Bold.ttf")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
FontFaces[Font{
|
|
Family: SourceCodePro,
|
|
Style: FONT_STYLE_BOLD,
|
|
}] = b
|
|
b, err = fontFacesFS.ReadFile("ttf/SourceCodePro-Italic.ttf")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
FontFaces[Font{
|
|
Family: SourceCodePro,
|
|
Style: FONT_STYLE_ITALIC,
|
|
}] = b
|
|
b, err = fontFacesFS.ReadFile("ttf/SourceSansPro-Bold.ttf")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
FontFaces[Font{
|
|
Family: SourceSansPro,
|
|
Style: FONT_STYLE_BOLD,
|
|
}] = b
|
|
b, err = fontFacesFS.ReadFile("ttf/SourceSansPro-Italic.ttf")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
FontFaces[Font{
|
|
Family: SourceSansPro,
|
|
Style: FONT_STYLE_ITALIC,
|
|
}] = b
|
|
b, err = fontFacesFS.ReadFile("ttf/ArchitectsDaughter-Regular.ttf")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
FontFaces[Font{
|
|
Family: HandDrawn,
|
|
Style: FONT_STYLE_REGULAR,
|
|
}] = b
|
|
FontFaces[Font{
|
|
Family: HandDrawn,
|
|
Style: FONT_STYLE_ITALIC,
|
|
}] = b
|
|
b, err = fontFacesFS.ReadFile("ttf/FuzzyBubbles-Bold.ttf")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
FontFaces[Font{
|
|
Family: HandDrawn,
|
|
Style: FONT_STYLE_BOLD,
|
|
}] = b
|
|
}
|
|
|
|
func AddFont(fontLoc string) (FontFamily, error) {
|
|
if fontLoc == "" {
|
|
return "", nil
|
|
}
|
|
fontFileName := filepath.Base(fontLoc)
|
|
|
|
ext := filepath.Ext(fontFileName)
|
|
if ext != ".ttf" {
|
|
return "", fmt.Errorf("cannot open non .ttf fonts")
|
|
}
|
|
|
|
fontBuf, err := os.ReadFile(fontLoc)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to read font at location %v", err)
|
|
}
|
|
|
|
fontName := strings.TrimSuffix(fontFileName, ext)
|
|
fontFamily := FontFamily(fontName)
|
|
woffFont, err := fontlib.Sfnt2Woff(fontBuf)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to convert to woff font: %v", err)
|
|
}
|
|
|
|
encodedWoff := fmt.Sprintf("data:application/font-woff;base64,%v", base64.StdEncoding.EncodeToString(woffFont))
|
|
|
|
// Encode all styles for now
|
|
customFont := fontFamily.Font(0, FONT_STYLE_REGULAR)
|
|
FontFaces[customFont] = fontBuf
|
|
FontEncodings[customFont] = encodedWoff
|
|
|
|
customFont = fontFamily.Font(0, FONT_STYLE_BOLD)
|
|
FontFaces[customFont] = fontBuf
|
|
FontEncodings[customFont] = encodedWoff
|
|
|
|
customFont = fontFamily.Font(0, FONT_STYLE_ITALIC)
|
|
FontFaces[customFont] = fontBuf
|
|
FontEncodings[customFont] = encodedWoff
|
|
|
|
FontFamilies = append(FontFamilies, fontFamily)
|
|
return fontFamily, nil
|
|
}
|
|
|
|
var D2_FONT_TO_FAMILY = map[string]FontFamily{
|
|
"default": SourceSansPro,
|
|
"mono": SourceCodePro,
|
|
}
|