Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Smallcache #38

Merged
merged 4 commits into from
Dec 7, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions box/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
)

// MaxBytes is the largest capacity of bytes in a box
var MaxBytes = 512 + 3
var MaxBytes = 256 + 3

func NewRun(minDx, maxDx int, ft *font.Font, newRulerFunc ...func([]byte, *font.Font) Ruler) Run {
fn := NewByteRuler
Expand All @@ -20,7 +20,6 @@ func NewRun(minDx, maxDx int, ft *font.Font, newRulerFunc ...func([]byte, *font.
Font: ft,
newRulerFunc: fn,
br: fn(make([]byte, MaxBytes), ft),
br2: fn(make([]byte, MaxBytes), ft),
}
}

Expand All @@ -39,7 +38,6 @@ type Run struct {

newRulerFunc func([]byte, *font.Font) Ruler
br Ruler
br2 Ruler
}

func (f *Run) Combine(g *Run, n int) {
Expand Down Expand Up @@ -118,14 +116,14 @@ func (f *Run) Split(bn, n int) {
}

func (f *Run) MeasureBytes(p []byte) int {
br := f.newRulerFunc(p, f.Font)
f.br.Reset(p)//f.newRulerFunc(p, f.Font)
for {
_, _, err := br.Next()
_, _, err := f.br.Next()
if err != nil {
break
}
}
return br.Width()
return f.br.Width()
}

// Chop drops the first n chars in box b
Expand Down
7 changes: 7 additions & 0 deletions draw.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,13 @@ func (f *Frame) drawsel(pt image.Point, p0, p1 int64, back, text image.Image) im
if f.PlainBox(nb) {
f.stringNBG(f.b, pt, text, image.ZP, f.Font, ptr)
}
// TODO(as): replace the above with the snippet below: reason:
// stringBG is more efficient now that it does an src bitblt for an already-known character
// if f.PlainBox(nb){
// f.stringBG(f.b, pt, text, image.ZP, f.Font, ptr)
// } else {
// f.Draw(f.b, image.Rect(pt.X, pt.Y, min(pt.X+w, f.r.Max.X), pt.Y+f.Font.Dy()), back, pt, f.op)
// }
pt.X += w

if q0 += len(ptr); q0 >= p1 {
Expand Down
59 changes: 59 additions & 0 deletions font/decon.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package font

import "image"

func deconvolveGlyph(g *Glyph) *Glyph {
if g.mask == nil {
panic("deconvolveGlyph: nil g.mask")
}
g.mask = deconvolve(g.mask)
return g
}

func ampGlyph(g *Glyph) *Glyph {
if g.mask == nil {
panic("ampGlyph: nil g.mask")
}
g.mask = amp(g.mask)
return g
}
func deconvolve(m *image.Alpha) *image.Alpha {
av := func(x, y int) uint8 {
a := m.AlphaAt(x, y)
return a.A
}
for y := 0; y < m.Bounds().Dy(); y++ {
for x := 0; x < m.Bounds().Dx(); x++ {
a := m.AlphaAt(x, y)
mean := int(
av(x-1, y-1)+av(x, y-1)+av(x+1, y-1)+
av(x-1, y-0)+av(x, y-0)+av(x+1, y-0)+
av(x-1, y+1)+av(x, y+1)+av(x+1, y+1)) / 8
if a.A-uint8(mean) > a.A {
a.A = 0
} else {
a.A -= uint8(mean)
}
defer m.SetAlpha(x, y, a)
}
}
return m
}

func amp(m *image.Alpha) *image.Alpha {
for y := 0; y < m.Bounds().Dy(); y++ {
for x := 0; x < m.Bounds().Dx(); x++ {
a := m.AlphaAt(x, y)
if a.A < 64 {
continue
}
if a.A+64 < a.A {
a.A = 255
} else {
a.A += 64
}
defer m.SetAlpha(x, y, a)
}
}
return m
}
30 changes: 29 additions & 1 deletion font/draw.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,43 @@ import (
)

func StringBG(dst draw.Image, p image.Point, src image.Image, sp image.Point, ft *Font, s []byte, bg image.Image, bgp image.Point) int {
cache := ft.imgCache
quad := rgba{}
{
r, g, b, a := bg.(*image.Uniform).RGBA()
quad = rgba{r, g, b, a}
}
sig := signature{
dy: ft.Dy(),
rgba: quad,
}
r0 := image.Rectangle{p, p}
for _, b := range s {
sig.b = b
if img, ok := cache[sig]; ok {
draw.Draw(dst, img.Bounds().Add(p), img, img.Bounds().Min, draw.Src)
p.X += img.Bounds().Dx() + ft.stride //Add(image.Pt(img.Bounds().Dx(), 0))
continue
}
mask := ft.Char(b)
if mask == nil {
panic("StringBG")
}
r := mask.Bounds()
//draw.Draw(dst, r.Add(p), bg, bgp, draw.Src)
if r0.Min == image.ZP {
r0.Min = r.Add(p).Min
}
draw.DrawMask(dst, r.Add(p), src, sp, mask, mask.Bounds().Min, draw.Over)
img := image.NewRGBA(r)
draw.Draw(img, img.Bounds(), bg, bgp, draw.Src)
draw.Draw(img, img.Bounds(), dst, r.Add(p).Min, draw.Src)
cache[sig] = img

p.X += r.Dx() + ft.stride
r0.Max.X += r.Dx() + ft.stride
if r.Dy() > r0.Dy() {
r0.Max.Y = r.Dy()
}
}
return p.X
}
Expand Down
86 changes: 62 additions & 24 deletions font/font.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package font

import (
"fmt"
"image"
"image/draw"
"unicode"
Expand All @@ -11,6 +10,7 @@ import (
"golang.org/x/image/font/basicfont"
"golang.org/x/image/font/gofont/gomedium"
"golang.org/x/image/font/gofont/gomono"
"golang.org/x/image/font/gofont/gomonobold"
"golang.org/x/image/font/gofont/goregular"
"golang.org/x/image/math/fixed"
)
Expand All @@ -29,6 +29,16 @@ type Font struct {
cache Cache
hexCache Cache
decCache Cache
imgCache map[signature]*image.RGBA
}

type rgba struct {
r, g, b, a uint32
}
type signature struct {
b byte
dy int
rgba
}

func NewGoRegular(size int) *Font {
Expand All @@ -39,6 +49,10 @@ func NewGoMedium(size int) *Font {
return NewTTF(gomedium.TTF, size)
}

func NewGoMonoBold(size int) *Font {
return NewTTF(gomonobold.TTF, size)
}

func NewGoMono(size int) *Font {
return NewTTF(gomono.TTF, size)
}
Expand All @@ -48,34 +62,49 @@ func NewBasic(size int) *Font {
f := basicfont.Face7x13
size = 13
ft := &Font{
Face: f,
size: size,
ascent: 2,
descent: 1,
letting: 0,
stride: 0,
Face: f,
size: size,
ascent: 2,
descent: 1,
letting: 0,
stride: 0,
imgCache: make(map[signature]*image.RGBA),
}
ft.dy = ft.ascent + ft.descent + ft.size
hexFt := fromTTF(gomono.TTF, ft.Dy()/4+3)
ft.hexDx = ft.genChar('_').Bounds().Dx()
helper := mkhelper(hexFt)
for i := 0; i != 256; i++ {
ft.cache[i] = ft.genChar(byte(i))
if ft.cache[i] == nil {
ft.cache[i] = hexFt.genHexChar(ft.Dy(), byte(i))
ft.cache[i] = hexFt.genHexCharTest(ft.Dy(), byte(i), helper)
}
}
return ft
}

const hexbytes = "0123456789abcdef"

func mkhelper(hexFt *Font) []*Glyph {
helper := make([]*Glyph, 0, len(hexbytes))
for _, s := range hexbytes {
helper = append(helper, hexFt.genChar(byte(s)))
}
return helper
}

func NewTTF(data []byte, size int) *Font {
//return makefont(data, size)
ft := fromTTF(data, size)
hexFt := fromTTF(gomono.TTF, ft.Dy()/4+3)

hexFt := fromTTF(gomono.TTF, ft.Dy()/3+3)
//hexFt := fromTTF(gomono.TTF, ft.Dy()/4+3)
ft.hexDx = ft.genChar('_').Bounds().Dx()

helper := mkhelper(hexFt)
for i := 0; i != 256; i++ {
ft.cache[i] = ft.genChar(byte(i))
if ft.cache[i] == nil {
ft.cache[i] = hexFt.genHexChar(ft.Dy(), byte(i))
ft.cache[i] = hexFt.genHexChar(ft.Dy(), byte(i), helper)
}
}
return ft
Expand All @@ -88,15 +117,14 @@ func fromTTF(data []byte, size int) *Font {
ft := &Font{
Face: truetype.NewFace(f,
&truetype.Options{
Size: float64(size),
GlyphCacheEntries: 512 * 2,
SubPixelsX: 1,
Size: float64(size),
}),
size: size,
ascent: 2,
descent: +(size / 3),
stride: 0,
data: data,
size: size,
ascent: 2,
descent: +(size / 3),
stride: 0,
data: data,
imgCache: make(map[signature]*image.RGBA),
}
ft.dy = ft.ascent + ft.descent + ft.size
return ft
Expand Down Expand Up @@ -145,20 +173,19 @@ func (f *Font) SetLetting(px int) {
}

func (f *Font) genChar(b byte) *Glyph {
dr, mask, maskp, adv, _ := f.Face.Glyph(fixed.P(0, f.size), rune(b))
if !f.Printable(b) {
return nil
}
dr, mask, maskp, adv, _ := f.Face.Glyph(fixed.P(0, f.size), rune(b))
r := image.Rect(0, 0, Fix(adv), f.Dy())
m := image.NewAlpha(r)
r = r.Add(image.Pt(dr.Min.X, dr.Min.Y))
draw.Draw(m, r, mask, maskp, draw.Src)
return &Glyph{mask: m, Rectangle: m.Bounds()}
}
func (f *Font) genHexChar(dy int, b byte) *Glyph {
s := fmt.Sprintf("%02x", b)
g0 := f.genChar(s[0])
g1 := f.genChar(s[1])
func (f *Font) genHexCharTest(dy int, b byte, helper []*Glyph) *Glyph {
g0 := helper[b/16]
g1 := helper[b%16]
r := image.Rect(2, f.descent+f.ascent, g0.Bounds().Dx()+g1.Bounds().Dx()+6, dy)
m := image.NewAlpha(r)
draw.Draw(m, r, g0.Mask(), image.ZP, draw.Over)
Expand All @@ -167,6 +194,17 @@ func (f *Font) genHexChar(dy int, b byte) *Glyph {
return &Glyph{mask: m, Rectangle: m.Bounds()}
}

func (f *Font) genHexChar(dy int, b byte, helper []*Glyph) *Glyph {
g0 := helper[b/16]
g1 := helper[b%16]
r := image.Rect(2, f.descent+f.ascent-3, g0.Bounds().Dx()+g1.Bounds().Dx()+7, dy)
m := image.NewAlpha(r)
draw.Draw(m, r, g0.Mask(), image.ZP, draw.Over)
r.Min.X += g0.Mask().Bounds().Dx()
draw.Draw(m, r.Add(image.Pt(-f.descent/4, f.descent+f.descent/2)), g1.Mask(), image.ZP, draw.Over)
return &Glyph{mask: m, Rectangle: m.Bounds()}
}

func (f *Font) Char(b byte) (mask *image.Alpha) {
return f.cache[b].mask
}
Expand Down
Loading