From 3115318f2577435400297a8b278e4b120a2f0acf Mon Sep 17 00:00:00 2001 From: Hamcha Date: Fri, 16 Nov 2018 11:46:10 +0100 Subject: [PATCH] Refactor to use emoji package --- emoji.go | 140 ---------------------------------------------------- freetype.go | 41 +++++++-------- 2 files changed, 17 insertions(+), 164 deletions(-) diff --git a/emoji.go b/emoji.go index acbb319..60f1ebb 100644 --- a/emoji.go +++ b/emoji.go @@ -1,13 +1,8 @@ package freetype import ( - "fmt" "image" "os" - "path/filepath" - "strconv" - "strings" - "unicode/utf8" _ "image/png" // Add PNG file loading support @@ -15,141 +10,6 @@ import ( "golang.org/x/image/math/fixed" ) -type emoji struct { - Codepoint []rune - IsEmoji bool - Path string - Sub emojiTable -} - -func (e emoji) String() (str string) { - str = "Emoji(" - for _, cprune := range e.Codepoint { - str += fmt.Sprintf("%U ", cprune) - } - str = strings.TrimRight(str, " ") + ")" - if e.Sub != nil { - str += "+" - } - if e.IsEmoji { - str += fmt.Sprintf("\n └ Path: %s", e.Path) - } - return str + "\n" -} - -func (e emoji) Length() int { - total := 0 - for _, r := range e.Codepoint { - total += utf8.RuneLen(r) - } - return total -} - -type emojiTable map[rune]emoji - -func (em emojiTable) Find(str string) *emoji { - for i, r := range str { - e, ok := em[r] - if !ok { - break - } - // Check if there are more bytes to check - if len(str) > i && e.Sub != nil { - rlen := utf8.RuneLen(r) - newemj := e.Sub.Find(str[i+rlen:]) - if newemj != nil { - return newemj - } - } - if e.IsEmoji { - return &e - } - } - return nil -} - -func (em emojiTable) IsEmoji(cp rune) bool { - _, ok := em[cp] - return ok -} - -func (em emojiTable) tostring(indent string, nomarker bool) (str string) { - counter := len(em) - marker := "│ " - if nomarker { - marker = " " - } - for r, emo := range em { - listr := "├" - if counter == 1 { - listr = "└" - } - str += fmt.Sprintf(indent+"%s%s %U", marker, listr, r) - if emo.IsEmoji { - str += fmt.Sprintf(": %s", emo.Path) - } - str += "\n" - if emo.Sub != nil { - str += emo.Sub.tostring(indent+marker, counter == 1) - } - counter-- - } - return -} - -func (em emojiTable) String() string { - return "Emoji table\n" + em.tostring("", true) -} - -func scanEmojiDirectory(emojipath string) (tab emojiTable, err error) { - tab = make(emojiTable) - filepath.Walk(emojipath, func(path string, info os.FileInfo, err error) error { - // Ignore non-images - if !strings.HasSuffix(strings.ToLower(path), ".png") { - return nil - } - - // Get icon filename - emojiname := filepath.Base(path) - - // Strip prefix and suffix - extsep := strings.LastIndexByte(emojiname, '.') - basesep := strings.IndexByte(emojiname, '_') - codepointstr := emojiname[basesep+2 : extsep] - - // Split codepoints by separator (_) - codepointlist := strings.Split(codepointstr, "_") - - // Parse codepoints to runes - curtab := &tab - codepoints := []rune{} - for cpi, cpstr := range codepointlist { - num, err := strconv.ParseInt(cpstr, 16, 32) - if err != nil { - return fmt.Errorf("malformed icon filename: %s (codepoints are not valid int32)", emojiname) - } - cprune := rune(num) - newemo := (*curtab)[cprune] - codepoints = append(codepoints, cprune) - newemo.Codepoint = codepoints[:] - if len(codepointlist) < cpi+2 { - // Set as emoji - newemo.IsEmoji = true - newemo.Path = path - } else { - // Add sub-entry if not existant - if newemo.Sub == nil { - newemo.Sub = make(emojiTable) - } - } - (*curtab)[cprune] = newemo - curtab = &newemo.Sub - } - return nil - }) - return tab, err -} - const emojiScale = fixed.Int26_6(100) func loadIconAtSize(path string, size fixed.Int26_6) (image.Image, error) { diff --git a/freetype.go b/freetype.go index 63e6877..4839305 100644 --- a/freetype.go +++ b/freetype.go @@ -13,6 +13,7 @@ import ( "image" "image/draw" + "git.fromouter.space/crunchy-rocks/emoji" "git.fromouter.space/crunchy-rocks/freetype/raster" "git.fromouter.space/crunchy-rocks/freetype/truetype" "golang.org/x/image/font" @@ -74,7 +75,7 @@ type Context struct { // cache is the glyph cache. cache [nGlyphs * nXFractions * nYFractions]cacheEntry // emojis is the table of all parsable emojis - emojis emojiTable + emojis emoji.Table } // PointToFixed converts the given number of points (as in "a 12 point font") @@ -234,31 +235,22 @@ func (c *Context) DrawString(s string, p fixed.Point26_6) (fixed.Point26_6, erro return fixed.Point26_6{}, errors.New("freetype: DrawText called with a nil font") } prev, hasPrev := truetype.Index(0), false - nextchar := 0 - for index, r := range s { - // Check if we need to skip entries - if nextchar > index { - continue - } + for fragment := range c.emojis.Iterate(s) { // Check if rune is an emoji - if c.emojis != nil && c.emojis.IsEmoji(r) { - icon := c.emojis.Find(s[index:]) - if icon != nil { - nextchar = index + icon.Length() - 1 - img, err := loadIconAtSize(icon.Path, c.scale) - h := emojiScale * c.scale / 90 - w := emojiScale * c.scale / 70 - if err == nil { - // Draw pic - ix, iy := int(p.X>>6), int((p.Y-h)>>6) - draw.Draw(c.dst, c.dst.Bounds(), img, image.Point{-ix, -iy}, draw.Over) - // Set some kerning variables - p.X += w - continue - } + if fragment.IsEmoji { + img, err := loadIconAtSize(fragment.Emoji.Path, c.scale) + h := emojiScale * c.scale / 90 + w := emojiScale * c.scale / 70 + if err == nil { + // Draw pic + ix, iy := int(p.X>>6), int((p.Y-h)>>6) + draw.Draw(c.dst, c.dst.Bounds(), img, image.Point{-ix, -iy}, draw.Over) + // Set some kerning variables + p.X += w + continue } } - index := c.f.Index(r) + index := c.f.Index(fragment.Rune) if hasPrev { kern := c.f.Kern(c.scale, prev, index) if c.hinting != font.HintingNone { @@ -362,11 +354,12 @@ func NewContext() *Context { fontSize: 12, dpi: 72, scale: 12 << 6, + emojis: make(emoji.Table), } } // ScanEmojis scans a directory for emojis and adds them to the context's emoji repertoire func (c *Context) ScanEmojis(path string) (err error) { - c.emojis, err = scanEmojiDirectory(path) + c.emojis, err = emoji.ScanEmojiDirectory(path) return }