Files
motdGO/figlet/font.go
2014-10-15 23:53:21 +08:00

173 lines
3.6 KiB
Go

package figlet
import (
"errors"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
)
type Font struct {
Hardblank string
Height int
FontSlice []string
}
type FontManager struct {
// font library
fontLib map[string]*Font
// font name to path
fontList map[string]string
}
func NewFontManager() *FontManager {
this := &FontManager{}
this.fontLib = make(map[string]*Font)
this.fontList = make(map[string]string)
this.loadBuildInFont()
return this
}
// walk through the path, load all the *.flf font file
func (this *FontManager) LoadFont(fontPath string) error {
return filepath.Walk(fontPath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() || !strings.HasSuffix(info.Name(), ".flf") {
return nil
}
fontName := strings.TrimSuffix(info.Name(), ".flf")
this.fontList[fontName] = path
return nil
})
}
func (this *FontManager) loadBuildInFont() error {
font, err := this.parseFontContent(BuildInFont())
if err != nil {
return err
}
this.fontLib["default"] = font
return nil
}
func (this *FontManager) loadDiskFont(fontName string) error {
fontFilePath, ok := this.fontList[fontName]
if !ok {
return errors.New("FontName Not Found.")
}
// read full file content
fileBuf, err := ioutil.ReadFile(fontFilePath)
if err != nil {
return err
}
font, err := this.parseFontContent(string(fileBuf))
if err != nil {
return err
}
this.fontLib[fontName] = font
return nil
}
func (this *FontManager) parseFontContent(cont string) (*Font, error) {
lines := strings.Split(cont, "\n")
if len(lines) < 1 {
return nil, errors.New("font content error")
}
// flf2a$ 7 5 16 -1 12
// Fender by Scooter 8/94 (jkratten@law.georgetown.edu)
//
// Explanation of first line:
// flf2 - "magic number" for file identification
// a - should always be `a', for now
// $ - the "hardblank" -- prints as a blank, but can't be smushed
// 7 - height of a character
// 5 - height of a character, not including descenders
// 10 - max line length (excluding comment lines) + a fudge factor
// -1 - default smushmode for this font (like "-m 15" on command line)
// 12 - number of comment lines
header := strings.Split(lines[0], " ")
font := &Font{}
font.Hardblank = header[0][len(header)-1:]
font.Height, _ = strconv.Atoi(header[1])
commentEndLine, _ := strconv.Atoi(header[5])
font.FontSlice = lines[commentEndLine+1:]
return font, nil
}
func (this *FontManager) getFont(fontName string) (*Font, error) {
font, ok := this.fontLib[fontName]
if !ok {
err := this.loadDiskFont(fontName)
if err != nil {
font, _ := this.fontLib["default"]
return font, nil
}
}
font, _ = this.fontLib[fontName]
return font, nil
}
func (this *FontManager) convertChar(font *Font, char rune) ([]string, error) {
if char < 0 || char > 127 {
return nil, errors.New("Not Ascii")
}
height := font.Height
begintRow := (int(char) - 32) * height
word := make([]string, height, height)
for i := 0; i < height; i++ {
row := font.FontSlice[begintRow+i]
row = strings.Replace(row, "@", "", -1)
row = strings.Replace(row, font.Hardblank, " ", -1)
word[i] = row
}
return word, nil
}
func (this *FontManager) ConvertString(fontName, asciiStr string) (string, error) {
font, _ := this.getFont(fontName)
wordlist := make([][]string, 0)
for _, char := range asciiStr {
word, err := this.convertChar(font, char)
if err != nil {
return "", err
}
wordlist = append(wordlist, word)
}
result := ""
for i := 0; i < font.Height; i++ {
for j := 0; j < len(wordlist); j++ {
result += wordlist[j][i]
}
result += "\n"
}
return result, nil
}