Watermark with "fogleman/gg"
Watermark with "fogleman/gg"
I stumbled into "fogleman/gg" yesterday and immediately seen it as a nice way to add watermark into my images. But I couldn't make ir work.
I started using "fogleman/gg/blob/master/examples/rotated-text.go" as boilerplate, but it seeans the dc.Rotate() do it with all the canvas and I couldn't center the text!
If course the idea is draw a diagonal text over the hypotenuse of the canvas. Exactly into the center.
When I draw the texto with 0 degrees rotarion it is on center. But if I only rotate 45 degrees, it's a mess.
Does anybody can help with that?
The intended steps are:
-
Get the image bounds and compute hypotenuse, and fit the most large text possible without get clipped out of canvas;
-
Create a canvas with transparent backgroud and draw the rotate (45º) text;
-
Save the new picture with a another name;
The step 2 is the tricky one at the moment!
@fogleman ?
Canvas rotated at 45 degress:

Canvas at 0 degress:

Draft souce code:
// https://github.com/fogleman/gg/blob/master/examples/rotated-text.go
// go build -v -ldflags "-s -w" -o rotated-text.exe rotated-text.go
//
package main
import (
"flag"
"fmt"
"os"
"os/exec"
"path/filepath"
//
// External packages:
//
"github.com/fogleman/gg"
"github.com/golang/freetype/truetype"
"golang.org/x/image/font/gofont/goregular"
)
// Execute a external process and return the process object, error object and full executable path
func Start(args ...string) (p *os.Process, err error, executable string) {
if args[0], err = exec.LookPath(args[0]); err == nil {
var procAttr os.ProcAttr
procAttr.Files = []*os.File{os.Stdin,
os.Stdout, os.Stderr}
p, err := os.StartProcess(args[0], args, &procAttr)
if err == nil {
return p, nil, args[0]
}
}
return nil, err, args[0]
}
func main() {
xPtr := flag.Int("x", -150, "Valor de X")
yPtr := flag.Int("y", 160, "Valor de Y")
rotatePtr := flag.Int("rotate", -45, "Angulo de rotação em graus")
fontSizePtr := flag.Int("fontSize", 32, "Tamanho da fonte")
sizePtr := flag.Int("size", 500, "Tamanho do Canvas (size x size)")
txtPtr := flag.String("text", "Willian & Simone", "Texto para imprimir")
viewerPtr := flag.String("viewer", "mspaint.exe", "Visualizador de imagem.")
imageFilePtr := flag.String("file", "rotated-text.go.png", "Arquivo para salvar a imagem")
bWaitViewer := flag.Bool("WaitViewer", false, "Wait the viewer to finish")
flag.Parse()
var S = *sizePtr
dc := gg.NewContext(S, S)
dc.SetRGB(1, 1, 1)
dc.Clear()
dc.SetRGB(0, 0, 0)
font, err := truetype.Parse(goregular.TTF)
if err != nil {
panic("truetype.Parse()")
}
face := truetype.NewFace(font, &truetype.Options{
Size: float64(*fontSizePtr),
})
dc.SetFontFace(face)
dc.Rotate(gg.Radians(float64(*rotatePtr))) // Left to Right and Up
var tx, ty float64
tx, ty = float64(*xPtr), float64(*yPtr)
text := *txtPtr
w, h := dc.MeasureString(text)
fmt.Printf("DEBUG> Text width is %v and height is %v.\n", w, h)
dc.DrawRectangle(0, 0, float64(S), float64(S))
dc.SetRGB(0, 0, 0)
dc.DrawRectangle(tx, ty, w, h)
dc.Stroke()
dc.DrawString(text, tx, ty-4+h)
dc.SavePNG(*imageFilePtr)
if len(*viewerPtr) > 0 {
process, err, executable := Start(*viewerPtr, *imageFilePtr)
if err != nil {
fmt.Printf("ERROR Unable to run \"%s %s\": %s\n", *viewerPtr, *imageFilePtr, err.Error())
} else {
imageFullPath, _ := filepath.Abs(*imageFilePtr)
fmt.Printf("Running as pid %d with \"%s %s\"\n", process.Pid, executable, imageFullPath)
if *bWaitViewer {
process.Wait()
}
}
}
}
/*
rotated-text.exe -rotate 0 -text "Willian & Simone" -size 500 -x 126 -y 234
Text width is 247 and height is 32.
x = 500 - 247 / 2
y = 500 - 32 / 2
rotated-text.exe -rotate -45 -text "Willian & Simone" -size 500 -x 126 -y 234
*/
you need to translate to the centre of the rotation
(below works, i think, but has changes other than just bug fix.)
package main
import (
"flag"
//"fmt"
"github.com/fogleman/gg"
"github.com/golang/freetype/truetype"
"golang.org/x/image/font/gofont/goregular"
)
func main() {
xPtr := flag.Int("x", 250, "Valor de X")
yPtr := flag.Int("y", 250, "Valor de Y")
rotatePtr := flag.Int("rotate", -45, "Angulo de rotação em graus")
fontSizePtr := flag.Int("fontSize", 32, "Tamanho da fonte")
sizePtr := flag.Int("size", 500, "Tamanho do Canvas (size x size)")
txtPtr := flag.String("text", "Willian & Simone", "Texto para imprimir")
imageFilePtr := flag.String("file", "rotated-text.go.png", "Arquivo para salvar a imagem")
flag.Parse()
dc := gg.NewContext(*sizePtr, *sizePtr)
dc.SetRGB(1, 1, 1)
dc.Clear()
font, err := truetype.Parse(goregular.TTF)
if err != nil {
panic("truetype.Parse()")
}
face := truetype.NewFace(font, &truetype.Options{
Size: float64(*fontSizePtr),
})
dc.SetFontFace(face)
dc.SetRGB(0, 0, 0)
// border inset 10px
dc.DrawRectangle(10, 10, float64(*sizePtr)-20, float64(*sizePtr)-20)
dc.Stroke()
dc.Translate(float64(*xPtr), float64(*yPtr))
dc.Rotate(gg.Radians(float64(*rotatePtr))) // Left to Right and Up
// does its own centring
dc.DrawStringAnchored(*txtPtr, 0, 0,.5,.5)
w, h := dc.MeasureString(*txtPtr)
// added border
dc.DrawRectangle(-w/2-10,-h/2, w+20, h+10)
dc.Stroke()
dc.SavePNG(*imageFilePtr)
}
also use alpha color...
dc.SetRGBA(1, 1, 1,100)
... for a transparent watermark
I'll check it later, after I get home!
Thank you!
Hi @splace,
I tested it and work!
I looks like a missed the detail in the documentation about the function DrawStringAnchored().
I started some test and now I'll look for a function group to save the canvas status (colors, etc.) and restore it after.
And ofcourse, add the code to read a existing image and apply the watermark at it center without compromised the original image & text.