This commit is contained in:
llgcode 2017-12-04 16:29:40 +01:00
parent 8167230c09
commit a5f7ac8ebe
4 changed files with 53 additions and 29 deletions

View File

@ -2,21 +2,29 @@ package draw2dbase
import "github.com/llgcode/draw2d" import "github.com/llgcode/draw2d"
var glyphCache map[string]map[rune]*Glyph // GlyphCache manage a map of glyphs
type GlyphCache struct {
glyphs map[string]map[rune]*Glyph
}
func init() {
glyphCache = make(map[string]map[rune]*Glyph) // NewGlyphCache initializes a GlyphCache
func NewGlyphCache() *GlyphCache {
glyphs := make(map[string]map[rune]*Glyph)
return &GlyphCache {
glyphs: glyphs,
}
} }
// FetchGlyph fetches a glyph from the cache, calling renderGlyph first if it doesn't already exist // FetchGlyph fetches a glyph from the cache, calling renderGlyph first if it doesn't already exist
func FetchGlyph(gc draw2d.GraphicContext, fontName string, chr rune) *Glyph { func (glyphCache *GlyphCache) FetchGlyph(gc draw2d.GraphicContext, fontName string, chr rune) *Glyph {
if glyphCache[fontName] == nil { if glyphCache.glyphs[fontName] == nil {
glyphCache[fontName] = make(map[rune]*Glyph, 60) glyphCache.glyphs[fontName] = make(map[rune]*Glyph, 60)
} }
if glyphCache[fontName][chr] == nil { if glyphCache.glyphs[fontName][chr] == nil {
glyphCache[fontName][chr] = renderGlyph(gc, fontName, chr) glyphCache.glyphs[fontName][chr] = renderGlyph(gc, fontName, chr)
} }
return glyphCache[fontName][chr].Copy() return glyphCache.glyphs[fontName][chr].Copy()
} }
// renderGlyph renders a glyph then caches and returns it // renderGlyph renders a glyph then caches and returns it
@ -40,6 +48,7 @@ type Glyph struct {
Width float64 Width float64
} }
// Returns a copy of a Glyph
func (g *Glyph) Copy() *Glyph { func (g *Glyph) Copy() *Glyph {
return &Glyph{ return &Glyph{
path: g.path.Copy(), path: g.path.Copy(),

View File

@ -4,7 +4,6 @@
package draw2dimg package draw2dimg
import ( import (
"errors"
"image" "image"
"image/color" "image/color"
"log" "log"
@ -35,6 +34,8 @@ type GraphicContext struct {
painter Painter painter Painter
fillRasterizer *raster.Rasterizer fillRasterizer *raster.Rasterizer
strokeRasterizer *raster.Rasterizer strokeRasterizer *raster.Rasterizer
FontCache draw2d.FontCache
glyphCache *draw2dbase.GlyphCache
glyphBuf *truetype.GlyphBuf glyphBuf *truetype.GlyphBuf
DPI int DPI int
} }
@ -74,6 +75,8 @@ func NewGraphicContextWithPainter(img draw.Image, painter Painter) *GraphicConte
painter, painter,
raster.NewRasterizer(width, height), raster.NewRasterizer(width, height),
raster.NewRasterizer(width, height), raster.NewRasterizer(width, height),
draw2d.GetGlobalFontCache(),
draw2dbase.NewGlyphCache(),
&truetype.GlyphBuf{}, &truetype.GlyphBuf{},
dpi, dpi,
} }
@ -136,7 +139,7 @@ func (gc *GraphicContext) FillStringAt(text string, x, y float64) (width float64
if hasPrev { if hasPrev {
x += fUnitsToFloat64(f.Kern(fixed.Int26_6(gc.Current.Scale), prev, index)) x += fUnitsToFloat64(f.Kern(fixed.Int26_6(gc.Current.Scale), prev, index))
} }
glyph := draw2dbase.FetchGlyph(gc, fontName, r) glyph := gc.glyphCache.FetchGlyph(gc, fontName, r)
x += glyph.Fill(gc, x, y) x += glyph.Fill(gc, x, y)
prev, hasPrev = index, true prev, hasPrev = index, true
} }
@ -163,7 +166,7 @@ func (gc *GraphicContext) StrokeStringAt(text string, x, y float64) (width float
if hasPrev { if hasPrev {
x += fUnitsToFloat64(f.Kern(fixed.Int26_6(gc.Current.Scale), prev, index)) x += fUnitsToFloat64(f.Kern(fixed.Int26_6(gc.Current.Scale), prev, index))
} }
glyph := draw2dbase.FetchGlyph(gc, fontName, r) glyph := gc.glyphCache.FetchGlyph(gc, fontName, r)
x += glyph.Stroke(gc, x, y) x += glyph.Stroke(gc, x, y)
prev, hasPrev = index, true prev, hasPrev = index, true
} }
@ -171,16 +174,15 @@ func (gc *GraphicContext) StrokeStringAt(text string, x, y float64) (width float
} }
func (gc *GraphicContext) loadCurrentFont() (*truetype.Font, error) { func (gc *GraphicContext) loadCurrentFont() (*truetype.Font, error) {
font := draw2d.GetFont(gc.Current.FontData) font, err := gc.FontCache.Load(gc.Current.FontData)
if font == nil { if err != nil {
font = draw2d.GetFont(draw2dbase.DefaultFontData) font, err = gc.FontCache.Load(draw2dbase.DefaultFontData)
} }
if font == nil { if font != nil {
return nil, errors.New("No font set, and no default font available.") gc.SetFont(font)
gc.SetFontSize(gc.Current.FontSize)
} }
gc.SetFont(font) return font, err
gc.SetFontSize(gc.Current.FontSize)
return font, nil
} }
// p is a truetype.Point measured in FUnits and positive Y going upwards. // p is a truetype.Point measured in FUnits and positive Y going upwards.

