From 696ea8953089c3872bca22ec24ca28139ef46cd3 Mon Sep 17 00:00:00 2001 From: Přemysl Janouch Date: Fri, 26 Apr 2019 11:40:43 +0200 Subject: label-tool: respect font ascent and descent Also try to load the values from the BDF font file. --- bdf/bdf.go | 28 ++++++++++++++-------------- label/label.go | 40 ++++++++++++++++++++++++++++++---------- 2 files changed, 44 insertions(+), 24 deletions(-) diff --git a/bdf/bdf.go b/bdf/bdf.go index c02e31e..5ff8f30 100644 --- a/bdf/bdf.go +++ b/bdf/bdf.go @@ -49,6 +49,8 @@ func (g *glyph) At(x, y int) color.Color { // Font represents a particular bitmap font. type Font struct { Name string + Ascent int // needn't be present in the font + Descent int // needn't be present in the font glyphs map[rune]glyph fallback glyph } @@ -192,17 +194,23 @@ func (p *bdfParser) readLine() bool { return true } -func (p *bdfParser) readCharEncoding() int { +func (p *bdfParser) readIntegerArgument() int { if len(p.tokens) < 2 { panic("insufficient arguments") } if i, err := strconv.Atoi(p.tokens[1]); err != nil { panic(err) } else { - return i // Some fonts even use -1 for things outside the encoding. + return i } } +// Some fonts even use -1 for things outside the encoding. +func (p *bdfParser) readCharEncoding() int { return p.readIntegerArgument() } + +// XXX: Ignoring vertical advance since we only expect purely horizontal fonts. +func (p *bdfParser) readDwidth() int { return p.readIntegerArgument() } + func (p *bdfParser) parseProperties() { // The wording in the specification suggests that the argument // with the number of properties to follow isn't reliable. @@ -210,22 +218,14 @@ func (p *bdfParser) parseProperties() { switch p.tokens[0] { case "DEFAULT_CHAR": p.defaultChar = p.readCharEncoding() + case "FONT_ASCENT": + p.font.Ascent = p.readIntegerArgument() + case "FONT_DESCENT": + p.font.Descent = p.readIntegerArgument() } } } -// XXX: Ignoring vertical advance since we only expect purely horizontal fonts. -func (p *bdfParser) readDwidth() int { - if len(p.tokens) < 2 { - panic("insufficient arguments") - } - if i, err := strconv.Atoi(p.tokens[1]); err != nil { - panic(err) - } else { - return i - } -} - func (p *bdfParser) readBBX() image.Rectangle { if len(p.tokens) < 5 { panic("insufficient arguments") diff --git a/label/label.go b/label/label.go index 062b072..63c600e 100644 --- a/label/label.go +++ b/label/label.go @@ -51,6 +51,13 @@ func GenLabelForHeight(font *bdf.Font, return combinedImg } +func max(a, b int) int { + if a > b { + return a + } + return b +} + func GenLabelForWidth(font *bdf.Font, text string, width, scale int) image.Image { var lines []string @@ -58,30 +65,43 @@ func GenLabelForWidth(font *bdf.Font, lines = append(lines, strings.TrimSuffix(line, "\r")) } - height := 0 - var rects []image.Rectangle - for _, line := range lines { + // Respect font ascent and descent so that there are gaps between lines. + rects := make([]image.Rectangle, len(lines)) + jumps := make([]int, len(lines)) + for i, line := range lines { r, _ := font.BoundString(line) - rects = append(rects, r) - height += r.Dy() * scale + rects[i] = r + + if i > 0 { + deficitD := font.Descent - rects[i-1].Max.Y + jumps[i] += max(0, deficitD) + deficitA := font.Ascent - (-r.Min.Y) + jumps[i] += max(0, deficitA) + } + } + + height := 0 + for i := range lines { + height += jumps[i] + rects[i].Dy() } - imgRect := image.Rect(0, 0, width, height) + imgRect := image.Rect(0, 0, width, height*scale) img := image.NewRGBA(imgRect) draw.Draw(img, imgRect, image.White, image.ZP, draw.Src) y := 0 - for i := 0; i < len(lines); i++ { + for i, line := range lines { textImg := image.NewRGBA(rects[i]) draw.Draw(textImg, rects[i], image.White, image.ZP, draw.Src) - font.DrawString(textImg, image.ZP, lines[i]) + font.DrawString(textImg, image.ZP, line) scaledImg := imgutil.Scale{Image: textImg, Scale: scale} scaledRect := scaledImg.Bounds() - target := image.Rect(0, y, imgRect.Max.X, imgRect.Max.Y) + y += jumps[i] + target := image.Rect(0, y*scale, imgRect.Max.X, imgRect.Max.Y) draw.Draw(img, target, &scaledImg, scaledRect.Min, draw.Src) - y += scaledRect.Dy() + y += rects[i].Dy() } return img } -- cgit v1.2.3-70-g09d2