因为工作需要把一批图片按照样机处理成固定的样子,就用 golang 写了一个小脚本来处理
package main
import (
"flag"
"fmt"
"github.com/nfnt/resize"
"image"
"image/draw"
"image/jpeg"
"image/png"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
"sync"
"time"
)
var wg sync.WaitGroup
func main() {
start := time.Now()
dir, err := os.Getwd()
if err != nil {
fmt.Println(err)
}
// 待存在目录
var picDir string
// 保存目录
var out string
// 模板 ID
var template int
flag.StringVar(&picDir, "p", "", "请输入待处理图片的目录")
flag.StringVar(&out, "o", "", "请输入保存图片的目录")
flag.IntVar(&template, "t", 0, "请输入模板:1-3")
flag.Parse()
if picDir == "" {
fmt.Println("请输入待处理图片的目录")
return
}
if out == "" {
fmt.Println("请输入保存图片的目录")
return
}
exit, _ := PathExists(out)
if !exit {
err := os.Mkdir(out, 0777)
if err != nil {
panic(err)
}
}
if template == 0 {
fmt.Println("请输入模板")
return
}
if template > 3 && template < 1 {
fmt.Println("模板只能在1-3")
return
}
suffixList := [] string {
".jpg",
".jpeg",
".png",
}
picList, err := GetAllFiles(picDir, suffixList)
if err != nil {
panic(err)
}
if len(picList) == 0 {
fmt.Println(picDir + " 文件夹下面没有图片")
return
}
for _, pic := range picList {
wg.Add(1) // 启动一个goroutine就登记+1
switch template {
case 1:
baseTpl := dir + "\\template\\01.jpg"
go template1(baseTpl, out, pic)
break
case 2:
baseTpl := dir + "\\template\\02.jpg"
go template2(baseTpl, out, pic)
break
case 3:
baseTpl := dir + "\\template\\03.jpg"
go template3(baseTpl, out, pic)
break
}
}
wg.Wait() // 等待所有登记的goroutine都结束
end := time.Since(start)
fmt.Println("选择样机 0" + strconv.Itoa(template) + ".jpg 共生成 " + strconv.Itoa(len(picList)) + " 图片,耗时:", end)
}
/**
* @param baseTpl 模板
* @param outDir 保存路径
* @param sourcePic 源文件
*/
func template1(baseTpl, outDir, sourcePic string) {
defer wg.Done() // goroutine结束就登记-1
templateFile, err := os.Open(baseTpl)
if err != nil {
panic(err)
}
defer templateFile.Close()
// 解码
templateFileImage, err := jpeg.Decode(templateFile)
if err != nil {
panic(err)
}
// 新建一张和模板文件一样大小的画布
newTemplateImage := image.NewRGBA(templateFileImage.Bounds())
// 将模板图片画到新建的画布上
draw.Draw(newTemplateImage, templateFileImage.Bounds(), templateFileImage, templateFileImage.Bounds().Min, draw.Over)
// ====================向模板中粘贴图片 begin========================
imageData, err := getDataByImage(sourcePic)
if err != nil {
fmt.Println("获取图片失败,err:", err.Error())
return
}
//2、重新调整要粘贴图片尺寸
imageData = resize.Resize(575, 431, imageData, resize.Lanczos3)
// 粘贴缩略图
draw.Draw(newTemplateImage,
newTemplateImage.Bounds().Add(image.Pt(366, 74)),
imageData,
imageData.Bounds().Min,
draw.Over)
imageData = resize.Resize(600, 450, imageData, resize.Lanczos3)
// 粘贴缩略图
draw.Draw(newTemplateImage,
newTemplateImage.Bounds().Add(image.Pt(106, 956)),
imageData,
imageData.Bounds().Min,
draw.Over)
imageData = resize.Resize(1024, 916, imageData, resize.Lanczos3)
// 粘贴缩略图
draw.Draw(newTemplateImage,
newTemplateImage.Bounds().Add(image.Pt(0, 1779)),
imageData,
imageData.Bounds().Min,
draw.Over)
_, fileName := filepath.Split(sourcePic)
// ====================向模板中粘贴图片 结束========================
// 保存图片 ---> 在此我们统一将文件保存到:
outFile := strings.TrimRight(outDir, "\\") + "\\" + fileName
saveFile(newTemplateImage, outFile)
}
/**
* @param baseTpl 模板
* @param outDir 保存路径
* @param sourcePic 源文件
*/
func template2(baseTpl, outDir, sourcePic string) {
defer wg.Done() // goroutine结束就登记-1
templateFile, err := os.Open(baseTpl)
if err != nil {
panic(err)
}
defer templateFile.Close()
// 解码
templateFileImage, err := jpeg.Decode(templateFile)
if err != nil {
panic(err)
}
// 新建一张和模板文件一样大小的画布
newTemplateImage := image.NewRGBA(templateFileImage.Bounds())
// 将模板图片画到新建的画布上
draw.Draw(newTemplateImage, templateFileImage.Bounds(), templateFileImage, templateFileImage.Bounds().Min, draw.Over)
// ====================向模板中粘贴图片 begin========================
imageData, err := getDataByImage(sourcePic)
if err != nil {
fmt.Println("获取图片失败,err:", err.Error())
return
}
//2、重新调整要粘贴图片尺寸
imageData = resize.Resize(760, 760, imageData, resize.Lanczos3)
// 粘贴缩略图
draw.Draw(newTemplateImage,
newTemplateImage.Bounds().Add(image.Pt(134, 165)),
imageData,
imageData.Bounds().Min,
draw.Over)
imageData = resize.Resize(704, 704, imageData, resize.Lanczos3)
// 粘贴缩略图
draw.Draw(newTemplateImage,
newTemplateImage.Bounds().Add(image.Pt(163, 1870)),
imageData,
imageData.Bounds().Min,
draw.Over)
imageData = resize.Resize(1024, 885, imageData, resize.Lanczos3)
// 粘贴缩略图
draw.Draw(newTemplateImage,
newTemplateImage.Bounds().Add(image.Pt(0, 3407)),
imageData,
imageData.Bounds().Min,
draw.Over)
_, fileName := filepath.Split(sourcePic)
// ====================向模板中粘贴图片 结束========================
// 保存图片 ---> 在此我们统一将文件保存到:
outFile := strings.TrimRight(outDir, "\\") + "\\" + fileName
saveFile(newTemplateImage, outFile)
}
/**
* @param baseTpl 模板
* @param outDir 保存路径
* @param sourcePic 源文件
*/
func template3(baseTpl, outDir, sourcePic string) {
defer wg.Done() // goroutine结束就登记-1
templateFile, err := os.Open(baseTpl)
if err != nil {
panic(err)
}
defer templateFile.Close()
// 解码
templateFileImage, err := jpeg.Decode(templateFile)
if err != nil {
panic(err)
}
// 新建一张和模板文件一样大小的画布
newTemplateImage := image.NewRGBA(templateFileImage.Bounds())
// 将模板图片画到新建的画布上
draw.Draw(newTemplateImage, templateFileImage.Bounds(), templateFileImage, templateFileImage.Bounds().Min, draw.Over)
// ====================向模板中粘贴图片 begin========================
imageData, err := getDataByImage(sourcePic)
if err != nil {
fmt.Println("获取图片失败,err:", err.Error())
return
}
//2、重新调整要粘贴图片尺寸
imageData = resize.Resize(1606, 2273, imageData, resize.Lanczos3)
// 粘贴缩略图
draw.Draw(newTemplateImage,
newTemplateImage.Bounds().Add(image.Pt(150, 103)),
imageData,
imageData.Bounds().Min,
draw.Over)
imageData = resize.Resize(1095, 1549, imageData, resize.Lanczos3)
// 粘贴缩略图
draw.Draw(newTemplateImage,
newTemplateImage.Bounds().Add(image.Pt(575, 3611)),
imageData,
imageData.Bounds().Min,
draw.Over)
imageData = resize.Resize(970, 1373, imageData, resize.Lanczos3)
// 粘贴缩略图
draw.Draw(newTemplateImage,
newTemplateImage.Bounds().Add(image.Pt(227, 6778)),
imageData,
imageData.Bounds().Min,
draw.Over)
_, fileName := filepath.Split(sourcePic)
// ====================向模板中粘贴图片 结束========================
// 保存图片 ---> 在此我们统一将文件保存到:
outFile := strings.TrimRight(outDir, "\\") + "\\" + fileName
saveFile(newTemplateImage, outFile)
}
//获取指定目录下的所有文件,包含子目录下的文件
func GetAllFiles(dirPth string, suffixList []string) (files []string, err error) {
var dirs []string
dir, err := ioutil.ReadDir(dirPth)
if err != nil {
return nil, err
}
PthSep := string(os.PathSeparator)
for _, fi := range dir {
if fi.IsDir() { // 目录, 递归遍历
dirs = append(dirs, dirPth+PthSep+fi.Name())
GetAllFiles(dirPth + PthSep + fi.Name(), suffixList)
} else {
// 过滤指定格式
for _, suffix := range suffixList {
fileName := strings.ToLower(fi.Name())
ok := strings.HasSuffix(fileName, suffix)
if ok {
files = append(files, dirPth+PthSep+fi.Name())
}
}
}
}
// 读取子目录下文件
for _, table := range dirs {
temp, _ := GetAllFiles(table, suffixList)
for _, temp1 := range temp {
files = append(files, temp1)
}
}
return files, nil
}
// 根据地址获取图片内容
func getDataByImage(picUrl string) (img image.Image, err error) {
if !strings.HasPrefix(picUrl, ".jpg") &&
!strings.HasPrefix(picUrl, ".jpeg") &&
!strings.HasPrefix(picUrl, ".jpg") {
err = fmt.Errorf("[%s]不支持的图片类型,暂只支持.jpg、.png文件类型", picUrl)
}
fp, err := os.Open(picUrl)
if err != nil {
return nil, err
}
defer fp.Close()
// 解码图片
if strings.HasSuffix(picUrl, ".jpg") || strings.HasSuffix(picUrl, ".jpeg") {
img, err = jpeg.Decode(fp)
if err != nil {
return nil, err
}
}
if strings.HasSuffix(picUrl, ".png") {
img, err = png.Decode(fp)
if err != nil {
err = fmt.Errorf("png.Decode err:%s", err.Error())
return nil, err
}
}
return img, nil
}
func saveFile(pic *image.RGBA, outFile string) {
dstFile, err := os.Create(outFile)
if err != nil {
fmt.Println(err)
}
defer dstFile.Close()
err = jpeg.Encode(dstFile, pic, nil)
if err != nil {
panic(err)
}
}
/**
* 判断目录是否存
*/
func PathExists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil
}
if os.IsNotExist(err) {
return false, nil
}
return false, err
}