Browse Source

label-tool: respect font ascent and descent

Also try to load the values from the BDF font file.
master
Přemysl Janouch 3 weeks ago
parent
commit
696ea89530
Signed by: Přemysl Janouch <p@janouch.name> GPG Key ID: A0420B94F92B9493
2 changed files with 44 additions and 24 deletions
  1. 14
    14
      bdf/bdf.go
  2. 30
    10
      label/label.go

+ 14
- 14
bdf/bdf.go View File

@@ -49,6 +49,8 @@ func (g *glyph) At(x, y int) color.Color {
49 49
 // Font represents a particular bitmap font.
50 50
 type Font struct {
51 51
 	Name     string
52
+	Ascent   int // needn't be present in the font
53
+	Descent  int // needn't be present in the font
52 54
 	glyphs   map[rune]glyph
53 55
 	fallback glyph
54 56
 }
@@ -192,17 +194,23 @@ func (p *bdfParser) readLine() bool {
192 194
 	return true
193 195
 }
194 196
 
195
-func (p *bdfParser) readCharEncoding() int {
197
+func (p *bdfParser) readIntegerArgument() int {
196 198
 	if len(p.tokens) < 2 {
197 199
 		panic("insufficient arguments")
198 200
 	}
199 201
 	if i, err := strconv.Atoi(p.tokens[1]); err != nil {
200 202
 		panic(err)
201 203
 	} else {
202
-		return i // Some fonts even use -1 for things outside the encoding.
204
+		return i
203 205
 	}
204 206
 }
205 207
 
208
+// Some fonts even use -1 for things outside the encoding.
209
+func (p *bdfParser) readCharEncoding() int { return p.readIntegerArgument() }
210
+
211
+// XXX: Ignoring vertical advance since we only expect purely horizontal fonts.
212
+func (p *bdfParser) readDwidth() int { return p.readIntegerArgument() }
213
+
206 214
 func (p *bdfParser) parseProperties() {
207 215
 	// The wording in the specification suggests that the argument
208 216
 	// with the number of properties to follow isn't reliable.
@@ -210,22 +218,14 @@ func (p *bdfParser) parseProperties() {
210 218
 		switch p.tokens[0] {
211 219
 		case "DEFAULT_CHAR":
212 220
 			p.defaultChar = p.readCharEncoding()
221
+		case "FONT_ASCENT":
222
+			p.font.Ascent = p.readIntegerArgument()
223
+		case "FONT_DESCENT":
224
+			p.font.Descent = p.readIntegerArgument()
213 225
 		}
214 226
 	}
215 227
 }
216 228
 
217
-// XXX: Ignoring vertical advance since we only expect purely horizontal fonts.
218
-func (p *bdfParser) readDwidth() int {
219
-	if len(p.tokens) < 2 {
220
-		panic("insufficient arguments")
221
-	}
222
-	if i, err := strconv.Atoi(p.tokens[1]); err != nil {
223
-		panic(err)
224
-	} else {
225
-		return i
226
-	}
227
-}
228
-
229 229
 func (p *bdfParser) readBBX() image.Rectangle {
230 230
 	if len(p.tokens) < 5 {
231 231
 		panic("insufficient arguments")

+ 30
- 10
label/label.go View File

@@ -51,6 +51,13 @@ func GenLabelForHeight(font *bdf.Font,
51 51
 	return combinedImg
52 52
 }
53 53
 
54
+func max(a, b int) int {
55
+	if a > b {
56
+		return a
57
+	}
58
+	return b
59
+}
60
+
54 61
 func GenLabelForWidth(font *bdf.Font,
55 62
 	text string, width, scale int) image.Image {
56 63
 	var lines []string
@@ -58,30 +65,43 @@ func GenLabelForWidth(font *bdf.Font,
58 65
 		lines = append(lines, strings.TrimSuffix(line, "\r"))
59 66
 	}
60 67
 
61
-	height := 0
62
-	var rects []image.Rectangle
63
-	for _, line := range lines {
68
+	// Respect font ascent and descent so that there are gaps between lines.
69
+	rects := make([]image.Rectangle, len(lines))
70
+	jumps := make([]int, len(lines))
71
+	for i, line := range lines {
64 72
 		r, _ := font.BoundString(line)
65
-		rects = append(rects, r)
66
-		height += r.Dy() * scale
73
+		rects[i] = r
74
+
75
+		if i > 0 {
76
+			deficitD := font.Descent - rects[i-1].Max.Y
77
+			jumps[i] += max(0, deficitD)
78
+			deficitA := font.Ascent - (-r.Min.Y)
79
+			jumps[i] += max(0, deficitA)
80
+		}
81
+	}
82
+
83
+	height := 0
84
+	for i := range lines {
85
+		height += jumps[i] + rects[i].Dy()
67 86
 	}
68 87
 
69
-	imgRect := image.Rect(0, 0, width, height)
88
+	imgRect := image.Rect(0, 0, width, height*scale)
70 89
 	img := image.NewRGBA(imgRect)
71 90
 	draw.Draw(img, imgRect, image.White, image.ZP, draw.Src)
72 91
 
73 92
 	y := 0
74
-	for i := 0; i < len(lines); i++ {
93
+	for i, line := range lines {
75 94
 		textImg := image.NewRGBA(rects[i])
76 95
 		draw.Draw(textImg, rects[i], image.White, image.ZP, draw.Src)
77
-		font.DrawString(textImg, image.ZP, lines[i])
96
+		font.DrawString(textImg, image.ZP, line)
78 97
 
79 98
 		scaledImg := imgutil.Scale{Image: textImg, Scale: scale}
80 99
 		scaledRect := scaledImg.Bounds()
81 100
 
82
-		target := image.Rect(0, y, imgRect.Max.X, imgRect.Max.Y)
101
+		y += jumps[i]
102
+		target := image.Rect(0, y*scale, imgRect.Max.X, imgRect.Max.Y)
83 103
 		draw.Draw(img, target, &scaledImg, scaledRect.Min, draw.Src)
84
-		y += scaledRect.Dy()
104
+		y += rects[i].Dy()
85 105
 	}
86 106
 	return img
87 107
 }

Loading…
Cancel
Save