pigfox
pigfox

Reputation: 1401

Dynamic text on image

I have an application that creates a dynamic image and writes text on it. The English language text works as advertised but other languages fail completely. The letters become boxes, etc.

package main

import (
    "errors"
    "fmt"
    "image"
    "image/color"
    "image/png"
    "math"
    "os"

    "github.com/fogleman/gg"
    guuid "github.com/google/uuid"

    "github.com/jimlawless/whereami"
)

type TextImage struct {
    BgImgPath string
    FontPath  string
    FontSize  float64
    Text      string
}

var sentence = make(map[string]string)
var language string

func init() {
    sentence["arabic"] = "قفز الثعلب البني فوق الكلب الكسول."
    sentence["english"] = "The brown fox jumped over the lazy dog."
    sentence["hebrew"] = "השועל החום קפץ מעל הכלב העצלן."
    sentence["hindi"] = "भूरी लोमड़ी आलसी कुत्ते के ऊपर से कूद गई।."
    sentence["greek"] = "Η καφέ αλεπού πήδηξε πάνω από το τεμπέλικο σκυλί."
}

func main() {
    language = "greek"
    uuid := genUUID()
    createFolder(uuid)
    createImage(len(sentence[language]), uuid)
    writeImage(sentence[language], uuid)
}

func genUUID() string {
    return guuid.New().String()
}

func createFolder(p string) {
    path := "./tmp/" + p
    if _, err := os.Stat(path); errors.Is(err, os.ErrNotExist) {
        err := os.MkdirAll(path, os.ModePerm)
        if err != nil {
            fmt.Println(err.Error() + " @ " + whereami.WhereAmI())
        }
    }
}

func writeImage(text string, path string) {
    ti := TextImage{
        BgImgPath: "./tmp/" + path + "/" + language + ".png",
        FontPath:  "./ttf/PlayfairDisplay-Regular.ttf",
        FontSize:  24,
        Text:      text,
    }
    img, err := textOnImg(ti)
    if err != nil {
        fmt.Println(err.Error() + " @ " + whereami.WhereAmI())
    }
    err = saveImage(img, "./tmp/"+path+"/"+language+".png")
    if err != nil {
        fmt.Println(err.Error() + " @ " + whereami.WhereAmI())
    }
}

func createImage(textlength int, path string) {
    minDim := 300
    scale := 30
    dim := math.Sqrt(float64(textlength))
    width := int(dim) * scale
    height := int(dim) * scale

    if width < minDim || height < minDim {
        width = minDim
        height = minDim
    }

    upLeft := image.Point{0, 0}
    lowRight := image.Point{width, height}

    img := image.NewRGBA(image.Rectangle{upLeft, lowRight})
    //img.Bounds()
    white := color.RGBA{255, 255, 255, 0xff}

    // Set color for each pixel.
    for x := 0; x < width; x++ {
        for y := 0; y < height; y++ {
            switch {
            case x < width/2 && y < height/2: // upper left quadrant
                img.Set(x, y, white)
            case x >= width/2 && y >= height/2: // lower right quadrant
                img.Set(x, y, color.White)
            default:
                img.Set(x, y, color.White)
            }
        }
    }

    f, err := os.Create("./tmp/" + path + "/" + language + ".png")
    if err != nil {
        fmt.Println(err.Error() + " @ " + whereami.WhereAmI())
    }
    err = png.Encode(f, img)
    if err != nil {
        fmt.Println(err.Error() + " @ " + whereami.WhereAmI())
    }
}

func deleteFolder(folder string) {
    err := os.RemoveAll("./tmp/" + folder)
    if err != nil {
        fmt.Println(err.Error() + " @ " + whereami.WhereAmI())
    }
}

func textOnImg(ti TextImage) (image.Image, error) {
    bgImage, err := gg.LoadImage(ti.BgImgPath)
    if err != nil {
        fmt.Println(err.Error() + " @ " + whereami.WhereAmI())
        return nil, err
    }
    imgWidth := bgImage.Bounds().Dx()
    imgHeight := bgImage.Bounds().Dy()

    dc := gg.NewContext(imgWidth, imgHeight)
    dc.DrawImage(bgImage, 0, 0)

    if err := dc.LoadFontFace(ti.FontPath, ti.FontSize); err != nil {
        fmt.Println(err.Error() + " @ " + whereami.WhereAmI())
        return nil, err
    }

    x := float64(imgWidth / 2)
    y := float64((imgHeight / 2) - 80)
    maxWidth := float64(imgWidth) - 60.0
    dc.SetColor(color.Black)
    fmt.Println(ti.Text)
    dc.DrawStringWrapped(ti.Text, x, y, 0.5, 0.5, maxWidth, 1.5, gg.AlignLeft)

    return dc.Image(), nil
}

func saveImage(img image.Image, path string) error {
    if err := gg.SavePNG(path, img); err != nil {
        fmt.Println(err.Error() + " @ " + whereami.WhereAmI())
        return err
    }
    return nil
}

Any recommendations how to fix this?

Upvotes: 0

Views: 461

Answers (1)

AJR
AJR

Reputation: 1671

I changed one line (as @dmitry suggested) and got it to work (Windows):

        FontPath: "C:/Windows/Fonts/arial.ttf",

BTW you can use a map literal instead of the init() call.

var sentence = map[string]string{
    "arabic":  "قفز الثعلب البني فوق الكلب الكسول.",
    "english": "The brown fox jumped over the lazy dog.",
    "hebrew":  "השועל החום קפץ מעל הכלב העצלן.",
    "hindi":   "भूरी लोमड़ी आलसी कुत्ते के ऊपर से कूद गई।.",
    "greek":   "Η καφέ αλεπού πήδηξε πάνω από το τεμπέλικο σκυλί.",
}

Upvotes: 2

Related Questions