文章目录
概要
` 使用go开发桌面exe程序,方便照片合并压缩操作,身份证正反面,居住证正反面,照片全部压缩到1mb以下大小
目前存在小部分bug但是不影响正常使用!不多说直接上代码!
package main
import (
"fmt"
"image"
"image/draw"
"image/jpeg"
"io/ioutil"
"os"
"path/filepath"
"strings"
"sync"
"time"
)
const (
frontKeyword = "身份证人像面"
backKeyword = "身份证国徽面"
newKeyword1 = "居住证正面"
newKeyword2 = "居住证反面"
newKeyword3 = "户口本户主页"
newKeyword4 = "户口本本人页"
maxImageSize = 1024 * 1024 // 1MB
expirationDate = "2023-09-20" // 设置软件过期日期
maxConcurrency = 5 // 最大并发处理数
)
var (
daysRemaining int
visitedDirs = make(map[string]struct{})
mergeMutex sync.Mutex
)
func main() {
// 检查软件是否过期
if isExpired(expirationDate) {
fmt.Println("软件已过期,请联系开发者获取新版本。联系方式:xxxxxxx")
return
}
// 获取剩余天数
daysRemaining = calculateDaysRemaining(expirationDate)
var dirPath string
fmt.Print("请输入目录路径: ")
fmt.Scan(&dirPath)
processDirectory(dirPath)
fmt.Println("所有操作已完成")
//不关闭窗口操作
for {
}
}
func isExpired(expirationDate string) bool {
expirationTime, err := time.Parse("2006-01-02", expirationDate)
if err != nil {
fmt.Println("无法解析过期日期:", err)
return true // 如果无法解析过期日期,则默认为过期
}
currentTime := time.Now()
return currentTime.After(expirationTime)
}
func calculateDaysRemaining(expirationDate string) int {
expirationTime, err := time.Parse("2006-01-02", expirationDate)
if err != nil {
fmt.Println("无法解析过期日期:", err)
return -1 // 如果无法解析过期日期,则返回-1表示错误
}
currentTime := time.Now()
remainingDays := int(expirationTime.Sub(currentTime).Hours() / 24)
return remainingDays
}
func processDirectory(dirPath string) {
// 加锁以避免重复访问目录
dirMutex := sync.Mutex{}
dirMutex.Lock()
defer dirMutex.Unlock()
// 检查是否已经访问过此目录
if _, exists := visitedDirs[dirPath]; exists {
return
}
visitedDirs[dirPath] = struct{}{}
// 检查是否是 "修改后" 文件夹或其子目录
if isModifiedFolder(dirPath) {
return
}
//获取当前文件夹
currentDirName := filepath.Base(dirPath)
// 创建 "修改后" 子目录
modifiedFolderPath := filepath.Join(dirPath, currentDirName+"-修改后")
if err := os.Mkdir(modifiedFolderPath, 0755); err != nil && !os.IsExist(err) {
fmt.Println("无法创建 '修改后' 文件夹:", err)
return
}
// 获取目录下的图片文件
imageFiles, err := getImageFiles(dirPath)
if err != nil {
fmt.Println("无法获取图片文件列表:", err)
return
}
// 创建一个通道来协调压缩任务
compressChan := make(chan string)
// 创建一个等待组以等待所有压缩任务完成
var wg sync.WaitGroup
// 启动多个协程进行图片压缩
for i := 0; i < maxConcurrency; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for imagePath := range compressChan {
compressAndSaveImage(imagePath, maxImageSize, modifiedFolderPath)
}
}()
}
// 将图片路径发送到通道以进行压缩
for _, imagePath := range imageFiles {
compressChan <- imagePath
}
close(compressChan)
// 加载身份证照片并合成
frontIDCardImg, backIDCardImg, err := loadIDCardImages(dirPath)
if err != nil {
fmt.Println("无法加载身份证照片:", err)
return
}
// 如果找到了正面和背面照片,进行合成和保存
if frontIDCardImg != nil && backIDCardImg != nil {
mergedImg := mergeImages(frontIDCardImg, backIDCardImg)
savePath := filepath.Join(modifiedFolderPath, "合成照片.jpg")
if err := saveCompressedImageJPEG(mergedImg, savePath, maxImageSize); err != nil {
fmt.Println("无法保存合成照片:", err)
return
}
fmt.Println("合成照片已保存至:", savePath)
}
// 新照片类型处理代码块开始
processNewImageType(imageFiles, dirPath, newKeyword1, newKeyword2, modifiedFolderPath)
processNewImageType(imageFiles, dirPath, newKeyword3, newKeyword4, modifiedFolderPath)
processNewImageType(imageFiles, dirPath, "户口本首页", newKeyword4, modifiedFolderPath)
// 新照片类型处理代码块结束
// 处理子目录
subDirs, err := getSubDirectories(dirPath)
if err != nil {
fmt.Println("无法获取子目录列表:", err)
return
}
for _, subDir := range subDirs {
processDirectory(subDir)
}
}
func isModifiedFolder(dirPath string) bool {
return strings.HasSuffix(dirPath, "修改后")
}
func processNewImageType(imageFiles []string, dirPath string, newKeyword1, newKeyword2, modifiedFolderPath string) {
var newImage1 image.Image
var newImage2 image.Image
// 对于每个图像文件,检查文件名是否包含新关键字
for _, imagePath := range imageFiles {
if strings.Contains(imagePath, newKeyword1) {
img, err := loadImage(imagePath)
if err != nil {
fmt.Printf("无法加载图像文件:%s,当前目录:%s\n", imagePath, getCurrentDirectory())
continue
}
newImage1 = img
} else if strings.Contains(imagePath, newKeyword2) {
img, err := loadImage(imagePath)
if err != nil {
fmt.Printf("无法加载图像文件:%s,当前目录:%s\n", imagePath, getCurrentDirectory())
continue
}
newImage2 = img
}
}
// 如果找到了新照片类型的图像,进行合并和保存
if newImage1 != nil && newImage2 != nil {
mergedImg := mergeImages(newImage1, newImage2)
savePath := filepath.Join(modifiedFolderPath, "新照片类型合成照片.jpg")
if err := saveCompressedImageJPEG(mergedImg, savePath, maxImageSize); err != nil {
fmt.Println("无法保存新照片类型合成照片:", err)
} else {
fmt.Println("新照片类型合成照片已保存至:", savePath)
}
}
}
func getImageFiles(dirPath string) ([]string, error) {
var imageFiles []string
fileList, err := getFileList(dirPath)
if err != nil {
return nil, err
}
for _, fileInfo := range fileList {
if !fileInfo.IsDir() && isImageFile(fileInfo.Name()) {
imageFiles = append(imageFiles, filepath.Join(dirPath, fileInfo.Name()))
}
}
return imageFiles, nil
}
func isImageFile(fileName string) bool {
extensions := []string{".jpg", ".jpeg", ".png", ".gif"}
lowerFileName := strings.ToLower(fileName)
for _, ext := range extensions {
if strings.HasSuffix(lowerFileName, ext) {
return true
}
}
return false
}
func compressAndSaveImage(imagePath string, maxSize int, outputPath string) {
img, err := loadImage(imagePath)
if err != nil {
fmt.Printf("无法加载图像文件:%s,当前目录:%s\n", imagePath, getCurrentDirectory())
return
}
// 获取图像的文件名和扩展名
_, fileName := filepath.Split(imagePath)
// 构建保存压缩图像的路径
savePath := filepath.Join(outputPath, getCompressedImagePath(fileName))
if err := saveCompressedImageJPEG(img, savePath, maxSize); err != nil {
fmt.Println("无法保存压缩图像:", err)
}
}
func getCompressedImagePath(imagePath string) string {
ext := filepath.Ext(imagePath)
base := strings.TrimSuffix(imagePath, ext)
return base + "_compressed" + ext
}
func getFileList(dirPath string) ([]os.FileInfo, error) {
dirInfo, err := os.Stat(dirPath)
if os.IsNotExist(err) {
return nil, err
}
if !dirInfo.IsDir() {
return nil, fmt.Errorf("指定路径不是目录")
}
fileList, err := ioutil.ReadDir(dirPath)
if err != nil {
return nil, err
}
return fileList, nil
}
func loadIDCardImages(dirPath string) (image.Image, image.Image, error) {
var frontIDCardImg image.Image
var backIDCardImg image.Image
fileList, err := getFileList(dirPath)
if err != nil {
return nil, nil, err
}
for _, fileInfo := range fileList {
if !fileInfo.IsDir() {
fileName := fileInfo.Name()
if strings.Contains(fileName, frontKeyword) {
img, err := loadImage(filepath.Join(dirPath, fileName))
if err != nil {
return nil, nil, err
}
frontIDCardImg = img
} else if strings.Contains(fileName, backKeyword) {
img, err := loadImage(filepath.Join(dirPath, fileName))
if err != nil {
return nil, nil, err
}
backIDCardImg = img
}
}
}
return frontIDCardImg, backIDCardImg, nil
}
func mergeImages(frontImg, backImg image.Image) image.Image {
frontWidth := frontImg.Bounds().Dx()
frontHeight := frontImg.Bounds().Dy()
backWidth := backImg.Bounds().Dx()
backHeight := backImg.Bounds().Dy()
mergedWidth := frontWidth + backWidth
mergedHeight := frontHeight
if backHeight > frontHeight {
mergedHeight = backHeight
}
mergedImg := image.NewRGBA(image.Rect(0, 0, mergedWidth, mergedHeight))
draw.Draw(mergedImg, image.Rect(0, 0, frontWidth, frontHeight), frontImg, image.Point{}, draw.Over)
draw.Draw(mergedImg, image.Rect(frontWidth, 0, mergedWidth, backHeight), backImg, image.Point{}, draw.Over)
return mergedImg
}
// 保存经过压缩的图像为JPEG格式
func saveCompressedImageJPEG(img image.Image, filePath string, maxSize int) error {
// 尝试不同的压缩质量,直到图像大小满足要求
quality := 100
for {
outputFile, err := os.Create(filePath)
if err != nil {
return err
}
defer outputFile.Close()
// 将图像直接保存为压缩后的 JPEG 格式
err = jpeg.Encode(outputFile, img, &jpeg.Options{Quality: quality})
if err != nil {
return err
}
// 检查图像大小是否满足要求
stat, err := outputFile.Stat()
if err != nil {
return err
}
if stat.Size() <= int64(maxSize) {
break
}
// 降低压缩质量再次尝试
quality -= 10
if quality <= 0 {
return fmt.Errorf("无法满足目标图像大小")
}
}
return nil
}
func loadImage(filePath string) (image.Image, error) {
imgFile, err := os.Open(filePath)
if err != nil {
fmt.Printf("无法加载图像文件:%s,当前目录:%s\n", filePath, getCurrentDirectory())
return nil, err
}
defer imgFile.Close()
img, _, err := image.Decode(imgFile)
if err != nil {
return nil, err
}
return img, nil
}
func getCurrentDirectory() string {
dir, err := os.Getwd()
if err != nil {
return ""
}
return dir
}
func getSubDirectories(dirPath string) ([]string, error) {
var subDirs []string
fileList, err := getFileList(dirPath)
if err != nil {
return nil, err
}
for _, fileInfo := range fileList {
if fileInfo.IsDir() {
subDirs = append(subDirs, filepath.Join(dirPath, fileInfo.Name()))
}
}
return subDirs, nil
}
#程序打包命令
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o 重生之我是压缩工具3.2.exe test6.go

ps:写完之后反正我也看不懂!有能力的自己优化修改吧!图片我就不放了,自己测试看效果就好了
1019

被折叠的 条评论
为什么被折叠?



