Compare commits
2 commits
e2365dfdc4
...
752f9e4be4
Author | SHA1 | Date | |
---|---|---|---|
752f9e4be4 | |||
1d07a50459 |
15 changed files with 232 additions and 16 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
noto_emojis
|
||||
example/emojis/out.png
|
76
emoji.go
Normal file
76
emoji.go
Normal file
|
@ -0,0 +1,76 @@
|
|||
package freetype
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
type Emoji struct {
|
||||
Codepoints []rune
|
||||
Bytes int
|
||||
}
|
||||
|
||||
var (
|
||||
errNotAnEmoji = errors.New("not an emoji")
|
||||
)
|
||||
|
||||
func inrange(val, min, max rune) bool {
|
||||
return val >= min && val < max
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/questions/30757193/find-out-if-character-in-string-is-emoji/39425959
|
||||
func isEmoji(chr rune) bool {
|
||||
switch {
|
||||
case inrange(chr, 0x1f600, 0x1f64f), // Emoticons
|
||||
inrange(chr, 0x1f300, 0x1f5ff), // Misc Symbols and Pictographs
|
||||
inrange(chr, 0x1f680, 0x1f6ff), // Transport and Map
|
||||
inrange(chr, 0x1f1e6, 0x1f1ff), // Regional country flags
|
||||
inrange(chr, 0x2600, 0x26ff), // Misc symbols
|
||||
inrange(chr, 0x2700, 0x27bf), // Dingbats
|
||||
inrange(chr, 0xfe00, 0xfe0f), // Variation Selectors
|
||||
inrange(chr, 0x1f900, 0x1f9ff), // Supplemental Symbols and Pictographs
|
||||
inrange(chr, 127000, 127600), // Various asian characters
|
||||
inrange(chr, 65024, 65039), // Variation selector
|
||||
inrange(chr, 9100, 9300), // Misc items
|
||||
inrange(chr, 8400, 8447): // Combining Diacritical Marks for Symbols
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isZWJ(chr rune) bool {
|
||||
return chr == 8205
|
||||
}
|
||||
|
||||
func parseEmoji(str string) (Emoji, error) {
|
||||
if len(str) < 1 {
|
||||
return Emoji{}, errNotAnEmoji
|
||||
}
|
||||
|
||||
emoji := Emoji{}
|
||||
|
||||
for _, r := range str {
|
||||
// Check if rune is emoji
|
||||
if !isEmoji(r) && !isZWJ(r) {
|
||||
if len(emoji.Codepoints) < 1 {
|
||||
return emoji, errNotAnEmoji
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
emoji.Codepoints = append(emoji.Codepoints, r)
|
||||
emoji.Bytes += utf8.RuneLen(r)
|
||||
}
|
||||
|
||||
return emoji, nil
|
||||
}
|
||||
|
||||
func (e Emoji) String() string {
|
||||
codepoints := []string{}
|
||||
for _, cp := range e.Codepoints {
|
||||
codepoints = append(codepoints, fmt.Sprintf("%U", cp))
|
||||
}
|
||||
return "Emoji(" + strings.Join(codepoints, ", ") + ")"
|
||||
}
|
|
@ -21,7 +21,7 @@ import (
|
|||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/golang/freetype/raster"
|
||||
"git.fromouter.space/crunchy-rocks/freetype/raster"
|
||||
"golang.org/x/image/math/fixed"
|
||||
)
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ import (
|
|||
"math"
|
||||
"os"
|
||||
|
||||
"github.com/golang/freetype/truetype"
|
||||
"git.fromouter.space/crunchy-rocks/freetype/truetype"
|
||||
"golang.org/x/image/font"
|
||||
"golang.org/x/image/math/fixed"
|
||||
)
|
||||
|
|
124
example/emojis/main.go
Normal file
124
example/emojis/main.go
Normal file
|
@ -0,0 +1,124 @@
|
|||
// Copyright 2010 The Freetype-Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by your choice of either the
|
||||
// FreeType License or the GNU General Public License version 2 (or
|
||||
// any later version), both of which can be found in the LICENSE file.
|
||||
|
||||
// +build example
|
||||
//
|
||||
// This build tag means that "go install github.com/golang/freetype/..."
|
||||
// doesn't install this example program. Use "go run main.go" to run it or "go
|
||||
// install -tags=example" to install it.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"flag"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
"image/png"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"git.fromouter.space/crunchy-rocks/freetype"
|
||||
"golang.org/x/image/font"
|
||||
)
|
||||
|
||||
var (
|
||||
dpi = flag.Float64("dpi", 72, "screen resolution in Dots Per Inch")
|
||||
fontfile = flag.String("fontfile", "../../testdata/luxisr.ttf", "filename of the ttf font")
|
||||
hinting = flag.String("hinting", "none", "none | full")
|
||||
size = flag.Float64("size", 20, "font size in points")
|
||||
spacing = flag.Float64("spacing", 1.5, "line spacing (e.g. 2 means double spaced)")
|
||||
wonb = flag.Bool("whiteonblack", false, "white text on a black background")
|
||||
)
|
||||
|
||||
var text = []string{
|
||||
"Single glyph emoji: 😂",
|
||||
"Gender-modified emoji: 💂♀️",
|
||||
"Skin-modified emoji: 🖐🏽",
|
||||
"Mixed emoji: 👩👩👧👧",
|
||||
"👌👀👌👀👌👀👌👀👌👀 good shit go౦ԁ sHit👌 thats ✔ some good👌👌shit right👌👌",
|
||||
"th 👌 ere👌👌👌 right✔there ✔✔if i do ƽaү so my self 💯 i say so ",
|
||||
"💯 thats what im talking about right there right there (chorus: ʳᶦᵍʰᵗ ᵗʰᵉʳᵉ)",
|
||||
"mMMMMᎷМ💯 👌👌 👌НO0ОଠOOOOOОଠଠOoooᵒᵒᵒᵒᵒᵒᵒᵒᵒ👌 👌👌 👌 💯 👌 👀 👀 👀 👌👌Good shit",
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
// Read the font data.
|
||||
fontBytes, err := ioutil.ReadFile(*fontfile)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
f, err := freetype.ParseFont(fontBytes)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
// Initialize the context.
|
||||
fg, bg := image.Black, image.White
|
||||
ruler := color.RGBA{0xdd, 0xdd, 0xdd, 0xff}
|
||||
if *wonb {
|
||||
fg, bg = image.White, image.Black
|
||||
ruler = color.RGBA{0x22, 0x22, 0x22, 0xff}
|
||||
}
|
||||
rgba := image.NewRGBA(image.Rect(0, 0, 640, 480))
|
||||
draw.Draw(rgba, rgba.Bounds(), bg, image.ZP, draw.Src)
|
||||
c := freetype.NewContext()
|
||||
c.SetDPI(*dpi)
|
||||
c.SetFont(f)
|
||||
c.SetFontSize(*size)
|
||||
c.SetClip(rgba.Bounds())
|
||||
c.SetDst(rgba)
|
||||
c.SetSrc(fg)
|
||||
switch *hinting {
|
||||
default:
|
||||
c.SetHinting(font.HintingNone)
|
||||
case "full":
|
||||
c.SetHinting(font.HintingFull)
|
||||
}
|
||||
|
||||
// Draw the guidelines.
|
||||
for i := 0; i < 200; i++ {
|
||||
rgba.Set(10, 10+i, ruler)
|
||||
rgba.Set(10+i, 10, ruler)
|
||||
}
|
||||
|
||||
// Draw the text.
|
||||
pt := freetype.Pt(10, 10+int(c.PointToFixed(*size)>>6))
|
||||
for _, s := range text {
|
||||
_, err = c.DrawString(s, pt)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
pt.Y += c.PointToFixed(*size * *spacing)
|
||||
}
|
||||
|
||||
// Save that RGBA image to disk.
|
||||
outFile, err := os.Create("out.png")
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer outFile.Close()
|
||||
b := bufio.NewWriter(outFile)
|
||||
err = png.Encode(b, rgba)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
err = b.Flush()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Println("Wrote out.png OK.")
|
||||
}
|
|
@ -23,7 +23,7 @@ import (
|
|||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/golang/freetype"
|
||||
"git.fromouter.space/crunchy-rocks/freetype"
|
||||
"golang.org/x/image/font"
|
||||
)
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ import (
|
|||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/golang/freetype/raster"
|
||||
"git.fromouter.space/crunchy-rocks/freetype/raster"
|
||||
"golang.org/x/image/math/fixed"
|
||||
)
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ import (
|
|||
"strings"
|
||||
"unicode"
|
||||
|
||||
"github.com/golang/freetype/truetype"
|
||||
"git.fromouter.space/crunchy-rocks/freetype/truetype"
|
||||
"golang.org/x/image/font"
|
||||
"golang.org/x/image/math/fixed"
|
||||
)
|
||||
|
|
|
@ -21,7 +21,7 @@ import (
|
|||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/golang/freetype/raster"
|
||||
"git.fromouter.space/crunchy-rocks/freetype/raster"
|
||||
"golang.org/x/image/math/fixed"
|
||||
)
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ import (
|
|||
"math"
|
||||
"os"
|
||||
|
||||
"github.com/golang/freetype/raster"
|
||||
"git.fromouter.space/crunchy-rocks/freetype/raster"
|
||||
"golang.org/x/image/math/fixed"
|
||||
)
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ import (
|
|||
"io/ioutil"
|
||||
"log"
|
||||
|
||||
"github.com/golang/freetype/truetype"
|
||||
"git.fromouter.space/crunchy-rocks/freetype/truetype"
|
||||
"golang.org/x/image/font"
|
||||
"golang.org/x/image/math/fixed"
|
||||
)
|
||||
|
|
24
freetype.go
24
freetype.go
|
@ -6,15 +6,16 @@
|
|||
// The freetype package provides a convenient API to draw text onto an image.
|
||||
// Use the freetype/raster and freetype/truetype packages for lower level
|
||||
// control over rasterization and TrueType parsing.
|
||||
package freetype // import "github.com/golang/freetype"
|
||||
package freetype // import "git.fromouter.space/crunchy-rocks/freetype"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/draw"
|
||||
|
||||
"github.com/golang/freetype/raster"
|
||||
"github.com/golang/freetype/truetype"
|
||||
"git.fromouter.space/crunchy-rocks/freetype/raster"
|
||||
"git.fromouter.space/crunchy-rocks/freetype/truetype"
|
||||
"golang.org/x/image/font"
|
||||
"golang.org/x/image/math/fixed"
|
||||
)
|
||||
|
@ -232,8 +233,21 @@ 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
|
||||
for _, rune := range s {
|
||||
index := c.f.Index(rune)
|
||||
nextchar := 0
|
||||
for index, r := range s {
|
||||
// Check if we need to skip entries
|
||||
if nextchar > index {
|
||||
continue
|
||||
}
|
||||
// Check if rune is an emoji
|
||||
if isEmoji(r) {
|
||||
emoji, err := parseEmoji(s[index:])
|
||||
if err == nil {
|
||||
fmt.Println("Found emoji:", emoji)
|
||||
nextchar = index + emoji.Bytes
|
||||
}
|
||||
}
|
||||
index := c.f.Index(r)
|
||||
if hasPrev {
|
||||
kern := c.f.Kern(c.scale, prev, index)
|
||||
if c.hinting != font.HintingNone {
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
// the Freetype "smooth" module, and the Anti-Grain Geometry library. A
|
||||
// description of the area/coverage algorithm is at
|
||||
// http://projects.tuxee.net/cl-vectors/section-the-cl-aa-algorithm
|
||||
package raster // import "github.com/golang/freetype/raster"
|
||||
package raster // import "git.fromouter.space/crunchy-rocks/freetype/raster"
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"image"
|
||||
"math"
|
||||
|
||||
"github.com/golang/freetype/raster"
|
||||
"git.fromouter.space/crunchy-rocks/freetype/raster"
|
||||
"golang.org/x/image/font"
|
||||
"golang.org/x/image/math/fixed"
|
||||
)
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
//
|
||||
// To measure a TrueType font in ideal FUnit space, use scale equal to
|
||||
// font.FUnitsPerEm().
|
||||
package truetype // import "github.com/golang/freetype/truetype"
|
||||
package truetype // import "git.fromouter.space/crunchy-rocks/freetype/truetype"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
|
Loading…
Reference in a new issue