gg icon indicating copy to clipboard operation
gg copied to clipboard

Watermark with "fogleman/gg"

Open WillianBR opened this issue 2 years ago • 4 comments

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:

  1. Get the image bounds and compute hypotenuse, and fit the most large text possible without get clipped out of canvas;

  2. Create a canvas with transparent backgroud and draw the rotate (45º) text;

  3. Save the new picture with a another name;

The step 2 is the tricky one at the moment!

@fogleman ?

Canvas rotated at 45 degress:

rotated-text 45-degrees

Canvas at 0 degress:

rotated-text 0-degrees

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
*/


WillianBR avatar Feb 11 '23 17:02 WillianBR

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)

}

splace avatar Feb 20 '23 01:02 splace

also use alpha color... dc.SetRGBA(1, 1, 1,100) ... for a transparent watermark

splace avatar Feb 20 '23 01:02 splace

I'll check it later, after I get home!

Thank you!

WillianBR avatar Feb 24 '23 16:02 WillianBR

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.

WillianBR avatar Feb 26 '23 13:02 WillianBR