From 1b49270d080a9073a84d485e9d0fad72e0010654 Mon Sep 17 00:00:00 2001 From: Drahoslav Date: Sun, 7 Jan 2018 17:57:38 +0100 Subject: [PATCH] Experimental embed svg font functionality --- draw2dsvg/fileutil.go | 4 +- draw2dsvg/gc.go | 79 ++++++++++++++++++++++++++--------- draw2dsvg/svg.go | 52 +++++++++++++++++++++-- draw2dsvg/xml_test.go | 1 + output/samples/geometry.png | Bin 23028 -> 24322 bytes path.go | 31 ++++++++++++++ samples/geometry/geometry.go | 9 ++++ 7 files changed, 152 insertions(+), 24 deletions(-) diff --git a/draw2dsvg/fileutil.go b/draw2dsvg/fileutil.go index ed28f03..2ade34b 100644 --- a/draw2dsvg/fileutil.go +++ b/draw2dsvg/fileutil.go @@ -1,9 +1,9 @@ package draw2dsvg import ( - "os" "encoding/xml" _ "errors" + "os" ) func SaveToSvgFile(filePath string, svg *Svg) error { @@ -19,4 +19,4 @@ func SaveToSvgFile(filePath string, svg *Svg) error { err = encoder.Encode(svg) return err -} \ No newline at end of file +} diff --git a/draw2dsvg/gc.go b/draw2dsvg/gc.go index 6e83aa4..b4a6dca 100644 --- a/draw2dsvg/gc.go +++ b/draw2dsvg/gc.go @@ -4,17 +4,17 @@ package draw2dsvg import ( + "fmt" + "github.com/golang/freetype/truetype" "github.com/llgcode/draw2d" "github.com/llgcode/draw2d/draw2dbase" + "golang.org/x/image/font" + "golang.org/x/image/math/fixed" "image" "log" - "strings" "math" - "github.com/golang/freetype/truetype" - "golang.org/x/image/math/fixed" - "golang.org/x/image/font" "strconv" - "fmt" + "strings" ) type drawType int @@ -133,12 +133,16 @@ func (gc *GraphicContext) drawString(text string, drawType drawType, x, y float6 svgText.FontSize = gc.Current.FontSize svgText.X = x svgText.Y = y - svgText.FontFamily = "" // TODO set font + svgText.FontFamily = gc.Current.FontData.Name + + if gc.svg.fontMode == SvgFontMode { + gc.embedSvgFont(text) + } // link to group group.Texts = []*Text{&svgText} left, _, right, _ := gc.GetStringBounds(text) - return right-left + return right - left } // Creates new group from current context @@ -170,20 +174,59 @@ func (gc *GraphicContext) newGroup(drawType drawType) *Group { return &group } -/////////////////////////////////////// -// TODO implement following methods (or remove if not neccesary) +// Embed svg font definition to svg tree itself +func (gc *GraphicContext) embedSvgFont(text string) { + fontName := gc.Current.FontData.Name + gc.loadCurrentFont() -// SetFontData sets the current FontData -func (gc *GraphicContext) SetFontData(fontData draw2d.FontData) { + // find or create font Element + svgFont := (*Font)(nil) + for _, font := range gc.svg.Fonts { + if font.Name == fontName { + svgFont = font + break + } + } + if svgFont == nil { + // create new + svgFont = &Font{} + // and link + gc.svg.Fonts = append(gc.svg.Fonts, svgFont) + } + // fill with glyphs + + gc.Save() + defer gc.Restore() + gc.SetFontSize(2048) + defer gc.SetDPI(gc.GetDPI()) + gc.SetDPI(92) +filling: + for _, rune := range text { + for _, g := range svgFont.Glyphs { + if g.Rune == Rune(rune) { + continue filling + } + } + glyph := gc.glyphCache.Fetch(gc, gc.GetFontName(), rune) + // glyphCache.Load indirectly calls CreateStringPath for single rune string + + glypPath := glyph.Path.VerticalFlip() // svg font glyphs have oposite y axe + svgFont.Glyphs = append(svgFont.Glyphs, &Glyph{ + Rune: Rune(rune), + Desc: toSvgPathDesc(glypPath), + HorizAdvX: glyph.Width, + }) + } + + // set attrs + svgFont.Id = "font-" + strconv.Itoa(len(gc.svg.Fonts)) + svgFont.Name = fontName + + // TODO use css @font-face with id instead of this + svgFont.Face = &Face{Family: fontName, Units: 2048, HorizAdvX: 2048} } -// GetFontData gets the current FontData -func (gc *GraphicContext) GetFontData() draw2d.FontData { - return draw2d.FontData{} -} - - // NOTE following functions copied from dwra2d{img|gl} // TODO move them all to common draw2dbase? @@ -218,7 +261,6 @@ func (gc *GraphicContext) CreateStringPath(s string, x, y float64) (cursor float return x - startx } - // GetStringBounds returns the approximate pixel bounds of the string s at x, y. // The the left edge of the em square of the first character of s // and the baseline intersect at 0, 0 in the returned coordinates. @@ -311,7 +353,6 @@ func (gc *GraphicContext) SetFontSize(fontSize float64) { gc.recalc() } - /////////////////////////////////////// // TODO implement following methods (or remove if not neccesary) diff --git a/draw2dsvg/svg.go b/draw2dsvg/svg.go index baad46e..819832e 100644 --- a/draw2dsvg/svg.go +++ b/draw2dsvg/svg.go @@ -9,10 +9,22 @@ import ( /* svg elements */ +type FontMode int + +const ( + SysFontMode FontMode = 1 << iota + LinkFontMode + SvgFontMode + CssFontMode + PathFontMode +) + type Svg struct { - XMLName xml.Name `xml:"svg"` - Xmlns string `xml:"xmlns,attr"` - Groups []*Group `xml:"g"` + XMLName xml.Name `xml:"svg"` + Xmlns string `xml:"xmlns,attr"` + Fonts []*Font `xml:"defs>font"` + Groups []*Group `xml:"g"` + fontMode FontMode FillStroke } @@ -20,6 +32,7 @@ func NewSvg() *Svg { return &Svg{ Xmlns: "http://www.w3.org/2000/svg", FillStroke: FillStroke{Fill: "none", Stroke: "none"}, + fontMode: SvgFontMode, } } @@ -45,8 +58,41 @@ type Text struct { Style string `xml:"style,attr,omitempty"` } +type Font struct { + Identity + Face *Face `xml:"font-face"` + Glyphs []*Glyph `xml:"glyph"` +} + +type Face struct { + Family string `xml:"font-family,attr"` + Units int `xml:"units-per-em,attr"` + HorizAdvX float64 `xml:"horiz-adv-x,attr"` + // TODO add other attrs, like style, variant, weight... +} + +type Glyph struct { + Rune Rune `xml:"unicode,attr"` + Desc string `xml:"d,attr"` + HorizAdvX float64 `xml:"horiz-adv-x,attr"` +} + +type Rune rune + +func (r Rune) MarshalXMLAttr(name xml.Name) (xml.Attr, error) { + return xml.Attr{ + Name: name, + Value: string(rune(r)), + }, nil +} + /* shared attrs */ +type Identity struct { + Id string `xml:"id,attr"` + Name string `xml:"name,attr"` +} + type Position struct { X float64 `xml:"x,attr,omitempty"` Y float64 `xml:"y,attr,omitempty"` diff --git a/draw2dsvg/xml_test.go b/draw2dsvg/xml_test.go index b0760e7..8a7d11e 100644 --- a/draw2dsvg/xml_test.go +++ b/draw2dsvg/xml_test.go @@ -31,6 +31,7 @@ func TestXml(t *testing.T) { }} expectedOut := ` + diff --git a/output/samples/geometry.png b/output/samples/geometry.png index b68bb3275a511c1bcab41fafd0bdfad1ecd17d33..b46ec8953d3b6fba9d9040e35a36aa13b9776d43 100644 GIT binary patch literal 24322 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 Hu0mjf_k>wS diff --git a/path.go b/path.go index 04a6572..bd24c9b 100644 --- a/path.go +++ b/path.go @@ -190,3 +190,34 @@ func (p *Path) String() string { } return s } + +// Returns new Path with flipped y axes +func (path *Path) VerticalFlip() *Path { + p := path.Copy() + j := 0 + for _, cmd := range p.Components { + switch cmd { + case MoveToCmp, LineToCmp: + p.Points[j+1] = -p.Points[j+1] + j = j + 2 + case QuadCurveToCmp: + p.Points[j+1] = -p.Points[j+1] + p.Points[j+3] = -p.Points[j+3] + j = j + 4 + case CubicCurveToCmp: + p.Points[j+1] = -p.Points[j+1] + p.Points[j+3] = -p.Points[j+3] + p.Points[j+5] = -p.Points[j+5] + j = j + 6 + case ArcToCmp: + p.Points[j+1] = -p.Points[j+1] + p.Points[j+3] = -p.Points[j+3] + p.Points[j+4] = -p.Points[j+4] // start angle + p.Points[j+5] = -p.Points[j+5] // angle + j = j + 6 + case CloseCmp: + } + } + p.y = -p.y + return p +} diff --git a/samples/geometry/geometry.go b/samples/geometry/geometry.go index 90892f9..05d9bdb 100644 --- a/samples/geometry/geometry.go +++ b/samples/geometry/geometry.go @@ -189,6 +189,7 @@ func CubicCurve(gc draw2d.GraphicContext, x, y, width, height float64) { } // FillString draws a filled and stroked string. +// And filles/stroked path created from string. Which may have different - unselectable - output in non raster gc implementations. func FillString(gc draw2d.GraphicContext, x, y, width, height float64) { sx, sy := width/100, height/100 gc.Save() @@ -215,6 +216,14 @@ func FillString(gc draw2d.GraphicContext, x, y, width, height float64) { gc.SetStrokeColor(color.NRGBA{0x33, 0x33, 0xff, 0xff}) gc.SetLineWidth(height / 100) gc.StrokeString("Hug") + + gc.Translate(-(w + sx), sy*24) + w = gc.CreateStringPath("Hug", 0, 0) + gc.Fill() + gc.Translate(w+sx, 0) + gc.CreateStringPath("Hug", 0, 0) + path := gc.GetPath() + gc.Stroke((&path).VerticalFlip()) gc.Restore() }