]> git.maquefel.me Git - brevno-suite/hugo/commitdiff
images.Text: Add "alignx" option for horizontal alignment
authorJulius Künzel <julius.kuenzel@kde.org>
Mon, 6 Jan 2025 19:31:18 +0000 (20:31 +0100)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Wed, 8 Jan 2025 16:23:46 +0000 (17:23 +0100)
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

docs/content/en/functions/images/Text.md
resources/images/filters.go
resources/images/text.go

index 8c6670d422ddf8033d79a3ac048a7024ba0aee05..6a18468b7466b8dc64ed5d479096b69514ba9ef0 100644 (file)
@@ -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
index 0a620716d99955df47681aaa3f2198ffc0520b92..99fecdf20d773a4e15a2cbf8aa6111599647baad 100644 (file)
@@ -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":
index c1abc60bd434c57233b146bc0d7eef793ea5ff47..324878839872c59e5b14a3f1eacd6dc982a9d821 100644 (file)
@@ -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)
        }
 }