Golang 编写的图片压缩程序,质量、尺寸压缩,批量、单张压缩
目录:
前序
效果图
简介
全部代码
前序:
接触 golang 不久,一直是边学边做,边总结,深深感到这门语言的魅力,等下要跟大家分享是最近项目 服务端 用到的图片压缩程序,我单独分离了出来,做成了 exe 程序,可以在 Window 下运行。也可以放到 Linux 环境下编译运行,golang 是一种静态、跨平台的语言。
效果图
-

压缩前
压缩后
开始main:
showTips 做了一些有好提示的文字输出,execute 是核心,压缩函数的调用也在里面
func main() {
showTips()
execute()
time.Sleep( * time.Minute) /** 如果不是自己点击退出,延时5分钟 */
}
提示函数
我分离了两种压缩形式,批量和单张,再组合质量和尺寸,压缩100张600K的图片到8~9K,200px宽度,仅用了6秒左右,win 10,12G,i5,ssd。
还可以做完全的,宽和高像素尺寸的限制,只需要改变几个参数,大家先来看看程序运行的时候显示给用户的提示信息:
对于批量压缩,自动遍历用户输入的文件夹里面的所有符合格式的文件,并进行压缩。
func showTips() {
tips := []string{
"请输入文件夹或图片路径:",
"如果输入文件夹,那么该目录的图片将会被批量压缩;",
"如果是图片路径,那么将会被单独压缩处理。",
"例如:",
"C:/Users/lzq/Desktop/headImages/ 75 200",
"指桌面 headImages 文件夹,里面的图片质量压缩到75%,宽分辨率为200,高是等比例计算",
"C:/Users/lzq/Desktop/headImages/1.jpg 75 200",
"指桌面的 headImages 文件夹里面的 1.jpg 图片,质量压缩到75%,宽分辨率为200,高是等比例计算 ",
"请输入:"}
itemLen := len(tips)
for i :=;i<itemLen;i++ {
if i == itemLen - {
fmt.Printf(tips[i])
}else{
fmt.Println(tips[i])
}
}
}
压缩结构体:
这个比较简单,其余添加可以自定义
type InputArgs struct {
OutputPath string /** 输出目录 */
LocalPath string /** 输入的目录或文件路径 */
Quality int /** 质量 */
Width int /** 宽度尺寸,像素单位 */
}
图片格式验证
自定义支持的文件格式,主要是图片的格式,同时拆分返回一些关键的信息,例如尾缀
/** 是否是图片 */
func isPictureFormat(path string) (string,string,string) {
temp := strings.Split(path,".")
if len(temp) <= {
return "","",""
}
mapRule := make(map[string]int64)
mapRule["jpg"] =
mapRule["png"] =
mapRule["jpeg"] =
// fmt.Println(temp[1]+"---")
/** 添加其他格式 */
if mapRule[temp[]] == {
println(temp[])
return path,temp[],temp[]
}else{
return "","",""
}
}
文件夹遍历
主要用于批量压缩,做了所输入的目录的图片文件遍历,和要保存到的文件夹的创建,和采用纳秒级做压缩后的图片的名称。
func getFilelist(path string) {
/** 创建输出目录 */
errC := os.MkdirAll(inputArgs.OutputPath, )
if errC != nil {
fmt.Printf("%s", errC)
return
}
err := filepath.Walk(path, func(pathFound string, f os.FileInfo, err error) error {
if ( f == nil ) {
return err
}
if f.IsDir() { /** 是否是目录 */
return nil
}
// println(pathFound)
/** 找到一个文件 */
/** 判断是不是图片 */
localPath,format,_ := isPictureFormat(pathFound)
/** 随机数 */
t := time.Now()
millis := t.Nanosecond() /** 纳秒 */
outputPath := inputArgs.OutputPath+strconv.FormatInt(int64(millis),)+"."+format
if localPath!="" {
if !imageCompress(
func() (io.Reader,error){
return os.Open(localPath)
},
func() (*os.File,error) {
return os.Open(localPath)
},
outputPath,
inputArgs.Quality,
inputArgs.Width,format) {
fmt.Println("生成缩略图失败")
}else{
fmt.Println("生成缩略图成功 "+outputPath)
}
}
return nil
})
if err != nil {
fmt.Printf("输入的路径信息有误 %v\n", err)
}
}
压缩前处理函数:
主要做了压缩结构体数据的配置,和验证用户路径的输入以及最终压缩输出文件目录的路径组合。这里有个坑点,对于控制台的数据获取,最好使用 bufio.NewReader(os.Stdin) 而不是 fmt.Scanf 否则,在fmt.p... 输出错误提示信息的时候也会被当作输入读取了,而不是用户输入的。
func execute() {
/** 获取输入 */
//str := ""
//fmt.Scanln (&str) /** 不要使用 scanf,它不会并以一个新行结束输入 */
reader := bufio.NewReader(os.Stdin)
data, _, _ := reader.ReadLine()
/** 分割 */
strPice := strings.Split(string(data)," ") /** 空格 */
if len(strPice) < {
fmt.Printf("输入有误,参数数量不足,请重新输入或退出程序:")
execute()
return
}
inputArgs.LocalPath = strPice[]
inputArgs.Quality,_ = strconv.Atoi(strPice[])
inputArgs.Width,_ = strconv.Atoi(strPice[])
pathTemp,format,top := isPictureFormat(inputArgs.LocalPath)
if pathTemp == "" {
/** 目录 */
/** 如果输入目录,那么是批量 */
fmt.Println("开始批量压缩...")
rs := []rune(inputArgs.LocalPath)
end := len(rs)
substr := string(rs[end-:end])
if substr=="/" {
/** 有 / */
rs := []rune(inputArgs.LocalPath)
end := len(rs)
substr := string(rs[:end-])
endIndex := strings.LastIndex(substr,"/")
inputArgs.OutputPath = string(rs[:endIndex])+"/LghImageCompress/";
}else {
endIndex := strings.LastIndex(inputArgs.LocalPath,"/")
inputArgs.OutputPath = string(rs[:endIndex])+"/LghImageCompress/";
}
getFilelist(inputArgs.LocalPath)
}else{
/** 单个 */
/** 如果输入文件,那么是单个,允许自定义路径 */
fmt.Println("开始单张压缩...")
inputArgs.OutputPath = top+"_compress."+format
if !imageCompress(
func() (io.Reader,error){
return os.Open(inputArgs.LocalPath)
},
func() (*os.File,error) {
return os.Open(inputArgs.LocalPath)
},
inputArgs.OutputPath,
inputArgs.Quality,
inputArgs.Width,format) {
fmt.Println("生成缩略图失败")
}else{
fmt.Println("生成缩略图成功 "+inputArgs.OutputPath)
finish()
}
}
}
压缩函数(核心):
基于golang 1.7 自带的 image/jpeg 库。所谓的宽高完全自定义的修改,就在这里,我是采用了等比例缩放,所以只需要传入其中一项。里面分两次读写同一个文件是因为一次用于尺寸读取,而且两次是不能共用的,会出错。
func imageCompress(
getReadSizeFile func() (io.Reader,error),
getDecodeFile func() (*os.File,error),
to string,
Quality,
base int,
format string) bool{
/** 读取文件 */
file_origin, err := getDecodeFile()
defer file_origin.Close()
if err != nil {
fmt.Println("os.Open(file)错误");
log.Fatal(err)
return false
}
var origin image.Image
var config image.Config
var temp io.Reader
/** 读取尺寸 */
temp, err = getReadSizeFile()
if err != nil {
fmt.Println("os.Open(temp)");
log.Fatal(err)
return false
}
var typeImage int64
format = strings.ToLower(format)
/** jpg 格式 */
if format=="jpg" || format =="jpeg" {
typeImage =
origin, err = jpeg.Decode(file_origin)
if err != nil {
fmt.Println("jpeg.Decode(file_origin)");
log.Fatal(err)
return false
}
temp, err = getReadSizeFile()
if err != nil {
fmt.Println("os.Open(temp)");
log.Fatal(err)
return false
}
config,err = jpeg.DecodeConfig(temp);
if err != nil {
fmt.Println("jpeg.DecodeConfig(temp)");
return false
}
}else if format=="png" {
typeImage =
origin, err = png.Decode(file_origin)
if err != nil {
fmt.Println("png.Decode(file_origin)");
log.Fatal(err)
return false
}
temp, err = getReadSizeFile()
if err != nil {
fmt.Println("os.Open(temp)");
log.Fatal(err)
return false
}
config,err = png.DecodeConfig(temp);
if err != nil {
fmt.Println("png.DecodeConfig(temp)");
return false
}
}
/** 做等比缩放 */
width := uint(base) /** 基准 */
height := uint(base*config.Height/config.Width) canvas := resize.Thumbnail(width, height, origin, resize.Lanczos3)
file_out, err := os.Create(to)
defer file_out.Close()
if err != nil {
log.Fatal(err)
return false
}
if typeImage== {
err = png.Encode(file_out, canvas)
if err!=nil {
fmt.Println("压缩图片失败");
return false
}
}else{
err = jpeg.Encode(file_out, canvas, &jpeg.Options{Quality})
if err!=nil {
fmt.Println("压缩图片失败");
return false
}
} return true
}
全部代码
gitHub: https://github.com/af913337456/golang_image_compress
Golang 编写的图片压缩程序,质量、尺寸压缩,批量、单张压缩的更多相关文章
- Android中图片压缩(质量压缩和尺寸压缩)
关于Android 图片压缩的学习: 自己总结分为质量压缩和像素压缩.质量压缩即:将Bitmap对象保存到对应路径下是所占用的内存减小,但是当你重新读取压缩后的file为Bitmap时,它所占用的内存 ...
- 编写优质嵌入式C程序
前言:这是一年前我为公司内部写的一个文档,旨在向年轻的嵌入式软件工程师们介绍如何在裸机环境下编写优质嵌入式C程序.感觉是有一定的参考价值,所以拿出来分享,抛砖引玉. 转载请注明出处:http://bl ...
- 编写优质无错C程序秘诀!《经验谈》
这里我将陆续给大家载出我在以前学习和编写c代码时遇到的问题和解决方法.学习的心得,有些是经过查询一些曾经参加微软microsoft的开发小组的老程序员的书籍和资料后提供给大家! 首先,当发现错误时,要 ...
- C语言编写的bmp读写程序
C语言编写的bmp读写程序 建议先把bmp的数据存储格式了解下 <span style="font-size:16px;">#include "Windows ...
- 编写优质嵌入式C程序(转)
前言:这是一年前我为公司内部写的一个文档,旨在向年轻的嵌入式软件工程师们介绍如何在裸机环境下编写优质嵌入式C程序.感觉是有一定的参考价值,所以拿出来分享,抛砖引玉. 转载请注明出处:http://bl ...
- 编写高性能Web应用程序的10个技巧
这篇文章讨论了: ·一般ASP.NET性能的秘密 ·能提高ASP.NET表现的有用的技巧和窍门 ·在ASP.NET中使用数据库的建议 ·ASP.NET中的缓存和后台处理 使用ASP.NET编写一个We ...
- 编写高性能 Web 应用程序的 10 个技巧
使用 ASP.NET 编写 Web 应用程序的简单程度令人不敢相信.正因为如此简单,所以很多开发人员就不会花时间来设计其应用程序的结构,以获得更好的性能了.在本文中,我将讲述 10 个用于编写高性能 ...
- 转自微软内部资料:编写高性能 Web 应用程序的 10 个技巧
编写高性能 Web 应用程序的 10 个技巧 转自微软资料数据层性能技巧 1 — 返回多个结果集技巧 2 — 分页的数据访问技巧 3 — 连接池技巧 4 — ASP.NET 缓存 API技巧 5 — ...
- asp.net 图片质量压缩(不改变尺寸)
private static ImageCodecInfo GetEncoderInfo(String mimeType) { int j; ImageCodecInfo[] encoders; en ...
随机推荐
- opencv在图像显示中文
在图像定位和模式识别时,经常需要把结果标注到图片上,标注内容可以是数字字母.矩形框等(opencv支持的)或者是中文汉字(借助freetype). 1.显示数字/矩形框 #include <op ...
- word-wrap ,word-break 和white-space 的联系
在工作中我遇到一个问题,其实功能也不复杂,就是上面有个textarea标签 ,里面输入内容,下面有个显示效果 ,有个条件就是 上面输入的什么格式(比如换行等等),下面显示的也是 什么格式.如下图: 这 ...
- C语言 · 判定数字
编写函数,判断某个给定字符是否为数字. 样例输入 9 样例输出 yes #include<stdio.h> int main(){ char c; scanf("%c" ...
- 120项改进:开源超级爬虫Hawk 2.0 重磅发布!
沙漠君在历时半年,修改无数bug,更新一票新功能后,在今天隆重推出最新改进的超级爬虫Hawk 2.0! 啥?你不知道Hawk干吗用的? 这是采集数据的挖掘机,网络猎杀的重狙!半年多以前,沙漠君写了一篇 ...
- AFNetworking 3.0 源码解读(十)之 UIActivityIndicatorView/UIRefreshControl/UIImageView + AFNetworking
我们应该看到过很多类似这样的例子:某个控件拥有加载网络图片的能力.但这究竟是怎么做到的呢?看完这篇文章就明白了. 前言 这篇我们会介绍 AFNetworking 中的3个UIKit中的分类.UIAct ...
- Go web开发初探
2017年的第一篇博客,也是第一次写博客,写的不好,请各位见谅. 本人之前一直学习java.java web,最近开始学习Go语言,所以也想了解一下Go语言中web的开发方式以及运行机制. 在< ...
- CentOS下mysql数据库常用命令总结
mysql数据库使用总结 本文主要记录一些mysql日常使用的命令,供以后查询. 1.更改root密码 mysqladmin -uroot password 'yourpassword' 2.远程登陆 ...
- iOS - 模态Model视图跳转和Push视图跳转的混合需求实现原理
在研发中总会遇到一些莫名的需求,本着存在即合理的态度跟大家分享一下"模态Model视图跳转和Push视图跳转的需求实现",本文仅仅传授研发技术不传授产品以及UE的思想,请大家合理对 ...
- AFN解析器里的坑
AFN框架是用来用来发送网络请求的,它的好处是可以自动给你解析JSON数据,还可以发送带参数的请求AFN框架还可以监测当前的网络状态,还支持HTTPS请求,分别对用的类为AFNetworkReacha ...
- 如何dos命令打开服务窗口?
1.输入services.msc点击<确定>进入服务窗口.如图: