diff --git a/context.go b/context.go index c2e917e..b09e590 100644 --- a/context.go +++ b/context.go @@ -504,6 +504,14 @@ func (dc *Context) DrawStringAnchored(s string, x, y, ax, ay float64) { d.DrawString(s) } +func (dc *Context) DrawStringWrapped(s string, x, y, w float64) { + lines := wordWrap(dc, s, w) + for _, line := range lines { + dc.DrawStringAnchored(line, x, y, 0, 0) + y += dc.fontHeight * 1.5 + } +} + // MeasureString returns the rendered width and height of the specified text // given the current font face. func (dc *Context) MeasureString(s string) (w, h float64) { diff --git a/examples/lorem.go b/examples/lorem.go index 07d052a..a252417 100644 --- a/examples/lorem.go +++ b/examples/lorem.go @@ -2,14 +2,12 @@ package main import "github.com/fogleman/gg" -var lines = []string{ - "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod", - "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,", - "quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo", - "consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse", - "cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat", - "non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", -} +var line = ("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod" + + "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam," + + "quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo" + + "consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse" + + "cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat" + + "non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. ") func main() { const W = 800 @@ -18,11 +16,7 @@ func main() { dc.SetRGB(1, 1, 1) dc.Clear() dc.SetRGB(0, 0, 0) - // dc.LoadFontFace("/Library/Fonts/Arial.ttf", 18) - const h = 24 - for i, line := range lines { - y := H/2 - h*len(lines)/2 + i*h - dc.DrawStringAnchored(line, 400, float64(y), 0.5, 0.5) - } + dc.LoadFontFace("/Library/Fonts/Arial.ttf", 18) + dc.DrawStringWrapped(line, 20, 20, W-40) dc.SavePNG("out.png") } diff --git a/wrap.go b/wrap.go new file mode 100644 index 0000000..0f2fcbd --- /dev/null +++ b/wrap.go @@ -0,0 +1,61 @@ +package gg + +import ( + "strings" + "unicode" +) + +type measureStringer interface { + MeasureString(s string) (w, h float64) +} + +func splitOnSpace(x string) []string { + var result []string + pi := 0 + ps := false + for i, c := range x { + s := unicode.IsSpace(c) + if s != ps && i > 0 { + result = append(result, x[pi:i]) + pi = i + } + ps = s + } + result = append(result, x[pi:]) + return result +} + +func wordWrap(m measureStringer, s string, width float64) []string { + var result []string + for _, line := range strings.Split(s, "\n") { + fields := splitOnSpace(line) + widths := make([]float64, len(fields)) + for i, field := range fields { + widths[i], _ = m.MeasureString(field) + } + start := 0 + total := 0.0 + for i := 0; i < len(fields); i += 2 { + if total+widths[i] > width { + if i == start { + end := i + 2 + result = append(result, strings.Join(fields[start:end], "")) + start, total = end, 0 + continue + } else { + end := i + result = append(result, strings.Join(fields[start:end], "")) + start, total = end, 0 + } + } + total += widths[i] + widths[i+1] + } + if start < len(fields) { + result = append(result, strings.Join(fields[start:], "")) + } + } + for i, line := range result { + result[i] = strings.TrimSpace(line) + } + return result +}