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 ...
随机推荐
- Python标准模块--ContextManager
1 模块简介 在数年前,Python 2.5 加入了一个非常特殊的关键字,就是with.with语句允许开发者创建上下文管理器.什么是上下文管理器?上下文管理器就是允许你可以自动地开始和结束一些事情. ...
- CoreCRM 开发实录——想用国货不容易
昨天(2016年12月29日)发了开始开发的文章.本来晚上准备在 Coding.NET 上添加几个任务开始搞起了.可是真的开始用的时候才发现:Coding.NET 的任务功能只针对私有的任务开放.我想 ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(69)-微信公众平台开发-功能概述
系列目录 为什么要先发这个文章? 因为接下来的文章是关于微信开发的系列,心中一定要有一个概念,知道自己接下来要做什么功能. 而且微信到处都是坑,我首先要把微信与本地跑通起来才敢发布,否则中间出现坑导致 ...
- mybatis_基础篇
一.认识mybatis: MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改 ...
- 使用ubuntu作为web开发环境的一些感受
从ms-dos,win95,win98,winMe,winXp,vista,win7,win10我都有使用的经历,我使用时间最长的应属winxp,其次是win7,说实话,我觉得这两个系统是微软做的最好 ...
- php实现的分页类
php分页类文件: <?php /** file: page.class.php 完美分页类 Page */ class Page { private $total; //数据表中总记录数 pr ...
- 使用EF CodeFirst 创建数据库
EntityFramework 在VS2015添加新建项时,选择数据->ADO.NET 实体数据模型,有一下选项 来自数据库的EF设计器,这个就是我们最常用的EntityFramework设计模 ...
- ExecuteOrDelayUntilScriptLoaded 还是 SP.SOD.executeFunc?
SharePoint 客户端 JS 开发时,要等待 SharePoint 对象都加载完毕再调用自己的方法(myFunction),可以有两种方式: ExecuteOrDelayUntilScriptL ...
- 需要UWP Vendor一名
工作地点北京,海淀,微软大厦2号楼,小冰项目组.
- Java:Double Brace Initialization
在我刚刚接触现在这个产品的时候,我就在我们的代码中接触到了对Double Brace Initialization的使用.那段代码用来初始化一个集合: final Set<String> ...