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