Measure DrawWrappedString
Any way to measure a wrapped string before drawing? I'd like to reduce font size until it's smaller than Y.
@naikrovek It looks like I can combine lines := dc.WordWrap(s, width) with MeasureMultilineString and get what I want. Thanks!
I got this working how I wanted! Thanks for the pointer. For posterity, here is my full code for generating a fixed size image with a multiline string, with that string vertically centered and left aligned. It also does a loop to find a font size that fits the width.
package imagebuilder
import (
"bytes"
"image/color"
"github.com/gregpassmore/cookthebooks/kitchen/env"
"github.com/fogleman/gg"
)
const (
coverWidth = 480
coverHeight = 640
coverPadding = 16
)
func BuildCoverImage(bookTitle string) ([]byte, error) {
const W = coverWidth
const H = coverHeight
const P = coverPadding
dc := gg.NewContext(W, H)
bgColor := chooseBackgroundColor()
dc.SetColor(bgColor)
dc.DrawRectangle(0, 0, W, H)
dc.Fill()
dc.SetRGB(0, 0, 0)
font := chooseFont()
var yPad float64 = P
var fontSize float64 = 96
var width float64 = W - (P * 2)
lineSpacing := 1.5
for {
if fontSize < 32 {
break
}
if err := dc.LoadFontFace(font, fontSize); err != nil {
panic(err)
}
stringLines := dc.WordWrap(bookTitle, width)
mls := ""
for i, sl := range stringLines {
mls = mls + sl
if i != len(stringLines)-1 {
mls = mls + "\n"
}
}
sw, sh := dc.MeasureMultilineString(mls, lineSpacing)
verticalSpace := H - sh
if verticalSpace/2 > P {
yPad = verticalSpace / 2
}
if sw < W-(2*P) {
break
}
fontSize = fontSize - 8
}
dc.DrawStringWrapped(bookTitle, P, yPad, 0.0, 0.0, width, lineSpacing, gg.AlignLeft)
buffer := bytes.Buffer{}
err := dc.EncodePNG(&buffer)
if err != nil {
return nil, err
}
return buffer.Bytes(), nil
}
func chooseFont() string {
return env.ProjectDir.Get() + "/resources/fonts/BebasNeue-Regular.ttf"
}
func chooseBackgroundColor() color.Color {
return color.RGBA{R: 255, G: 182, B: 193, A: 255}
}
It might be nice to provide a function that does the "MeasureWrappedString" since there is a draw func for it, its a bit of a dance to get it done as-is. I could do a PR if there is interest in this.
It might be nice to provide a function that does the "MeasureWrappedString" since there is a draw func for it, its a bit of a dance to get it done as-is. I could do a PR if there is interest in this.
There's interest, but I guess it's a bit late already (?)