1// Copyright 2015 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5// Package font defines an interface for font faces, for drawing text on an 6// image. 7// 8// Other packages provide font face implementations. For example, a truetype 9// package would provide one based on .ttf font files. 10package font // import "golang.org/x/image/font" 11 12import ( 13 "image" 14 "image/draw" 15 "io" 16 "unicode/utf8" 17 18 "golang.org/x/image/math/fixed" 19) 20 21// TODO: who is responsible for caches (glyph images, glyph indices, kerns)? 22// The Drawer or the Face? 23 24// Face is a font face. Its glyphs are often derived from a font file, such as 25// "Comic_Sans_MS.ttf", but a face has a specific size, style, weight and 26// hinting. For example, the 12pt and 18pt versions of Comic Sans are two 27// different faces, even if derived from the same font file. 28// 29// A Face is not safe for concurrent use by multiple goroutines, as its methods 30// may re-use implementation-specific caches and mask image buffers. 31// 32// To create a Face, look to other packages that implement specific font file 33// formats. 34type Face interface { 35 io.Closer 36 37 // Glyph returns the draw.DrawMask parameters (dr, mask, maskp) to draw r's 38 // glyph at the sub-pixel destination location dot, and that glyph's 39 // advance width. 40 // 41 // It returns !ok if the face does not contain a glyph for r. 42 // 43 // The contents of the mask image returned by one Glyph call may change 44 // after the next Glyph call. Callers that want to cache the mask must make 45 // a copy. 46 Glyph(dot fixed.Point26_6, r rune) ( 47 dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool) 48 49 // GlyphBounds returns the bounding box of r's glyph, drawn at a dot equal 50 // to the origin, and that glyph's advance width. 51 // 52 // It returns !ok if the face does not contain a glyph for r. 53 // 54 // The glyph's ascent and descent are equal to -bounds.Min.Y and 55 // +bounds.Max.Y. The glyph's left-side and right-side bearings are equal 56 // to bounds.Min.X and advance-bounds.Max.X. A visual depiction of what 57 // these metrics are is at 58 // https://developer.apple.com/library/archive/documentation/TextFonts/Conceptual/CocoaTextArchitecture/Art/glyphterms_2x.png 59 GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) 60 61 // GlyphAdvance returns the advance width of r's glyph. 62 // 63 // It returns !ok if the face does not contain a glyph for r. 64 GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) 65 66 // Kern returns the horizontal adjustment for the kerning pair (r0, r1). A 67 // positive kern means to move the glyphs further apart. 68 Kern(r0, r1 rune) fixed.Int26_6 69 70 // Metrics returns the metrics for this Face. 71 Metrics() Metrics 72 73 // TODO: ColoredGlyph for various emoji? 74 // TODO: Ligatures? Shaping? 75} 76 77// Metrics holds the metrics for a Face. A visual depiction is at 78// https://developer.apple.com/library/mac/documentation/TextFonts/Conceptual/CocoaTextArchitecture/Art/glyph_metrics_2x.png 79type Metrics struct { 80 // Height is the recommended amount of vertical space between two lines of 81 // text. 82 Height fixed.Int26_6 83 84 // Ascent is the distance from the top of a line to its baseline. 85 Ascent fixed.Int26_6 86 87 // Descent is the distance from the bottom of a line to its baseline. The 88 // value is typically positive, even though a descender goes below the 89 // baseline. 90 Descent fixed.Int26_6 91 92 // XHeight is the distance from the top of non-ascending lowercase letters 93 // to the baseline. 94 XHeight fixed.Int26_6 95 96 // CapHeight is the distance from the top of uppercase letters to the 97 // baseline. 98 CapHeight fixed.Int26_6 99 100 // CaretSlope is the slope of a caret as a vector with the Y axis pointing up. 101 // The slope {0, 1} is the vertical caret. 102 CaretSlope image.Point 103} 104 105// Drawer draws text on a destination image. 106// 107// A Drawer is not safe for concurrent use by multiple goroutines, since its 108// Face is not. 109type Drawer struct { 110 // Dst is the destination image. 111 Dst draw.Image 112 // Src is the source image. 113 Src image.Image 114 // Face provides the glyph mask images. 115 Face Face 116 // Dot is the baseline location to draw the next glyph. The majority of the 117 // affected pixels will be above and to the right of the dot, but some may 118 // be below or to the left. For example, drawing a 'j' in an italic face 119 // may affect pixels below and to the left of the dot. 120 Dot fixed.Point26_6 121 122 // TODO: Clip image.Image? 123 // TODO: SrcP image.Point for Src images other than *image.Uniform? How 124 // does it get updated during DrawString? 125} 126 127// TODO: should DrawString return the last rune drawn, so the next DrawString 128// call can kern beforehand? Or should that be the responsibility of the caller 129// if they really want to do that, since they have to explicitly shift d.Dot 130// anyway? What if ligatures span more than two runes? What if grapheme 131// clusters span multiple runes? 132// 133// TODO: do we assume that the input is in any particular Unicode Normalization 134// Form? 135// 136// TODO: have DrawRunes(s []rune)? DrawRuneReader(io.RuneReader)?? If we take 137// io.RuneReader, we can't assume that we can rewind the stream. 138// 139// TODO: how does this work with line breaking: drawing text up until a 140// vertical line? Should DrawString return the number of runes drawn? 141 142// DrawBytes draws s at the dot and advances the dot's location. 143// 144// It is equivalent to DrawString(string(s)) but may be more efficient. 145func (d *Drawer) DrawBytes(s []byte) { 146 prevC := rune(-1) 147 for len(s) > 0 { 148 c, size := utf8.DecodeRune(s) 149 s = s[size:] 150 if prevC >= 0 { 151 d.Dot.X += d.Face.Kern(prevC, c) 152 } 153 dr, mask, maskp, advance, ok := d.Face.Glyph(d.Dot, c) 154 if !ok { 155 // TODO: is falling back on the U+FFFD glyph the responsibility of 156 // the Drawer or the Face? 157 // TODO: set prevC = '\ufffd'? 158 continue 159 } 160 draw.DrawMask(d.Dst, dr, d.Src, image.Point{}, mask, maskp, draw.Over) 161 d.Dot.X += advance 162 prevC = c 163 } 164} 165 166// DrawString draws s at the dot and advances the dot's location. 167func (d *Drawer) DrawString(s string) { 168 prevC := rune(-1) 169 for _, c := range s { 170 if prevC >= 0 { 171 d.Dot.X += d.Face.Kern(prevC, c) 172 } 173 dr, mask, maskp, advance, ok := d.Face.Glyph(d.Dot, c) 174 if !ok { 175 // TODO: is falling back on the U+FFFD glyph the responsibility of 176 // the Drawer or the Face? 177 // TODO: set prevC = '\ufffd'? 178 continue 179 } 180 draw.DrawMask(d.Dst, dr, d.Src, image.Point{}, mask, maskp, draw.Over) 181 d.Dot.X += advance 182 prevC = c 183 } 184} 185 186// BoundBytes returns the bounding box of s, drawn at the drawer dot, as well as 187// the advance. 188// 189// It is equivalent to BoundBytes(string(s)) but may be more efficient. 190func (d *Drawer) BoundBytes(s []byte) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) { 191 bounds, advance = BoundBytes(d.Face, s) 192 bounds.Min = bounds.Min.Add(d.Dot) 193 bounds.Max = bounds.Max.Add(d.Dot) 194 return 195} 196 197// BoundString returns the bounding box of s, drawn at the drawer dot, as well 198// as the advance. 199func (d *Drawer) BoundString(s string) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) { 200 bounds, advance = BoundString(d.Face, s) 201 bounds.Min = bounds.Min.Add(d.Dot) 202 bounds.Max = bounds.Max.Add(d.Dot) 203 return 204} 205 206// MeasureBytes returns how far dot would advance by drawing s. 207// 208// It is equivalent to MeasureString(string(s)) but may be more efficient. 209func (d *Drawer) MeasureBytes(s []byte) (advance fixed.Int26_6) { 210 return MeasureBytes(d.Face, s) 211} 212 213// MeasureString returns how far dot would advance by drawing s. 214func (d *Drawer) MeasureString(s string) (advance fixed.Int26_6) { 215 return MeasureString(d.Face, s) 216} 217 218// BoundBytes returns the bounding box of s with f, drawn at a dot equal to the 219// origin, as well as the advance. 220// 221// It is equivalent to BoundString(string(s)) but may be more efficient. 222func BoundBytes(f Face, s []byte) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) { 223 prevC := rune(-1) 224 for len(s) > 0 { 225 c, size := utf8.DecodeRune(s) 226 s = s[size:] 227 if prevC >= 0 { 228 advance += f.Kern(prevC, c) 229 } 230 b, a, ok := f.GlyphBounds(c) 231 if !ok { 232 // TODO: is falling back on the U+FFFD glyph the responsibility of 233 // the Drawer or the Face? 234 // TODO: set prevC = '\ufffd'? 235 continue 236 } 237 b.Min.X += advance 238 b.Max.X += advance 239 bounds = bounds.Union(b) 240 advance += a 241 prevC = c 242 } 243 return 244} 245 246// BoundString returns the bounding box of s with f, drawn at a dot equal to the 247// origin, as well as the advance. 248func BoundString(f Face, s string) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) { 249 prevC := rune(-1) 250 for _, c := range s { 251 if prevC >= 0 { 252 advance += f.Kern(prevC, c) 253 } 254 b, a, ok := f.GlyphBounds(c) 255 if !ok { 256 // TODO: is falling back on the U+FFFD glyph the responsibility of 257 // the Drawer or the Face? 258 // TODO: set prevC = '\ufffd'? 259 continue 260 } 261 b.Min.X += advance 262 b.Max.X += advance 263 bounds = bounds.Union(b) 264 advance += a 265 prevC = c 266 } 267 return 268} 269 270// MeasureBytes returns how far dot would advance by drawing s with f. 271// 272// It is equivalent to MeasureString(string(s)) but may be more efficient. 273func MeasureBytes(f Face, s []byte) (advance fixed.Int26_6) { 274 prevC := rune(-1) 275 for len(s) > 0 { 276 c, size := utf8.DecodeRune(s) 277 s = s[size:] 278 if prevC >= 0 { 279 advance += f.Kern(prevC, c) 280 } 281 a, ok := f.GlyphAdvance(c) 282 if !ok { 283 // TODO: is falling back on the U+FFFD glyph the responsibility of 284 // the Drawer or the Face? 285 // TODO: set prevC = '\ufffd'? 286 continue 287 } 288 advance += a 289 prevC = c 290 } 291 return advance 292} 293 294// MeasureString returns how far dot would advance by drawing s with f. 295func MeasureString(f Face, s string) (advance fixed.Int26_6) { 296 prevC := rune(-1) 297 for _, c := range s { 298 if prevC >= 0 { 299 advance += f.Kern(prevC, c) 300 } 301 a, ok := f.GlyphAdvance(c) 302 if !ok { 303 // TODO: is falling back on the U+FFFD glyph the responsibility of 304 // the Drawer or the Face? 305 // TODO: set prevC = '\ufffd'? 306 continue 307 } 308 advance += a 309 prevC = c 310 } 311 return advance 312} 313 314// Hinting selects how to quantize a vector font's glyph nodes. 315// 316// Not all fonts support hinting. 317type Hinting int 318 319const ( 320 HintingNone Hinting = iota 321 HintingVertical 322 HintingFull 323) 324 325// Stretch selects a normal, condensed, or expanded face. 326// 327// Not all fonts support stretches. 328type Stretch int 329 330const ( 331 StretchUltraCondensed Stretch = -4 332 StretchExtraCondensed Stretch = -3 333 StretchCondensed Stretch = -2 334 StretchSemiCondensed Stretch = -1 335 StretchNormal Stretch = +0 336 StretchSemiExpanded Stretch = +1 337 StretchExpanded Stretch = +2 338 StretchExtraExpanded Stretch = +3 339 StretchUltraExpanded Stretch = +4 340) 341 342// Style selects a normal, italic, or oblique face. 343// 344// Not all fonts support styles. 345type Style int 346 347const ( 348 StyleNormal Style = iota 349 StyleItalic 350 StyleOblique 351) 352 353// Weight selects a normal, light or bold face. 354// 355// Not all fonts support weights. 356// 357// The named Weight constants (e.g. WeightBold) correspond to CSS' common 358// weight names (e.g. "Bold"), but the numerical values differ, so that in Go, 359// the zero value means to use a normal weight. For the CSS names and values, 360// see https://developer.mozilla.org/en/docs/Web/CSS/font-weight 361type Weight int 362 363const ( 364 WeightThin Weight = -3 // CSS font-weight value 100. 365 WeightExtraLight Weight = -2 // CSS font-weight value 200. 366 WeightLight Weight = -1 // CSS font-weight value 300. 367 WeightNormal Weight = +0 // CSS font-weight value 400. 368 WeightMedium Weight = +1 // CSS font-weight value 500. 369 WeightSemiBold Weight = +2 // CSS font-weight value 600. 370 WeightBold Weight = +3 // CSS font-weight value 700. 371 WeightExtraBold Weight = +4 // CSS font-weight value 800. 372 WeightBlack Weight = +5 // CSS font-weight value 900. 373) 374