images.Text: Add "alignx" option for horizontal alignment
Add an "alignx" option to the images.Text to control whether the value of the "x" option is the left border of the text (current behaviour), the center of each line or the right border. Fixes #10849
This commit is contained in:
parent
9cad8d38ca
commit
4a5cc2dd26
3 changed files with 57 additions and 13 deletions
|
@ -37,6 +37,10 @@ x
|
|||
y
|
||||
: (`int`) The vertical offset, in pixels, relative to the top of the image. Default is `10`.
|
||||
|
||||
alignx
|
||||
{{< new-in 0.141.0 >}}
|
||||
: (`string`) The horizontal alignment of the text relative to the `x` position. One of `left`, `center`, or `right`. Default is `left`.
|
||||
|
||||
[global resource]: /getting-started/glossary/#global-resource
|
||||
[page resource]: /getting-started/glossary/#page-resource
|
||||
[remote resource]: /getting-started/glossary/#remote-resource
|
||||
|
|
|
@ -69,6 +69,7 @@ func (*Filters) Text(text string, options ...any) gift.Filter {
|
|||
size: 20,
|
||||
x: 10,
|
||||
y: 10,
|
||||
alignx: "left",
|
||||
linespacing: 2,
|
||||
}
|
||||
|
||||
|
@ -87,6 +88,12 @@ func (*Filters) Text(text string, options ...any) gift.Filter {
|
|||
tf.x = cast.ToInt(v)
|
||||
case "y":
|
||||
tf.y = cast.ToInt(v)
|
||||
case "alignx":
|
||||
tf.alignx = cast.ToString(v)
|
||||
if tf.alignx != "left" && tf.alignx != "center" && tf.alignx != "right" {
|
||||
panic("alignx must be one of left, center, right")
|
||||
}
|
||||
|
||||
case "linespacing":
|
||||
tf.linespacing = cast.ToInt(v)
|
||||
case "font":
|
||||
|
|
|
@ -35,6 +35,7 @@ type textFilter struct {
|
|||
text string
|
||||
color color.Color
|
||||
x, y int
|
||||
alignx string
|
||||
size float64
|
||||
linespacing int
|
||||
fontSource hugio.ReadSeekCloserProvider
|
||||
|
@ -77,30 +78,62 @@ func (f textFilter) Draw(dst draw.Image, src image.Image, options *gift.Options)
|
|||
|
||||
gift.New().Draw(dst, src)
|
||||
|
||||
// Draw text, consider and include linebreaks
|
||||
maxWidth := dst.Bounds().Dx() - 20
|
||||
|
||||
var availableWidth int
|
||||
switch f.alignx {
|
||||
case "right":
|
||||
availableWidth = f.x
|
||||
case "center":
|
||||
availableWidth = min((maxWidth-f.x), f.x) * 2
|
||||
case "left":
|
||||
availableWidth = maxWidth - f.x
|
||||
}
|
||||
|
||||
fontHeight := face.Metrics().Ascent.Ceil()
|
||||
|
||||
// Calculate lines, consider and include linebreaks
|
||||
finalLines := []string{}
|
||||
f.text = strings.ReplaceAll(f.text, "\r", "")
|
||||
for _, line := range strings.Split(f.text, "\n") {
|
||||
currentLine := ""
|
||||
// Break each line at the maximum width.
|
||||
for _, str := range strings.Fields(line) {
|
||||
fieldStrWidth := font.MeasureString(face, str)
|
||||
currentLineStrWidth := font.MeasureString(face, currentLine)
|
||||
|
||||
if (currentLineStrWidth.Ceil() + fieldStrWidth.Ceil()) >= availableWidth {
|
||||
finalLines = append(finalLines, currentLine)
|
||||
currentLine = ""
|
||||
}
|
||||
currentLine += str + " "
|
||||
}
|
||||
finalLines = append(finalLines, currentLine)
|
||||
}
|
||||
|
||||
// Correct y position based on font and size
|
||||
f.y = f.y + fontHeight
|
||||
|
||||
// Start position
|
||||
y := f.y
|
||||
d.Dot = fixed.P(f.x, f.y)
|
||||
|
||||
// Draw text line by line, breaking each line at the maximum width.
|
||||
f.text = strings.ReplaceAll(f.text, "\r", "")
|
||||
for _, line := range strings.Split(f.text, "\n") {
|
||||
for _, str := range strings.Fields(line) {
|
||||
strWidth := font.MeasureString(face, str)
|
||||
if (d.Dot.X.Ceil() + strWidth.Ceil()) >= maxWidth {
|
||||
y = y + fontHeight + f.linespacing
|
||||
d.Dot = fixed.P(f.x, y)
|
||||
}
|
||||
d.DrawString(str + " ")
|
||||
// Draw text line by line
|
||||
for _, line := range finalLines {
|
||||
line = strings.TrimSpace(line)
|
||||
strWidth := font.MeasureString(face, line)
|
||||
var x int
|
||||
switch f.alignx {
|
||||
case "right":
|
||||
x = f.x - strWidth.Ceil()
|
||||
case "center":
|
||||
x = f.x - (strWidth.Ceil() / 2)
|
||||
|
||||
case "left":
|
||||
x = f.x
|
||||
}
|
||||
d.Dot = fixed.P(x, y)
|
||||
d.DrawString(line)
|
||||
y = y + fontHeight + f.linespacing
|
||||
d.Dot = fixed.P(f.x, y)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue