fogleman / gg

Go Graphics - 2D rendering in Go with a simple API.
https://godoc.org/github.com/fogleman/gg
MIT License
4.43k stars 357 forks source link

DrawStringWrapped chinese not supported #91

Open u0x01 opened 4 years ago

u0x01 commented 4 years ago

DrawStringWrapped break line by english space currently, is possible break line by the word width?fontFace should able to return width of each word.

JesseGuoX commented 4 years ago

I thought it could auto break by word width, but it not.

JesseGuoX commented 4 years ago

@u0x01 By implement splieRune function and replace splitOnSpace in wrap.go, you can do it yourself.

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 splitRune(x string) []string {
    var result []string
    for _, c := range x {
        result = append(result, string(c))
    }
    return result
}

func wordWrap(m measureStringer, s string, width float64) []string {
    var result []string
    for _, line := range strings.Split(s, "\n") {
        //fields := splitOnSpace(line)
        fields := splitRune(line)
        if len(fields)%2 == 1 {
            fields = append(fields, "")
        }
        x := ""
        for i := 0; i < len(fields); i += 2 {
            w, _ := m.MeasureString(x + fields[i])
            if w > width {
                if x == "" {
                    result = append(result, fields[i])
                    x = ""
                    continue
                } else {
                    result = append(result, x)
                    x = ""
                }
            }
            x += fields[i] + fields[i+1]
        }
        if x != "" {
            result = append(result, x)
        }
    }
    for i, line := range result {
        result[i] = strings.TrimSpace(line)
    }
    return result
}
alecpetrosky commented 3 years ago

Hi! Are there any plan to add this implementation to the library?

alea12 commented 2 years ago

@JesseGuoX You saved my day! Although I had to slightly change splitRune like this:

func splitRune(x string) []string {
    var result []string
    for _, c := range strings.Split(x, "") {
        result = append(result, string(c))
    }
    return result
}

It might be nice to have wrapping options in DrawStringWrapped (and WordWrap), something like the word-break option you can find in CSS.