├── ReadMe.md ├── go.mod ├── imageCompress.exe └── imageCompress.go /ReadMe.md: -------------------------------------------------------------------------------- 1 | ### 编译步骤: 2 | 安装golang环境 3 | 4 | 在控制台输入 go get "github.com/nfnt/resize" 5 | 6 | 最后 go build imageCompress.go 7 | 8 | ### 使用方法: 9 | 双击 imageCompress.exe,跟随提示即可 10 | 11 | ### 启动后输出: 12 | ```java 13 | 请输入文件夹或图片路径: 14 | 如果输入文件夹,那么该目录的图片将会被批量压缩; 15 | 如果是图片路径,那么将会被单独压缩处理。 16 | 例如: 17 | C:/Users/lzq/Desktop/headImages/ 75 200 18 | 指桌面 headImages 文件夹,里面的图片质量压缩到75%,宽分辨率为200,高是等比例计算 19 | C:/Users/lzq/Desktop/headImages/1.jpg 75 200 20 | 指桌面的 headImages 文件夹里面的 1.jpg 图片,质量压缩到75%,宽分辨率为200,高是等比例计算 21 | 请输入: 22 | ``` 23 | 24 | ### Linux 支持 25 | 26 | 可以自己在 Linux 环境下编译 27 | 28 | ### Compile Step: 29 | 30 | config your golang environment; 31 | 32 | go get "github.com/nfnt/resize" 33 | 34 | go build imageCompress.go 35 | 36 | ### How to use: 37 | double click imageCompress.exe,and just follow the tips 38 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module golang_image_compress 2 | 3 | go 1.16 4 | 5 | require github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 6 | -------------------------------------------------------------------------------- /imageCompress.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/af913337456/golang_image_compress/6dbd9e90bb8fede7b7e6cf983ebcf991e8a0b5f7/imageCompress.exe -------------------------------------------------------------------------------- /imageCompress.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | //"encoding/json" 5 | "fmt" 6 | //"os" 7 | //"io/ioutil" 8 | "github.com/nfnt/resize" 9 | "image/jpeg" 10 | "io" 11 | "log" 12 | "os" 13 | "path/filepath" 14 | "strconv" 15 | // "flag" 16 | "bufio" 17 | "image" 18 | "image/png" 19 | "strings" 20 | "time" 21 | ) 22 | 23 | func imageCompress( 24 | getReadSizeFile func() (io.Reader, error), 25 | getDecodeFile func() (*os.File, error), 26 | to string, 27 | Quality, 28 | base int, 29 | format string) bool { 30 | /** 读取文件 */ 31 | fileOrigin, err := getDecodeFile() 32 | if err != nil { 33 | fmt.Println("os.Open(file)错误") 34 | log.Fatal(err) 35 | return false 36 | } 37 | defer func() { 38 | if fileOrigin != nil { 39 | _ = fileOrigin.Close() 40 | } 41 | }() 42 | var origin image.Image 43 | var config image.Config 44 | var temp io.Reader 45 | /** 读取尺寸 */ 46 | temp, err = getReadSizeFile() 47 | if err != nil { 48 | fmt.Println("os.Open(temp)") 49 | log.Fatal(err) 50 | return false 51 | } 52 | var typeImage int64 53 | format = strings.ToLower(format) 54 | /** jpg 格式 */ 55 | if format == "jpg" || format == "jpeg" { 56 | typeImage = 1 57 | origin, err = jpeg.Decode(fileOrigin) 58 | if err != nil { 59 | fmt.Println("jpeg.Decode(file_origin)") 60 | log.Fatal(err) 61 | return false 62 | } 63 | temp, err = getReadSizeFile() 64 | if err != nil { 65 | fmt.Println("os.Open(temp)") 66 | log.Fatal(err) 67 | return false 68 | } 69 | config, err = jpeg.DecodeConfig(temp) 70 | if err != nil { 71 | fmt.Println("jpeg.DecodeConfig(temp)") 72 | return false 73 | } 74 | } else if format == "png" { 75 | typeImage = 0 76 | origin, err = png.Decode(fileOrigin) 77 | if err != nil { 78 | fmt.Println("png.Decode(file_origin)") 79 | log.Fatal(err) 80 | return false 81 | } 82 | temp, err = getReadSizeFile() 83 | if err != nil { 84 | fmt.Println("os.Open(temp)") 85 | log.Fatal(err) 86 | return false 87 | } 88 | config, err = png.DecodeConfig(temp) 89 | if err != nil { 90 | fmt.Println("png.DecodeConfig(temp)") 91 | return false 92 | } 93 | } 94 | /** 做等比缩放 */ 95 | width := uint(base) /** 基准 */ 96 | height := uint(base * config.Height / config.Width) 97 | 98 | canvas := resize.Thumbnail(width, height, origin, resize.Lanczos3) 99 | fileOut, err := os.Create(to) 100 | if err != nil { 101 | log.Fatal(err) 102 | return false 103 | } 104 | defer func() { 105 | if fileOut != nil { 106 | _ = fileOut.Close() 107 | } 108 | }() 109 | if typeImage == 0 { 110 | err = png.Encode(fileOut, canvas) 111 | if err != nil { 112 | fmt.Println("压缩图片失败") 113 | return false 114 | } 115 | } else { 116 | err = jpeg.Encode(fileOut, canvas, &jpeg.Options{Quality}) 117 | if err != nil { 118 | fmt.Println("压缩图片失败") 119 | return false 120 | } 121 | } 122 | 123 | return true 124 | } 125 | 126 | func getFilelist(path string) { 127 | /** 创建输出目录 */ 128 | errC := os.MkdirAll(inputArgs.OutputPath, 0777) 129 | if errC != nil { 130 | fmt.Printf("%s", errC) 131 | return 132 | } 133 | err := filepath.Walk(path, func(pathFound string, f os.FileInfo, err error) error { 134 | if f == nil { 135 | return err 136 | } 137 | if f.IsDir() { /** 是否是目录 */ 138 | return nil 139 | } 140 | // println(pathFound) 141 | /** 找到一个文件 */ 142 | /** 判断是不是图片 */ 143 | localPath, format, _ := isPictureFormat(pathFound) 144 | /** 随机数 */ 145 | t := time.Now() 146 | millis := t.Nanosecond() /** 纳秒 */ 147 | outputPath := inputArgs.OutputPath + strconv.FormatInt(int64(millis), 10) + "." + format 148 | if localPath != "" { 149 | if !imageCompress( 150 | func() (io.Reader, error) { 151 | return os.Open(localPath) 152 | }, 153 | func() (*os.File, error) { 154 | return os.Open(localPath) 155 | }, 156 | outputPath, 157 | inputArgs.Quality, 158 | inputArgs.Width, 159 | format) { 160 | fmt.Println("生成缩略图失败") 161 | } else { 162 | fmt.Println("生成缩略图成功 " + outputPath) 163 | } 164 | } 165 | return nil 166 | }) 167 | if err != nil { 168 | fmt.Printf("输入的路径信息有误 %v\n", err) 169 | } 170 | } 171 | 172 | /** 是否是图片 */ 173 | func isPictureFormat(path string) (string, string, string) { 174 | temp := strings.Split(path, ".") 175 | if len(temp) <= 1 { 176 | return "", "", "" 177 | } 178 | mapRule := make(map[string]int64) 179 | mapRule["jpg"] = 1 180 | mapRule["png"] = 1 181 | mapRule["jpeg"] = 1 182 | // fmt.Println(temp[1]+"---") 183 | /** 添加其他格式 */ 184 | if mapRule[temp[1]] == 1 { 185 | println(temp[1]) 186 | return path, temp[1], temp[0] 187 | } else { 188 | return "", "", "" 189 | } 190 | } 191 | 192 | func execute() { 193 | /** 获取输入 */ 194 | //str := "" 195 | //fmt.Scanln (&str) /** 不要使用 scanf,它不会并以一个新行结束输入 */ 196 | 197 | reader := bufio.NewReader(os.Stdin) 198 | data, _, _ := reader.ReadLine() 199 | /** 分割 */ 200 | strPice := strings.Split(string(data), " ") /** 空格 */ 201 | if len(strPice) < 3 { 202 | fmt.Printf("输入有误,参数数量不足,请重新输入或退出程序:") 203 | execute() 204 | return 205 | } 206 | 207 | inputArgs.LocalPath = strPice[0] 208 | inputArgs.Quality, _ = strconv.Atoi(strPice[1]) 209 | inputArgs.Width, _ = strconv.Atoi(strPice[2]) 210 | 211 | pathTemp, format, top := isPictureFormat(inputArgs.LocalPath) 212 | if pathTemp == "" { 213 | /** 目录 */ 214 | /** 如果输入目录,那么是批量 */ 215 | fmt.Println("开始批量压缩...") 216 | rs := []rune(inputArgs.LocalPath) 217 | end := len(rs) 218 | substr := string(rs[end-1 : end]) 219 | if substr == "/" { 220 | /** 有 / */ 221 | rs := []rune(inputArgs.LocalPath) 222 | end := len(rs) 223 | substr := string(rs[0 : end-1]) 224 | endIndex := strings.LastIndex(substr, "/") 225 | inputArgs.OutputPath = string(rs[0:endIndex]) + "/LghImageCompress/" 226 | } else { 227 | endIndex := strings.LastIndex(inputArgs.LocalPath, "/") 228 | inputArgs.OutputPath = string(rs[0:endIndex]) + "/LghImageCompress/" 229 | } 230 | getFilelist(inputArgs.LocalPath) 231 | fmt.Println("图片保存在文件夹 " + inputArgs.OutputPath) 232 | } else { 233 | /** 单个 */ 234 | /** 如果输入文件,那么是单个,允许自定义路径 */ 235 | fmt.Println("开始单张压缩...") //C:\Users\lzq\Desktop\Apk.jpg 75 200 236 | inputArgs.OutputPath = top + "_compress." + format 237 | if !imageCompress( 238 | func() (io.Reader, error) { 239 | return os.Open(inputArgs.LocalPath) 240 | }, 241 | func() (*os.File, error) { 242 | return os.Open(inputArgs.LocalPath) 243 | }, 244 | inputArgs.OutputPath, 245 | inputArgs.Quality, 246 | inputArgs.Width, 247 | format) { 248 | fmt.Println("生成缩略图失败") 249 | } else { 250 | fmt.Println("生成缩略图成功 " + inputArgs.OutputPath) 251 | finish() 252 | } 253 | } 254 | 255 | time.Sleep(5 * time.Minute) /** 如果不是自己点击退出,延时5分钟 */ 256 | } 257 | 258 | func finish() { 259 | fmt.Printf("继续输入进行压缩或者退出程序:") 260 | execute() 261 | } 262 | 263 | func showTips() { 264 | tips := []string{ 265 | "请输入文件夹或图片路径:", 266 | "如果输入文件夹,那么该目录的图片将会被批量压缩;", 267 | "如果是图片路径,那么将会被单独压缩处理。", 268 | "例如:", 269 | "C:/Users/lzq/Desktop/headImages/ 75 200", 270 | "指桌面 headImages 文件夹,里面的图片质量压缩到75%,宽分辨率为200,高是等比例计算", 271 | "C:/Users/lzq/Desktop/headImages/1.jpg 75 200", 272 | "指桌面的 headImages 文件夹里面的 1.jpg 图片,质量压缩到75%,宽分辨率为200,高是等比例计算 ", 273 | "请输入:"} 274 | itemLen := len(tips) 275 | for i := 0; i < itemLen; i++ { 276 | if i == itemLen-1 { 277 | fmt.Printf(tips[i]) 278 | } else { 279 | fmt.Println(tips[i]) 280 | } 281 | } 282 | } 283 | 284 | type InputArgs struct { 285 | OutputPath string /** 输出目录 */ 286 | LocalPath string /** 输入的目录或文件路径 */ 287 | Quality int /** 质量 */ 288 | Width int /** 宽度尺寸,像素单位 */ 289 | Format string /** 格式 */ 290 | } 291 | 292 | var inputArgs InputArgs 293 | 294 | func main() { 295 | showTips() 296 | execute() 297 | time.Sleep(5 * time.Minute) /** 如果不是自己点击退出,延时5分钟 */ 298 | } 299 | --------------------------------------------------------------------------------