diff --git a/font.go b/font.go index 516ae7c..7b23ce3 100644 --- a/font.go +++ b/font.go @@ -1,151 +1,35 @@ +// Explanation of the .flf file header +// THE HEADER LINE +// +// The header line gives information about the FIGfont. Here is an example +// showing the names of all parameters: +// +// flf2a$ 6 5 20 15 3 0 143 229 NOTE: The first five characters in +// | | | | | | | | | | the entire file must be "flf2a". +// / / | | | | | | | \ +// Signature / / | | | | | \ Codetag_Count +// Hardblank / / | | | \ Full_Layout* +// Height / | | \ Print_Direction +// Baseline / \ Comment_Lines +// Max_Length Old_Layout* +// +// * The two layout parameters are closely related and fairly complex. +// (See "INTERPRETATION OF LAYOUT PARAMETERS".) +// package figlet4go -import ( - "errors" - "io/ioutil" - "os" - "path/filepath" - "strconv" - "strings" -) - -const defaultFontName string = "standard" // Represents a single font type font struct { + // Hardblank symbol hardblank string + // Height of one char height int + // fontSlice []string } -// Holds the fonts -type fontManager struct { - // Font libraries - fontLib map[string]*font - // Font name to path - fontList map[string]string -} - -// Create new fontmanager -func newFontManager() *fontManager { - this := &fontManager{} - - this.fontLib = make(map[string]*font) - this.fontList = make(map[string]string) - this.loadBuildInFont() - - return this -} - -// Load all font *.flf files in the fontPath recursivly -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 - }) -} - -// Load the default font -func (this *fontManager) loadBuildInFont() error { - - // Default fonts to load - defaultFonts := []string{ - "standard", - "larry3d", - } - - // Load each default font - for _, name := range defaultFonts { - fontStr, err := Asset(name + ".flf") - if err != nil { - return err - } - font, err := this.parseFontContent(string(fontStr)) - if err != nil { - return err - } - this.fontLib[name] = font - } - - return nil -} - -// Load a font from disk -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 -} - -// Parse a font from a content string -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[0])-1:] - font.height, _ = strconv.Atoi(header[1]) - - commentEndLine, _ := strconv.Atoi(header[5]) - font.fontSlice = lines[commentEndLine+1:] - - return font, nil -} - -// Get a font by name -// Better error handling. Why is there one in the return if not used? -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[defaultFontName] - return font, nil - } - } - font, _ = this.fontLib[fontName] - return font, nil -} +func (f *font) getCharSlice() []string { + // TODO here will be the logic of NewAsciiChar + return []string{} +} \ No newline at end of file diff --git a/fontmanager.go b/fontmanager.go new file mode 100644 index 0000000..ba0ab82 --- /dev/null +++ b/fontmanager.go @@ -0,0 +1,165 @@ +package figlet4go + +import ( + "errors" + "io/ioutil" + "os" + "path/filepath" + "strconv" + "strings" +) + +// Default font if no other valid given +const defaultFont string = "standard" + +// Extension of a font file +const extension string = "flf" + +// Builtin fonts to load +var defaultFonts []string = []string{ + "standard", + "larry3d", +} + +// Holds the available fonts +type fontManager struct { + // The already read fonts + fontLib map[string]*font + // The in given pathes found fonts + fontList map[string]string +} + +// Create a new fontmanagerM +func newFontManager() *fontManager { + fm := &fontManager{} + fm.fontLib = make(map[string]*font) + fm.fontList = make(map[string]string) + fm.loadBuildInFont() + return fm +} + +// Get a font by name +// Default font if no other font could be loaded +func (fm *fontManager) getFont(fontName string) *font { + // Get the font from the fontLib + _, ok := fm.fontLib[fontName] + // Font not found + if !ok { + // Try to load it from loaded fontList + err := fm.loadDiskFont(fontName) + // Font also not found here, use the default font + if err != nil { + fontName = defaultFont + } + } + + return fm.fontLib[fontName] +} + + +// Loads all .flf files recursively in the fontPath path +// Saves the found font files in a map with the name as the key +// and the path as the value. Doesn't load them at this point +// for performance. Called in the AsciiRenderer +func (fm *fontManager) loadFontList(fontPath string) error { + // Walk through the path + return filepath.Walk(fontPath, func(path string, info os.FileInfo, err error) error { + // Return an error if occured + if err != nil { + return err + } + // If the current item is a directory or has not the correct suffix + if info.IsDir() || !strings.HasSuffix(info.Name(), "." + extension) { + return nil + } + // Extract the font name + fontName := strings.TrimSuffix(info.Name(), "." + extension) + // Save the font to the list + fm.fontList[fontName] = path + + return nil + }) +} + +// Load a font from disk +// The font must be registered in the fontList +func (this *fontManager) loadDiskFont(fontName string) error { + // Get the fontpath + path, ok := this.fontList[fontName] + // Font is not registered + if !ok { + return errors.New("Font Not Found: " + fontName) + } + + // Read file contents + fontStr, err := ioutil.ReadFile(path) + if err != nil { + return err + } + + // Parse the file contents + font, err := parseFontContent(string(fontStr)) + if err != nil { + return err + } + + // Register the font object in the fontLib + this.fontLib[fontName] = font + + return nil +} + +// Load the builtin fonts from the bindata.go file +// Load all fonts specified on top (defaultFonts) +func (fm *fontManager) loadBuildInFont() error { + + // Load each default font + for _, name := range defaultFonts { + // Get Contents + fontStr, err := Asset(name + "." + extension) + if err != nil { + return err + } + // Get the font + font, err := parseFontContent(string(fontStr)) + if err != nil { + return err + } + // Register the font object in the fontLib + fm.fontLib[name] = font + } + + return nil +} + + + +// Parse a font from a content string +// Used to load fonts from disk and the builtin fonts +func parseFontContent(cont string) (*font, error) { + // Get all lines + lines := strings.Split(cont, "\n") + + if len(lines) < 1 { + return nil, errors.New("Font content error") + } + + // Get the header metadata + header := strings.Split(lines[0], " ") + + // Line end of the comment + commentEndLine, _ := strconv.Atoi(header[5]) + + // Char height + height, _ := strconv.Atoi(header[1]) + + // Initialize the font + font := &font{ + hardblank: header[0][len(header[0])-1:], + height: height, + fontSlice: lines[commentEndLine+1:], + } + + return font, nil +} + diff --git a/render.go b/render.go index 222031a..65bae44 100644 --- a/render.go +++ b/render.go @@ -17,7 +17,7 @@ type RenderOptions struct { // Sets the default font name func NewRenderOptions() *RenderOptions { return &RenderOptions{ - FontName: defaultFontName, + FontName: defaultFont, } } @@ -36,7 +36,7 @@ func NewAsciiRender() *AsciiRender { // Loading all *.flf font files recursively in a path func (ar *AsciiRender) LoadFont(fontPath string) error { - return ar.fontMgr.loadFont(fontPath) + return ar.fontMgr.loadFontList(fontPath) } // Render a string with the default options @@ -53,11 +53,8 @@ func (ar *AsciiRender) RenderOpts(str string, opt *RenderOptions) (string, error colored := len(opt.FontColor) > 0 // Load the font - font, err := ar.fontMgr.getFont(opt.FontName) - if err != nil { - return "", err - } - + font := ar.fontMgr.getFont(opt.FontName) + // Slice holding the chars chars := []*AsciiChar{}