目录:

  前序

  效果图

  简介

  全部代码

前序:

  接触 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 编写的图片压缩程序,质量、尺寸压缩,批量、单张压缩的更多相关文章

  1. Android中图片压缩(质量压缩和尺寸压缩)

    关于Android 图片压缩的学习: 自己总结分为质量压缩和像素压缩.质量压缩即:将Bitmap对象保存到对应路径下是所占用的内存减小,但是当你重新读取压缩后的file为Bitmap时,它所占用的内存 ...

  2. 编写优质嵌入式C程序

    前言:这是一年前我为公司内部写的一个文档,旨在向年轻的嵌入式软件工程师们介绍如何在裸机环境下编写优质嵌入式C程序.感觉是有一定的参考价值,所以拿出来分享,抛砖引玉. 转载请注明出处:http://bl ...

  3. 编写优质无错C程序秘诀!《经验谈》

    这里我将陆续给大家载出我在以前学习和编写c代码时遇到的问题和解决方法.学习的心得,有些是经过查询一些曾经参加微软microsoft的开发小组的老程序员的书籍和资料后提供给大家! 首先,当发现错误时,要 ...

  4. C语言编写的bmp读写程序

    C语言编写的bmp读写程序 建议先把bmp的数据存储格式了解下 <span style="font-size:16px;">#include "Windows ...

  5. 编写优质嵌入式C程序(转)

    前言:这是一年前我为公司内部写的一个文档,旨在向年轻的嵌入式软件工程师们介绍如何在裸机环境下编写优质嵌入式C程序.感觉是有一定的参考价值,所以拿出来分享,抛砖引玉. 转载请注明出处:http://bl ...

  6. 编写高性能Web应用程序的10个技巧

    这篇文章讨论了: ·一般ASP.NET性能的秘密 ·能提高ASP.NET表现的有用的技巧和窍门 ·在ASP.NET中使用数据库的建议 ·ASP.NET中的缓存和后台处理 使用ASP.NET编写一个We ...

  7. 编写高性能 Web 应用程序的 10 个技巧

    使用 ASP.NET 编写 Web 应用程序的简单程度令人不敢相信.正因为如此简单,所以很多开发人员就不会花时间来设计其应用程序的结构,以获得更好的性能了.在本文中,我将讲述 10 个用于编写高性能 ...

  8. 转自微软内部资料:编写高性能 Web 应用程序的 10 个技巧

    编写高性能 Web 应用程序的 10 个技巧 转自微软资料数据层性能技巧 1 — 返回多个结果集技巧 2 — 分页的数据访问技巧 3 — 连接池技巧 4 — ASP.NET 缓存 API技巧 5 — ...

  9. asp.net 图片质量压缩(不改变尺寸)

    private static ImageCodecInfo GetEncoderInfo(String mimeType) { int j; ImageCodecInfo[] encoders; en ...

随机推荐

  1. Android 6.0 权限知识学习笔记

    最近在项目上因为6.0运行时权限吃了亏,发现之前对运行时权限的理解不足,决定回炉重造,重新学习一下Android Permission. 进入正题: Android权限 在Android系统中,权限分 ...

  2. 【翻译】Awesome R资源大全中文版来了,全球最火的R工具包一网打尽,超过300+工具,还在等什么?

    0.前言 虽然很早就知道R被微软收购,也很早知道R在统计分析处理方面很强大,开始一直没有行动过...直到 直到12月初在微软技术大会,看到我软的工程师演示R的使用,我就震惊了,然后最近在网上到处了解和 ...

  3. SQL Server-聚焦IN VS EXISTS VS JOIN性能分析(十九)

    前言 本节我们开始讲讲这一系列性能比较的终极篇IN VS EXISTS VS JOIN的性能分析,前面系列有人一直在说场景不够,这里我们结合查询索引列.非索引列.查询小表.查询大表来综合分析,简短的内 ...

  4. WebLogic的安装和配置以及MyEclipse中配置WebLogic

    WebLogic 中间件: 是基础软件的一大类,属于可复用软件的范畴,顾名思义,中间件属于操作系统软件与应用软件的中间,比如:JDK,框架,weblogic. weblogic与tomcat区别 : ...

  5. iOS从零开始学习直播之2.采集

      直播的采集由采集的设备(摄像头.话筒)不同分为视频采集和音频采集,本篇文章会分别介绍. 1.采集步骤   1.创建捕捉会话(AVCaptureSession),iOS调用相机和话筒之前都需要创建捕 ...

  6. ionic第一坑——ion-slide-box坑(ion-slide分两页的坑)

    ionic.views.Slider = ionic.views.View.inherit({ initialize: function (options) { . . . function setu ...

  7. 跟着老男孩教育学Python开发【第五篇】:模块

    递归的案例:阶乘 1*2*3*4*5*6*7- def func(num):     if num == 1:         return 1     return num * func(num - ...

  8. 二叉树的创建和遍历(C版和java版)

    以这颗树为例:#表示空节点前序遍历(根->左->右)为:ABD##E##C#F## 中序遍历(左->根->右)为:#D#B#E#A#C#F# 后序遍历(左->右-> ...

  9. 我的MYSQL学习心得(十三) 权限管理

    我的MYSQL学习心得(十三) 权限管理 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) ...

  10. 如何安装并简单的使用OwinHost——Katana

    微软OWIN的提出必然会引起一场风暴,而我们作为C#阵营中一份子,自然免不了会卷入其中.OWIN是什么东西,我在这里就不解析了,还不知道是OWIN是什么的读者请打开浏览器,然后搜索即可,中文的英文的应 ...