Closed ABetterCat closed 2 years ago
basically, it should just be a matter of playing with the alpha channel of the color you want to display your text.
ex:
func ExampleLabels_withOpacity() {
p := plot.New()
p.Title.Text = "Labels"
p.X.Min = -5
p.X.Max = +5
p.Y.Min = 0
p.Y.Max = +10
const N = 50
genXYs := func(n int) []plotter.XY {
o := make([]plotter.XY, n)
for i := range o {
o[i] = plotter.XY{X: 0, Y: 5}
}
return o
}
genLabels := func(n int) []string {
o := make([]string, n)
for i := range o {
o[i] = "OOOOOOOO"
}
return o
}
labels, err := plotter.NewLabels(plotter.XYLabels{
XYs: genXYs(N),
Labels: genLabels(N),
})
if err != nil {
log.Fatalf("could not creates labels plotter: %+v", err)
}
for i := range labels.TextStyle {
v := &labels.TextStyle[i]
v.Rotation = float64(i) * math.Pi / N
v.Font.Size = 20
var (
ir uint8
ig uint8
ib uint8
)
switch i % 3 {
case 0:
ir = 255
case 1:
ig = 255
case 2:
ib = 255
}
v.Color = color.RGBA{R: ir, G: ig, B: ib, A: 127}
}
p.Add(labels)
err = p.Save(10*vg.Centimeter, 10*vg.Centimeter, "testdata/labels_opacity.png")
if err != nil {
log.Fatalf("could not save plot: %+v", err)
}
}
does this help ?
Thanks for your reply.It helps me. I want to generate a watermark with a transparent background. I referred to your code. But I can't generate watermark on a png with transparent background.Can you give me an example?
like this ?
// An example of embedding an image in a plot with a watermark.
func ExampleImage_watermark() {
p := plot.New()
p.Title.Text = "A Logo w/ a watermark"
// load an image
f, err := os.Open("testdata/gopher.png")
if err != nil {
log.Fatalf("error opening image file: %v\n", err)
}
defer f.Close()
img, err := png.Decode(f)
if err != nil {
log.Fatalf("error decoding image file: %v\n", err)
}
p.Add(plotter.NewImage(img, 0, 0, 20, 20))
labels, err := plotter.NewLabels(plotter.XYLabels{
XYs: []plotter.XY{
{X: 5, Y: 5},
},
Labels: []string{"DRAFT"},
})
if err != nil {
log.Fatalf("could not creates labels plotter: %+v", err)
}
labels.TextStyle[0].Color = color.RGBA{R:255, A: 120}
labels.TextStyle[0].Rotation = math.Pi / 4
labels.TextStyle[0].Font.Size = vg.Points(60)
p.Add(labels)
const (
w = 10 * vg.Centimeter
h = 10 * vg.Centimeter
)
err = p.Save(w, h, "testdata/image_plot_watermark.png")
if err != nil {
log.Fatalf("error saving image plot: %v\n", err)
}
// Output:
}
or do you want the image itself being somewhat transparent ? and by image, do you mean a uniform color ? or a plain image like the logo I've shown above ?
I want the image itself being transparent totally.
And i want to write watermark on it.
---Original--- From: "Sebastien @.> Date: Fri, Aug 19, 2022 16:10 PM To: @.>; Cc: @.**@.>; Subject: Re: [gonum/plot] How to set transparency or opacity? (Issue #749)
or do you want the image itself being somewhat transparent ? and by image, do you mean a uniform color ? or a plain image like the logo I've shown above ?
— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you authored the thread.Message ID: @.***>
ok.
well, it's not possible to draw a transparent data image (ie: using the plotter.NewImage
scaffolding).
it is possible to use an image as background, though:
// An example of embedding an image in a plot with a watermark.
func ExampleImage_watermark2() {
p := plot.New()
p.BackgroundColor = color.NRGBA{B: 255, A: 120}
p.Title.Text = "A Logo w/ a watermark"
// load an image
f, err := os.Open("testdata/gopher.png")
if err != nil {
log.Fatalf("error opening image file: %v\n", err)
}
defer f.Close()
img, err := png.Decode(f)
if err != nil {
log.Fatalf("error decoding image file: %v\n", err)
}
c := vgimg.PngCanvas{vgimg.NewWith(
vgimg.UseBackgroundColor(color.Transparent),
vgimg.UseImage(img.(draw.Image)),
)}
labels, err := plotter.NewLabels(plotter.XYLabels{
XYs: []plotter.XY{
{X: 5, Y: 5},
},
Labels: []string{"DRAFT"},
})
if err != nil {
log.Fatalf("could not creates labels plotter: %+v", err)
}
labels.TextStyle[0].Color = color.RGBA{A: 100, R: 255}
labels.TextStyle[0].Rotation = math.Pi / 4
labels.TextStyle[0].Font.Size = vg.Points(60)
p.Add(labels)
p.Draw(vgdraw.New(c))
o, err := os.Create("testdata/image_plot_watermark2.png")
if err != nil {
log.Fatalf("could not create output file: %+v", err)
}
_, err = c.WriteTo(o)
if err != nil {
log.Fatalf("error saving image plot: %v\n", err)
}
err = o.Close()
if err != nil {
log.Fatalf("error closing image plot: %v\n", err)
}
// Output:
}
it's possible to draw transparent patches of colors with plotter.Image
, but not "plain" images:
// An example of embedding an image in a plot with a watermark.
func ExampleImage_watermark2() {
p := plot.New()
//p.BackgroundColor = color.NRGBA{B: 255, A: 120}
p.Title.Text = "A Logo w/ a watermark"
// load an image
f, err := os.Open("testdata/gopher.png")
if err != nil {
log.Fatalf("error opening image file: %v\n", err)
}
defer f.Close()
img, err := png.Decode(f)
if err != nil {
log.Fatalf("error decoding image file: %v\n", err)
}
c := vgimg.PngCanvas{vgimg.NewWith(
vgimg.UseBackgroundColor(color.Transparent),
)}
p.Add(plotter.NewImage(img, 0, 0, 20, 20))
{
img := image.NewRGBA(image.Rect(0, 0, 10, 10))
draw.Draw(img, img.Bounds(), image.NewUniform(color.RGBA{G: 255, A: 120}), image.Point{}, draw.Over)
p.Add(plotter.NewImage(img, 0, 0, 10, 10))
}
{
img := image.NewRGBA(image.Rect(0, 0, 10, 10))
draw.Draw(img, img.Bounds(), image.NewUniform(color.RGBA{B: 255, A: 120}), image.Point{}, draw.Over)
p.Add(plotter.NewImage(img, 5, 5, 15, 15))
}
if true {
f, err := os.Open("testdata/gopher_running.png")
if err != nil {
log.Fatalf("error opening image file: %v\n", err)
}
defer f.Close()
img, err := png.Decode(f)
if err != nil {
log.Fatalf("error decoding image file: %v\n", err)
}
p.Add(plotter.NewImage(img, 10, 10, 20, 20))
}
labels, err := plotter.NewLabels(plotter.XYLabels{
XYs: []plotter.XY{
{X: 5, Y: 5},
},
Labels: []string{"DRAFT"},
})
if err != nil {
log.Fatalf("could not creates labels plotter: %+v", err)
}
labels.TextStyle[0].Color = color.RGBA{A: 100, R: 255}
labels.TextStyle[0].Rotation = math.Pi / 4
labels.TextStyle[0].Font.Size = vg.Points(60)
p.Add(labels)
p.Draw(vgdraw.New(c))
o, err := os.Create("testdata/image_plot_watermark3.png")
if err != nil {
log.Fatalf("could not create output file: %+v", err)
}
_, err = c.WriteTo(o)
if err != nil {
log.Fatalf("error saving image plot: %v\n", err)
}
err = o.Close()
if err != nil {
log.Fatalf("error closing image plot: %v\n", err)
}
// Output:
}
without the running gopher:
with the running gopher:
to achieve this, we'd have to either introduce a new method to vg.Canvas
, like:
DrawImageMask(rect vg.Rectangle, img image.Image, mask image.Image, mp vg.Point)
or add some state/context to specify the mask + mask offset.
(or just modify DrawImage
signature to have the same than above, documenting that if mask==nil
, no mask should be applied)
@kortschak WDYT ?
If the alpha of the image obtained from the png file is appropriately adjusted, it will be transparent. I don't think there is anything that we need to do here.
Adjusted externally, but demonstrated with this
here is an example:
// An example of embedding an image in a plot with a watermark.
func ExampleImage_watermark() {
p := plot.New()
p.Title.Text = "A Logo w/ a watermark"
// load an image
f, err := os.Open("testdata/gopher.png")
if err != nil {
log.Fatalf("error opening image file: %v\n", err)
}
defer f.Close()
img, err := png.Decode(f)
if err != nil {
log.Fatalf("error decoding image file: %v\n", err)
}
p.Add(
plotter.NewImage(img, 0, 0, 20, 20),
plotter.NewImage(image.NewUniform(color.RGBA{G: 255, A: 120}), 0, 0, 10, 10),
plotter.NewImage(image.NewUniform(color.RGBA{B: 255, A: 120}), 5, 5, 15, 15),
)
{
f, err := os.Open("testdata/gopher_running.png")
if err != nil {
log.Fatalf("error opening image file: %v\n", err)
}
defer f.Close()
src, err := png.Decode(f)
if err != nil {
log.Fatalf("error decoding image file: %v\n", err)
}
img := src.(*image.NRGBA)
bnd := img.Bounds()
for iy := 0; iy < bnd.Dy(); iy++ {
for ix := 0; ix < bnd.Dx(); ix++ {
r, g, b, _ := img.At(ix, iy).RGBA()
img.SetNRGBA(ix, iy, color.NRGBA{uint8(r), uint8(g), uint8(b), 120})
}
}
p.Add(plotter.NewImage(img, 10, 10, 20, 20))
}
labels, err := plotter.NewLabels(plotter.XYLabels{
XYs: []plotter.XY{
{X: 5, Y: 5},
},
Labels: []string{"DRAFT"},
})
if err != nil {
log.Fatalf("could not creates labels plotter: %+v", err)
}
labels.TextStyle[0].Color = color.RGBA{A: 100, R: 255}
labels.TextStyle[0].Rotation = math.Pi / 4
labels.TextStyle[0].Font.Size = vg.Points(60)
p.Add(labels)
err = p.Save(10*vg.Centimeter, 10*vg.Centimeter, "testdata/image_plot_watermark.png")
if err != nil {
log.Fatalf("error saving image plot: %v\n", err)
}
// Output:
}
closing as solved.
When saving,it spends long time. And It never saved a png file.
I mean when i use a total transparent png as the background, it output a white background image.
Code?
I refered to the example
package main
import (
"bytes"
"fmt"
"gonum.org/v1/plot/font"
"gonum.org/v1/plot/font/liberation"
"strings"
"io/ioutil"
"os"
"path"
"math"
"math/rand"
"time"
"image"
"image/color"
"image/draw"
"image/jpeg"
"image/png"
"gonum.org/v1/plot/vg"
"gonum.org/v1/plot/vg/vgimg"
)
func init() {
rand.Seed(time.Now().UnixNano())
}
// WaterMark for adding a watermark on the image
func WaterMark(img image.Image, markText string) (image.Image, error) {
// image's length to canvas's length
bounds := img.Bounds()
w := vg.Length(bounds.Max.X) * vg.Inch / vgimg.DefaultDPI
h := vg.Length(bounds.Max.Y) * vg.Inch / vgimg.DefaultDPI
diagonal := vg.Length(math.Sqrt(float64(w*w + h*h)))
// create a canvas, which width and height are diagonal
c := vgimg.New(diagonal, diagonal)
// draw image on the center of canvas
rect := vg.Rectangle{}
rect.Min.X = diagonal/2 - w/2
rect.Min.Y = diagonal/2 - h/2
rect.Max.X = diagonal/2 + w/2
rect.Max.Y = diagonal/2 + h/2
c.DrawImage(rect, img)
cache := font.NewCache(liberation.Collection())
face := cache.Lookup(font.Font{Typeface: "Courier", Variant: "Serif"}, vg.Inch*0.15)
// repeat the markText
markTextWidth := face.Width(markText)
// 空格
space := ""
for i := 0; i < len(markText); i++ {
space += strings.Repeat(" ", 2)
}
unitText := markText
for markTextWidth <= diagonal {
markText += space + unitText
markTextWidth = face.Width(markText)
}
// set the color of markText
//c.SetColor(color.RGBA{225, 225, 225, 100})
c.SetColor(color.RGBA{128, 42, 42, 100})
// set a random angle between 0 and π/2
//θ := math.Pi * rand.Float64() / 2
c.Rotate(45)
// set the lineHeight and add the markText
//lineHeight := fontStyle.Extents().Height * 4
lineHeight := face.Extents().Height *8
n:=0
for offset := -2 * diagonal; offset < 2*diagonal; offset += lineHeight {
sss := addSpace(ifSpace(n), space)
m :=sss + markText
c.FillString(face, vg.Point{X: 0, Y: offset}, m)
n += 1
}
jc := vgimg.PngCanvas{Canvas: c}
buff := new(bytes.Buffer)
jc.WriteTo(buff)
img, _, err := image.Decode(buff)
if err != nil {
return nil, err
}
// get the center point of the image
ctp := int(diagonal * vgimg.DefaultDPI / vg.Inch / 2)
// cutout the marked image
size := bounds.Size()
bounds = image.Rect(ctp-size.X/2, ctp-size.Y/2, ctp+size.X/2, ctp+size.Y/2)
rv := image.NewRGBA(bounds)
draw.Draw(rv, bounds, img, bounds.Min, draw.Src)
return rv, nil
}
func ifSpace(n int) bool {
if n %2 == 1{
return true
}
return false
}
func addSpace(ifSpace bool, space string) string{
if ifSpace {
return space
}
return ""
}
// MarkingPicture for marking picture with text
func MarkingPicture(filepath, text string) (image.Image, error) {
f, err := os.Open(filepath)
if err != nil {
return nil, err
}
defer f.Close()
img, _, err := image.Decode(f)
if err != nil {
return nil, err
}
img, err = WaterMark(img, text)
if err != nil {
return nil, err
}
return img, nil
}
func writeTo(img image.Image, ext string) (rv *bytes.Buffer, err error) {
ext = strings.ToLower(ext)
rv = new(bytes.Buffer)
switch ext {
case ".jpg", ".jpeg":
err = jpeg.Encode(rv, img, &jpeg.Options{Quality: 100})
case ".png":
err = png.Encode(rv, img)
}
return rv, err
}
func main() {
text := "abc"
if stat, err := os.Stat(target); err == nil && stat.IsDir() {
files, _ := ioutil.ReadDir(target)
for _, fn := range files {
img, err := MarkingPicture(path.Join(target, fn.Name()), text)
if err != nil {
continue
}
ext := path.Ext(fn.Name())
base := strings.Split(fn.Name(), ".")[0] + "_marked"
f, err := os.Create(base + ext)
if err != nil {
panic(err)
}
buff, err := writeTo(img, ext)
if err != nil {
panic(err)
}
if _, err = buff.WriteTo(f); err != nil {
panic(err)
}
}
} else {
img, err := MarkingPicture(target, text)
if err != nil {
panic(err)
}
ext := path.Ext(target)
base := strings.Split(path.Base(target), ".")[0] + "_marked"
f, err := os.Create(base + ext)
if err != nil {
panic(err)
}
buff, err := writeTo(img, ext)
if err != nil {
panic(err)
}
if _, err = buff.WriteTo(f); err != nil {
panic(err)
}
}
}
Here is my png.
well, with the following code:
//go:build ignore
package main
import (
"bytes"
"image"
"image/color"
"image/draw"
"image/jpeg"
"image/png"
"io/ioutil"
"math"
"math/rand"
"os"
"path"
"strings"
"time"
"gonum.org/v1/plot/font"
"gonum.org/v1/plot/font/liberation"
"gonum.org/v1/plot/vg"
"gonum.org/v1/plot/vg/vgimg"
)
func init() {
rand.Seed(time.Now().UnixNano())
}
// WaterMark for adding a watermark on the image
func WaterMark(img image.Image, markText string) (image.Image, error) {
// image's length to canvas's length
bounds := img.Bounds()
w := vg.Length(bounds.Max.X) * vg.Inch / vgimg.DefaultDPI
h := vg.Length(bounds.Max.Y) * vg.Inch / vgimg.DefaultDPI
diagonal := vg.Length(math.Sqrt(float64(w*w + h*h)))
// create a canvas, which width and height are diagonal
c := vgimg.New(diagonal, diagonal)
// draw image on the center of canvas
rect := vg.Rectangle{}
rect.Min.X = diagonal/2 - w/2
rect.Min.Y = diagonal/2 - h/2
rect.Max.X = diagonal/2 + w/2
rect.Max.Y = diagonal/2 + h/2
c.DrawImage(rect, img)
cache := font.NewCache(liberation.Collection())
face := cache.Lookup(font.Font{Typeface: "Courier", Variant: "Serif"}, vg.Inch*0.15)
// repeat the markText
markTextWidth := face.Width(markText)
space := ""
for i := 0; i < len(markText); i++ {
space += strings.Repeat(" ", 2)
}
unitText := markText
for markTextWidth <= diagonal {
markText += space + unitText
markTextWidth = face.Width(markText)
}
// set the color of markText
//c.SetColor(color.RGBA{225, 225, 225, 100})
c.SetColor(color.RGBA{128, 42, 42, 100})
// set a random angle between 0 and π/2
//θ := math.Pi * rand.Float64() / 2
c.Rotate(45)
// set the lineHeight and add the markText
//lineHeight := fontStyle.Extents().Height * 4
lineHeight := face.Extents().Height * 8
n := 0
for offset := -2 * diagonal; offset < 2*diagonal; offset += lineHeight {
sss := addSpace(ifSpace(n), space)
m := sss + markText
c.FillString(face, vg.Point{X: 0, Y: offset}, m)
n += 1
}
jc := vgimg.PngCanvas{Canvas: c}
buff := new(bytes.Buffer)
_, err := jc.WriteTo(buff)
if err != nil {
return nil, err
}
img, _, err = image.Decode(buff)
if err != nil {
return nil, err
}
// get the center point of the image
ctp := int(diagonal * vgimg.DefaultDPI / vg.Inch / 2)
// cutout the marked image
size := bounds.Size()
bounds = image.Rect(ctp-size.X/2, ctp-size.Y/2, ctp+size.X/2, ctp+size.Y/2)
rv := image.NewRGBA(bounds)
draw.Draw(rv, bounds, img, bounds.Min, draw.Src)
return rv, nil
}
func ifSpace(n int) bool {
if n%2 == 1 {
return true
}
return false
}
func addSpace(ifSpace bool, space string) string {
if ifSpace {
return space
}
return ""
}
// MarkingPicture for marking picture with text
func MarkingPicture(filepath, text string) (image.Image, error) {
f, err := os.Open(filepath)
if err != nil {
return nil, err
}
defer f.Close()
img, _, err := image.Decode(f)
if err != nil {
return nil, err
}
img, err = WaterMark(img, text)
if err != nil {
return nil, err
}
return img, nil
}
func writeTo(img image.Image, ext string) (rv *bytes.Buffer, err error) {
ext = strings.ToLower(ext)
rv = new(bytes.Buffer)
switch ext {
case ".jpg", ".jpeg":
err = jpeg.Encode(rv, img, &jpeg.Options{Quality: 100})
case ".png":
err = png.Encode(rv, img)
}
return rv, err
}
func main() {
text := "abc"
target := "./plotter/testdata/gopher.png"
if stat, err := os.Stat(target); err == nil && stat.IsDir() {
files, _ := ioutil.ReadDir(target)
for _, fn := range files {
img, err := MarkingPicture(path.Join(target, fn.Name()), text)
if err != nil {
continue
}
ext := path.Ext(fn.Name())
base := strings.Split(fn.Name(), ".")[0] + "_marked"
f, err := os.Create(base + ext)
if err != nil {
panic(err)
}
buff, err := writeTo(img, ext)
if err != nil {
panic(err)
}
if _, err = buff.WriteTo(f); err != nil {
panic(err)
}
}
} else {
img, err := MarkingPicture(target, text)
if err != nil {
panic(err)
}
ext := path.Ext(target)
base := strings.Split(path.Base(target), ".")[0] + "_marked"
f, err := os.Create(base + ext)
if err != nil {
panic(err)
}
buff, err := writeTo(img, ext)
if err != nil {
panic(err)
}
if _, err = buff.WriteTo(f); err != nil {
panic(err)
}
}
}
I got this:
that said, if you don't need the plotting features of gonum/plot
(and "just" need to watermark an already existing image), perhaps another package might better suit your needs.
https://github.com/fogleman/gg comes to mind (even if it does sound a bit unmaintained)
How to set transparency or opacity of font?