mirror of
https://github.com/alecthomas/chroma.git
synced 2025-03-19 21:10:15 +02:00
embedded font in svg (#292)
This commit is contained in:
parent
73d11b3c45
commit
611a24ccdd
@ -21,7 +21,7 @@ var (
|
|||||||
}))
|
}))
|
||||||
// Default HTML formatter outputs self-contained HTML.
|
// Default HTML formatter outputs self-contained HTML.
|
||||||
htmlFull = Register("html", html.New(html.Standalone(), html.WithClasses())) // nolint
|
htmlFull = Register("html", html.New(html.Standalone(), html.WithClasses())) // nolint
|
||||||
Svg = Register("svg", svg.New())
|
SVG = Register("svg", svg.New(svg.EmbedFont("Liberation Mono", svg.FontLiberationMono, svg.WOFF)))
|
||||||
)
|
)
|
||||||
|
|
||||||
// Fallback formatter.
|
// Fallback formatter.
|
||||||
|
51
formatters/svg/font_liberation_mono.go
Normal file
51
formatters/svg/font_liberation_mono.go
Normal file
File diff suppressed because one or more lines are too long
@ -2,8 +2,12 @@
|
|||||||
package svg
|
package svg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/alecthomas/chroma"
|
"github.com/alecthomas/chroma"
|
||||||
@ -12,9 +16,38 @@ import (
|
|||||||
// Option sets an option of the SVG formatter.
|
// Option sets an option of the SVG formatter.
|
||||||
type Option func(f *Formatter)
|
type Option func(f *Formatter)
|
||||||
|
|
||||||
|
// FontFamily sets the font-family.
|
||||||
|
func FontFamily(fontFamily string) Option { return func(f *Formatter) { f.fontFamily = fontFamily } }
|
||||||
|
|
||||||
|
// EmbedFontFile embeds given font file
|
||||||
|
func EmbedFontFile(fontFamily string, fileName string) (option Option, err error) {
|
||||||
|
var format FontFormat
|
||||||
|
switch path.Ext(fileName) {
|
||||||
|
case ".woff":
|
||||||
|
format = WOFF
|
||||||
|
case ".woff2":
|
||||||
|
format = WOFF2
|
||||||
|
case ".ttf":
|
||||||
|
format = TRUETYPE
|
||||||
|
default:
|
||||||
|
return nil, errors.New("unexpected font file suffix")
|
||||||
|
}
|
||||||
|
|
||||||
|
var content []byte
|
||||||
|
if content, err = ioutil.ReadFile(fileName); err == nil {
|
||||||
|
option = EmbedFont(fontFamily, base64.StdEncoding.EncodeToString(content), format)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmbedFont embeds given base64 encoded font
|
||||||
|
func EmbedFont(fontFamily string, font string, format FontFormat) Option {
|
||||||
|
return func(f *Formatter) { f.fontFamily = fontFamily; f.embeddedFont = font; f.fontFormat = format }
|
||||||
|
}
|
||||||
|
|
||||||
// New SVG formatter.
|
// New SVG formatter.
|
||||||
func New(options ...Option) *Formatter {
|
func New(options ...Option) *Formatter {
|
||||||
f := &Formatter{}
|
f := &Formatter{fontFamily: "Consolas, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace"}
|
||||||
for _, option := range options {
|
for _, option := range options {
|
||||||
option(f)
|
option(f)
|
||||||
}
|
}
|
||||||
@ -23,6 +56,9 @@ func New(options ...Option) *Formatter {
|
|||||||
|
|
||||||
// Formatter that generates SVG.
|
// Formatter that generates SVG.
|
||||||
type Formatter struct {
|
type Formatter struct {
|
||||||
|
fontFamily string
|
||||||
|
embeddedFont string
|
||||||
|
fontFormat FontFormat
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Formatter) Format(w io.Writer, style *chroma.Style, iterator chroma.Iterator) (err error) {
|
func (f *Formatter) Format(w io.Writer, style *chroma.Style, iterator chroma.Iterator) (err error) {
|
||||||
@ -56,8 +92,13 @@ func (f *Formatter) writeSVG(w io.Writer, style *chroma.Style, tokens []chroma.T
|
|||||||
fmt.Fprint(w, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
|
fmt.Fprint(w, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
|
||||||
fmt.Fprint(w, "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n")
|
fmt.Fprint(w, "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n")
|
||||||
fmt.Fprintf(w, "<svg height=\"%d\" xmlns=\"http://www.w3.org/2000/svg\">\n", len(lines)*22)
|
fmt.Fprintf(w, "<svg height=\"%d\" xmlns=\"http://www.w3.org/2000/svg\">\n", len(lines)*22)
|
||||||
|
|
||||||
|
if f.embeddedFont != "" {
|
||||||
|
f.writeFontStyle(w)
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Fprintf(w, "<rect width=\"100%%\" height=\"100%%\" fill=\"%s\"/>\n", style.Get(chroma.Background).Background.String())
|
fmt.Fprintf(w, "<rect width=\"100%%\" height=\"100%%\" fill=\"%s\"/>\n", style.Get(chroma.Background).Background.String())
|
||||||
fmt.Fprintf(w, "<g font-family=\"Consolas, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace\" font-size=\"14px\" fill=\"%s\">\n", style.Get(chroma.Text).Colour.String())
|
fmt.Fprintf(w, "<g font-family=\"%s\" font-size=\"14px\" fill=\"%s\">\n", f.fontFamily, style.Get(chroma.Text).Colour.String())
|
||||||
|
|
||||||
f.writeTokenBackgrounds(w, lines, style)
|
f.writeTokenBackgrounds(w, lines, style)
|
||||||
|
|
||||||
@ -96,6 +137,32 @@ func (f *Formatter) writeTokenBackgrounds(w io.Writer, lines [][]chroma.Token, s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FontFormat int
|
||||||
|
|
||||||
|
// https://transfonter.org/formats
|
||||||
|
const (
|
||||||
|
WOFF FontFormat = iota
|
||||||
|
WOFF2
|
||||||
|
TRUETYPE
|
||||||
|
)
|
||||||
|
|
||||||
|
var fontFormats = [...]string{
|
||||||
|
"woff",
|
||||||
|
"woff2",
|
||||||
|
"truetype",
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Formatter) writeFontStyle(w io.Writer) {
|
||||||
|
fmt.Fprintf(w, `<style>
|
||||||
|
@font-face {
|
||||||
|
font-family: '%s';
|
||||||
|
src: url(data:application/x-font-%s;charset=utf-8;base64,%s) format('%s');'
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
</style>`, f.fontFamily, fontFormats[f.fontFormat], f.embeddedFont, fontFormats[f.fontFormat])
|
||||||
|
}
|
||||||
|
|
||||||
func (f *Formatter) styleAttr(styles map[chroma.TokenType]string, tt chroma.TokenType) string {
|
func (f *Formatter) styleAttr(styles map[chroma.TokenType]string, tt chroma.TokenType) string {
|
||||||
if _, ok := styles[tt]; !ok {
|
if _, ok := styles[tt]; !ok {
|
||||||
tt = tt.SubCategory()
|
tt = tt.SubCategory()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user