Last active
February 8, 2023 06:48
-
-
Save linw1995/41e103f29e7dd97679c577a6f4830be8 to your computer and use it in GitHub Desktop.
Using golang to mark the picture
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bytes" | |
"fmt" | |
"strings" | |
"io/ioutil" | |
"os" | |
"path" | |
"math" | |
"math/rand" | |
"time" | |
"image" | |
"image/color" | |
"image/draw" | |
"image/jpeg" | |
"image/png" | |
"github.com/gonum/plot/vg" | |
"github.com/gonum/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) | |
// make a fontStyle, which width is vg.Inch * 0.7 | |
fontStyle, _ := vg.MakeFont("Courier", vg.Inch*0.7) | |
// repeat the markText | |
markTextWidth := fontStyle.Width(markText) | |
unitText := markText | |
for markTextWidth <= diagonal { | |
markText += " " + unitText | |
markTextWidth = fontStyle.Width(markText) | |
} | |
// set the color of markText | |
c.SetColor(color.RGBA{0, 0, 0, 122}) | |
// set a random angle between 0 and π/2 | |
θ := math.Pi * rand.Float64() / 2 | |
c.Rotate(θ) | |
// set the lineHeight and add the markText | |
lineHeight := fontStyle.Extents().Height * 1 | |
for offset := -2 * diagonal; offset < 2*diagonal; offset += lineHeight { | |
c.FillString(fontStyle, vg.Point{X: 0, Y: offset}, markText) | |
} | |
// canvas writeto jpeg | |
// canvas.img is private | |
// so use a buffer to transfer | |
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 | |
} | |
// 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() { | |
if len(os.Args) < 3 { | |
panic(fmt.Errorf("Please using like this:$ %s [file or directory] [text]", os.Args[0])) | |
} | |
target := os.Args[1] | |
text := os.Args[2] | |
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) | |
} | |
} | |
} |
我使用的是0.11的plot
import (
"gonum.org/v1/plot/font"
"gonum.org/v1/plot/font/liberation"
"gonum.org/v1/plot/vg"
"gonum.org/v1/plot/vg/vgimg"
)
WaterMark方法修改如下, 从第7行开始:
// 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)
// make a fontStyle, which width is vg.Inch
fontStyle, _ := vg.MakeFont("Courier", vg.Inch)
var cache = font.NewCache(liberation.Collection())
var ft = cache.Lookup(font.Font{Typeface: "Courier", Variant: "Sans"}, vg.Inch)
// repeat the markText
markTextWidth := fontStyle.Width(markText)
unitText := markText
for markTextWidth <= 1.5*diagonal {
markText += " " + unitText
markTextWidth = fontStyle.Width(markText)
}
// set the color of markText
c.SetColor(color.RGBA{0, 0, 0, 122})
// set a random angle between 0 and π/2
θ := math.Pi * rand.Float64() / 2
c.Rotate(θ)
// set the lineHeight and add the markText
lineHeight := fontStyle.Extents().Height * 1.2
for offset := -2 * diagonal; offset < 2*diagonal; offset += lineHeight {
c.FillString(ft, vg.Point{X: 0, Y: offset}, markText)
}
// canvas writeto jpeg
// canvas.img is private
// so use a buffer to transfer
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
亲测有效
"gonum.org/v1/plot/vg" 用v0.8.1
增加支持中文字体,字体文件为PingFang SC Medium.ttf
package main
import (
"bytes"
"flag"
"fmt"
"github.com/golang/freetype/truetype"
"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) {
// custom font
var fontName = flag.String("font", "Courier", "Name of the font to use")
ttfBytes, err := ioutil.ReadFile("PingFang SC Medium.ttf")
fi, err := truetype.Parse(ttfBytes)
vg.AddFont(*fontName, fi)
//f, err := freetype.ParseFont(ttfBytes)
//vg.AddFont(*fontName, f)
// 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)
// make a fontStyle, which width is vg.Inch * 0.7
//fontStyle, _ := vg.MakeFont("Courier", vg.Inch*0.7)
fontStyle, _ := vg.MakeFont(*fontName, vg.Inch*0.4)
// repeat the markText
//markTextWidth := fontStyle.Width(markText)
//unitText := markText
//for markTextWidth <= diagonal {
// markText += " " + unitText
// markTextWidth = fontStyle.Width(markText)
//}
// set the color of markText
c.SetColor(color.RGBA{0, 0, 0, 122})
// set a random angle between 0 and π/2
//r := math.Pi * rand.Float64() / 2
//c.Rotate(r)
// set the lineHeight and add the markText
//lineHeight := fontStyle.Extents().Height * 1
//for offset := -2 * diagonal; offset < 2*diagonal; offset += lineHeight {
// c.FillString(fontStyle, vg.Point{X: 0, Y: offset}, markText)
//}
c.FillString(fontStyle, vg.Point{X: 200, Y: 400}, markText)
// canvas writeto jpeg
// canvas.img is private
// so use a buffer to transfer
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
}
// 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() {
if len(os.Args) < 3 {
panic(fmt.Errorf("Please using like this:$ %s [file or directory] [text]", os.Args[0]))
}
target := os.Args[1]
text := os.Args[2]
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)
}
}
}
您好,请问不透明度怎么调
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
你好,现在这个包没有此方法了,请问是哪个?这是报错undefined: vg.MakeFont