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 ...
随机推荐
- 谈谈一些有趣的CSS题目(十一)-- reset.css 知多少?
开本系列,谈谈一些有趣的 CSS 题目,题目类型天马行空,想到什么说什么,不仅为了拓宽一下解决问题的思路,更涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题 ...
- ABP文档 - 本地化
文档目录 本节内容: 简介 应用语言 本地化源 XML文件 注册XML本地化源 JSOn文件 注册JSON本地化源 资源文件 自定义源 获取一个本地文本 在服务端 在MVc控制器里 在MVC视图里 在 ...
- Jquery mobiscroll 移动设备(手机)wap日期时间选择插件以及滑动、滚动插件
Jquery Mobiscroll是一个用于触摸设备(Android phones, iPhone, iPad, Galaxy Tab)的日期和时间选择器jQuery插件.以及各种滑动插件 可以让用户 ...
- 8.仿阿里云虚拟云服务器的FTP(包括FTP文件夹大小限制)
平台之大势何人能挡? 带着你的Net飞奔吧!:http://www.cnblogs.com/dunitian/p/4822808.html#iis 原文:http://dnt.dkill.net/Ar ...
- Android GridView 通过seletor 设置状态和默认状态
Android中可以通过selector控制GridView Item 的状态,而省去使用代码控制 GridView View Selector Xml文件 <?xml version=&quo ...
- Vue + Webpack + Vue-loader 系列教程(1)功能介绍篇
原文地址:https://lvyongbo.gitbooks.io/vue-loader/content/ Vue-loader 是什么? vue-loader 是一个加载器,能把如下格式的 Vue ...
- 使用 JavaScript 和 canvas 做精确的像素碰撞检测
原文地址:Pixel accurate collision detection with Javascript and Canvas 译者:nzbin 我正在开发一个需要再次使用碰撞检测的游戏.我通常 ...
- 用javascript 写个函数返回一个页面里共使用了多少种HTML 标签
今天我无意间看到一个面试题: 如何用javascript 写个函数返回一个页面里共使用了多少种HTML 标签? 不知你看到 是否蒙B了,如果是我 面试,肯定脑子嗡嗡的响.... 网上搜了搜也没有找到答 ...
- JS魔法堂:不完全国际化&本地化手册 之 理論篇
前言 最近加入到新项目组负责前端技术预研和选型,其中涉及到一个熟悉又陌生的需求--国际化&本地化.熟悉的是之前的项目也玩过,陌生的是之前的实现仅仅停留在"有"的阶段而已. ...
- jquery.each()
$(selector).each(function(index,element)) index - 选择器的 index 位置 element - 当前的元素(也可使用 "this" ...