28
font.go
View File

@ -79,6 +79,10 @@ func GetFontFolder() string {
return defaultFonts.folder return defaultFonts.folder
} }
func GetGlobalFontCache() FontCache {
return defaultFonts
}
func SetFontFolder(folder string) { func SetFontFolder(folder string) {
defaultFonts.folder = filepath.Clean(folder) defaultFonts.folder = filepath.Clean(folder)
} }
@ -113,13 +117,24 @@ func SetFontCache(cache FontCache) {
} }
} }
type defaultFontCache struct { // FolderFontCache can Load font from folder
type FolderFontCache struct {
fonts map[string]*truetype.Font fonts map[string]*truetype.Font
folder string folder string
namer FontFileNamer namer FontFileNamer
} }
func (cache *defaultFontCache) Load(fontData FontData) (font *truetype.Font, err error) { // NewFolderFontCache creates FolderFontCache
func NewFolderFontCache(folder string) *FolderFontCache {
return &FolderFontCache{
fonts: make(map[string]*truetype.Font),
folder: folder,
namer: FontFileName,
}
}
// Load a font from cache if exists otherwise it will load the font from file
func (cache *FolderFontCache) Load(fontData FontData) (font *truetype.Font, err error) {
if font = cache.fonts[cache.namer(fontData)]; font != nil { if font = cache.fonts[cache.namer(fontData)]; font != nil {
return font, nil return font, nil
} }
@ -139,16 +154,13 @@ func (cache *defaultFontCache) Load(fontData FontData) (font *truetype.Font, err
return return
} }
func (cache *defaultFontCache) Store(fontData FontData, font *truetype.Font) { // Store a font to this cache
func (cache *FolderFontCache) Store(fontData FontData, font *truetype.Font) {
cache.fonts[cache.namer(fontData)] = font cache.fonts[cache.namer(fontData)] = font
} }
var ( var (
defaultFonts = &defaultFontCache{ defaultFonts = NewFolderFontCache("../resource/font")
fonts: make(map[string]*truetype.Font),
folder: "../resource/font",
namer: FontFileName,
}
fontCache FontCache = defaultFonts fontCache FontCache = defaultFonts
) )

View File

@ -2,6 +2,7 @@
package draw2d_test package draw2d_test
import ( import (
"fmt" "fmt"
"github.com/llgcode/draw2d" "github.com/llgcode/draw2d"
@ -25,10 +26,10 @@ func TestSync(t *testing.T) {
} }
func Draw(i int, ch chan<- int) { func Draw(i int, ch chan<- int) {
draw2d.SetFontFolder("./resource/font")
// Draw a rounded rectangle using default colors // Draw a rounded rectangle using default colors
dest := image.NewRGBA(image.Rect(0, 0, 297, 210.0)) dest := image.NewRGBA(image.Rect(0, 0, 297, 210.0))
gc := draw2dimg.NewGraphicContext(dest) gc := draw2dimg.NewGraphicContext(dest)
gc.FontCache = draw2d.NewFolderFontCache("./resource/font")
draw2dkit.RoundedRectangle(gc, 5, 5, 135, 95, 10, 10) draw2dkit.RoundedRectangle(gc, 5, 5, 135, 95, 10, 10)
gc.FillStroke() gc.FillStroke()