网站首页 返回列表 像“草根”一样,紧贴着地面,低调的存在,冬去春来,枯荣无恙。

63. 图片压缩

2020-06-10 02:56:09 admin 627

当客户端上传一张图片的时候,通常用户不会在意上传文件的大小。而服务端接收文件的时候,首先要保证客户原始文件的正确保存,但是到图片被调用的时候,图片如果过大的话,会占用很大的带宽。
于是有很多场景,要求服务端能够把图片变的小一点。
那么需要有原始图片,有压缩率,有目标大小,还有输出图片。先写个提示

__

  1. tips := []string{
  2. "输入参数:",
  3. "原始图片路径 输出图片压缩率 输出图片分辨率宽度 输出图片路径"}
  4. tipsLen := len(tips)
  5. for i := 0; i < tipsLen; i++ {
  6. fmt.Println(tips[i])
  7. }

这些语句可以输出一个提示信息。

提示信息

然后我们需要能够输入指令,并对参数进行分解。

__

  1. //--获取命令参数
  2. reader := bufio.NewReader(os.Stdin) //获取输入指令
  3. data, _, err := reader.ReadLine() //获取指令行信息
  4. if err != nil {
  5. fmt.Println(err)
  6. }else {
  7. strPice := strings.Split(string(data), " ") //以空格为分界,分解指令参数
  8. if len(strPice) < 4 {
  9. //--参数不足的时候执行(提示,并重新等待输入指令)
  10. fmt.Println("输入参数个数不足。需要四个参数:原始图片路径 输出图片压缩率 输出图片分辨率宽度 输出图片路径")
  11. play()
  12. return
  13. }else {
  14. //--参数充足,分解参数并初始化变量
  15. inputArgs.LocalPath = strPice[0]
  16. inputArgs.Quality, err = strconv.Atoi(strPice[1])
  17. if err != nil {
  18. inputArgs.Quality = 100 //默认不压缩
  19. }
  20. inputArgs.Width, err = strconv.Atoi(strPice[2])
  21. if err != nil {
  22. inputArgs.Width = 48 //默认常见ico图标宽度
  23. }
  24. inputArgs.OutputPath = strPice[3]

inputArgs是参数的结构,这里可以定义一个结构体,再声明一个变量。

__

  1. /**参数结构体*/
  2. type InputArgs struct {
  3. OutputPath string /** 输出目录 */
  4. LocalPath string /** 输入的目录或文件路径 */
  5. Quality int /** 质量 */
  6. Width int /** 宽度尺寸,像素单位 */
  7. Format string /** 格式 */
  8. }
  9. var inputArgs InputArgs

显然还需要一个必要的判断,检查输入的文件路径是否为图片路径。

__

  1. /**是否是图片,返回值: 路径,图片格式,图片名*/
  2. func isPic(path string) (string, string, string) {
  3. temp := strings.Split(path, ".")
  4. if len(temp) <= 1 {
  5. return "", "", ""
  6. }
  7. mapPicType := make(map[string]int64)
  8. mapPicType["jpg"] = 1
  9. mapPicType["jpeg"] = 1
  10. mapPicType["png"] = 1
  11. mapPicType["gif"] = 1
  12. mapPicType["bmp"] = 1
  13. if mapPicType[temp[1]] == 1 {
  14. fmt.Println(temp[1])
  15. return path, temp[1], temp[0]
  16. } else {
  17. return "", "", ""
  18. }
  19. }

这个函数,如果确定了是一个图片,就返回图片的相关信息。路径、图片格式(图片文件名后缀)、图片文件名称。如果不是图片,就返回空。
对各种格式的图片,采用相应的 Encode 方法。改变大小的操作,就没有重复造轮子了。引用”github.com/nfnt/resize”
编写imageCompress函数进行分别操作。

__

  1. func imageCompress(
  2. getReadSizeFile func() (io.Reader, error),
  3. getDecodeFile func() (*os.File, error),
  4. to string,
  5. Quality,
  6. base int,
  7. format string) bool {
  8. /** 读取文件 */
  9. file_origin, err := getDecodeFile()
  10. defer file_origin.Close()
  11. if err != nil {
  12. fmt.Println("os.Open(file)错误");
  13. log.Fatal(err)
  14. return false
  15. }
  16. var origin image.Image
  17. var config image.Config
  18. var temp io.Reader
  19. /** 读取尺寸 */
  20. temp, err = getReadSizeFile()
  21. if err != nil {
  22. fmt.Println("os.Open(temp)");
  23. log.Fatal(err)
  24. return false
  25. }
  26. var typeImage int64
  27. format = strings.ToLower(format)
  28. /** jpg 格式 */
  29. if format == "jpg" || format == "jpeg" {
  30. typeImage = 0
  31. origin, err = jpeg.Decode(file_origin)
  32. if err != nil {
  33. fmt.Println("jpeg.Decode(file_origin)");
  34. log.Fatal(err)
  35. return false
  36. }
  37. temp, err = getReadSizeFile()
  38. if err != nil {
  39. fmt.Println("os.Open(temp)");
  40. log.Fatal(err)
  41. return false
  42. }
  43. config, err = jpeg.DecodeConfig(temp);
  44. if err != nil {
  45. fmt.Println("jpeg.DecodeConfig(temp)");
  46. return false
  47. }
  48. } else if format == "png" {
  49. typeImage = 1
  50. origin, err = png.Decode(file_origin)
  51. if err != nil {
  52. fmt.Println("png.Decode(file_origin)");
  53. log.Fatal(err)
  54. return false
  55. }
  56. temp, err = getReadSizeFile()
  57. if err != nil {
  58. fmt.Println("os.Open(temp)");
  59. log.Fatal(err)
  60. return false
  61. }
  62. config, err = png.DecodeConfig(temp);
  63. if err != nil {
  64. fmt.Println("png.DecodeConfig(temp)");
  65. return false
  66. }
  67. } else if format == "gif" {
  68. typeImage = 2
  69. origin, err = gif.Decode(file_origin)
  70. if err != nil {
  71. fmt.Println("gif.Decode(file_origin)");
  72. log.Fatal(err)
  73. return false
  74. }
  75. temp, err = getReadSizeFile()
  76. if err != nil {
  77. fmt.Println("os.Open(temp)");
  78. log.Fatal(err)
  79. return false
  80. }
  81. config, err = gif.DecodeConfig(temp);
  82. if err != nil {
  83. fmt.Println("gif.DecodeConfig(temp)");
  84. return false
  85. }
  86. } else if format == "bmp" {
  87. typeImage = 3
  88. origin, err = bmp.Decode(file_origin)
  89. if err != nil {
  90. fmt.Println("bmp.Decode(file_origin)");
  91. log.Fatal(err)
  92. return false
  93. }
  94. temp, err = getReadSizeFile()
  95. if err != nil {
  96. fmt.Println("os.Open(temp)");
  97. log.Fatal(err)
  98. return false
  99. }
  100. config, err = bmp.DecodeConfig(temp);
  101. if err != nil {
  102. fmt.Println("bmp.DecodeConfig(temp)");
  103. return false
  104. }
  105. }
  106. /** 做等比缩放 */
  107. width := uint(base) /** 基准 */
  108. height := uint(base * config.Height / config.Width)
  109. canvas := resize.Thumbnail(width, height, origin, resize.Lanczos3)
  110. file_out, err := os.Create(to)
  111. defer file_out.Close()
  112. if err != nil {
  113. log.Fatal(err)
  114. return false
  115. }
  116. if typeImage == 0 {
  117. err = jpeg.Encode(file_out, canvas, &jpeg.Options{Quality})
  118. } else if typeImage == 1 {
  119. err = png.Encode(file_out, canvas)
  120. } else if typeImage == 2{
  121. //--需要再研究
  122. err = gif.Encode(file_out, canvas, &gif.Options{Quality, nil, nil})
  123. }else if typeImage == 3{
  124. err = bmp.Encode(file_out, canvas)
  125. }else {
  126. err = png.Encode(file_out, canvas)
  127. }
  128. if err != nil {
  129. fmt.Println("压缩图片失败");
  130. return false
  131. }
  132. return true
  133. }

其中 gif 格式还不完美。
完整代码

__

  1. /**
  2. * CofoxS
  3. * @Author: Jian Junbo
  4. * @Email: junbojian@qq.com
  5. * @Create: 2018/4/14 20:22
  6. * Copyright (c) 2018 Jian Junbo All rights reserved.
  7. *
  8. * Description:
  9. */
  10. package joelImageCompress
  11. import (
  12. "fmt"
  13. "runtime"
  14. "bufio"
  15. "os"
  16. "strings"
  17. "strconv"
  18. "io"
  19. "log"
  20. "image"
  21. "image/jpeg"
  22. "image/png"
  23. "image/gif"
  24. "github.com/nfnt/resize"
  25. "golang.org/x/image/bmp"
  26. )
  27. /**打印当前运行*/
  28. func Ggg() {
  29. for i := 0; i < 3; i++ {
  30. pc, file, line, ok := runtime.Caller(i)
  31. f := runtime.FuncForPC(pc)
  32. fmt.Println("This is 'runtime.Caller(", i, ")'", pc, ok, line, f.Name(), file)
  33. }
  34. }
  35. /**压缩图片_开始*/
  36. func Compress() {
  37. tips := []string{
  38. "输入参数:",
  39. "原始图片路径 输出图片压缩率 输出图片分辨率宽度 输出图片路径"}
  40. tipsLen := len(tips)
  41. for i := 0; i < tipsLen; i++ {
  42. fmt.Println(tips[i])
  43. }
  44. play()
  45. }
  46. /**执行*/
  47. func play() {
  48. //--获取命令参数
  49. reader := bufio.NewReader(os.Stdin) //获取输入指令
  50. data, _, err := reader.ReadLine() //获取指令行信息
  51. if err != nil {
  52. fmt.Println(err)
  53. } else {
  54. strPice := strings.Split(string(data), " ") //以空格为分界,分解指令参数
  55. if len(strPice) < 4 {
  56. //--参数不足的时候执行(提示,并重新等待输入指令)
  57. fmt.Println("输入参数个数不足。需要四个参数:原始图片路径 输出图片压缩率 输出图片分辨率宽度 输出图片路径")
  58. play()
  59. return
  60. } else {
  61. //--参数充足,分解参数并初始化变量
  62. inputArgs.LocalPath = strPice[0]
  63. inputArgs.Quality, err = strconv.Atoi(strPice[1])
  64. if err != nil {
  65. inputArgs.Quality = 100 //默认不压缩
  66. }
  67. inputArgs.Width, err = strconv.Atoi(strPice[2])
  68. if err != nil {
  69. inputArgs.Width = 48 //默认常见ico图标宽度
  70. }
  71. inputArgs.OutputPath = strPice[3]
  72. pathTemp, picType, picName := isPic(inputArgs.LocalPath)
  73. if pathTemp == "" {
  74. //--当前给出的不是一个图片
  75. log.Fatal("这不是图片")
  76. } else {
  77. //--当前给出的是一个图片
  78. //--设置当前输出
  79. if len(inputArgs.OutputPath) < 1 {
  80. inputArgs.OutputPath = picName + "_" + strconv.Itoa(inputArgs.Width) + "." + picType
  81. }
  82. if !imageCompress(
  83. func() (io.Reader, error) {
  84. return os.Open(inputArgs.LocalPath)
  85. },
  86. func() (*os.File, error) {
  87. return os.Open(inputArgs.LocalPath)
  88. },
  89. inputArgs.OutputPath,
  90. inputArgs.Quality,
  91. inputArgs.Width,
  92. picType) {
  93. fmt.Println("生成缩略图失败")
  94. } else {
  95. fmt.Println("生成缩略图成功")
  96. }
  97. Compress()
  98. }
  99. }
  100. }
  101. }
  102. /**是否是图片,返回值: 路径,图片格式,图片名*/
  103. func isPic(path string) (string, string, string) {
  104. temp := strings.Split(path, ".")
  105. if len(temp) <= 1 {
  106. return "", "", ""
  107. }
  108. mapPicType := make(map[string]int64)
  109. mapPicType["jpg"] = 1
  110. mapPicType["jpeg"] = 1
  111. mapPicType["png"] = 1
  112. mapPicType["gif"] = 1
  113. mapPicType["bmp"] = 1
  114. if mapPicType[temp[1]] == 1 {
  115. fmt.Println(temp[1])
  116. return path, temp[1], temp[0]
  117. } else {
  118. return "", "", ""
  119. }
  120. }
  121. /**参数结构体*/
  122. type InputArgs struct {
  123. OutputPath string /** 输出目录 */
  124. LocalPath string /** 输入的目录或文件路径 */
  125. Quality int /** 质量 */
  126. Width int /** 宽度尺寸,像素单位 */
  127. Format string /** 格式 */
  128. }
  129. var inputArgs InputArgs
  130. func imageCompress(
  131. getReadSizeFile func() (io.Reader, error),
  132. getDecodeFile func() (*os.File, error),
  133. to string,
  134. Quality,
  135. base int,
  136. format string) bool {
  137. /** 读取文件 */
  138. file_origin, err := getDecodeFile()
  139. defer file_origin.Close()
  140. if err != nil {
  141. fmt.Println("os.Open(file)错误");
  142. log.Fatal(err)
  143. return false
  144. }
  145. var origin image.Image
  146. var config image.Config
  147. var temp io.Reader
  148. /** 读取尺寸 */
  149. temp, err = getReadSizeFile()
  150. if err != nil {
  151. fmt.Println("os.Open(temp)");
  152. log.Fatal(err)
  153. return false
  154. }
  155. var typeImage int64
  156. format = strings.ToLower(format)
  157. /** jpg 格式 */
  158. if format == "jpg" || format == "jpeg" {
  159. typeImage = 0
  160. origin, err = jpeg.Decode(file_origin)
  161. if err != nil {
  162. fmt.Println("jpeg.Decode(file_origin)");
  163. log.Fatal(err)
  164. return false
  165. }
  166. temp, err = getReadSizeFile()
  167. if err != nil {
  168. fmt.Println("os.Open(temp)");
  169. log.Fatal(err)
  170. return false
  171. }
  172. config, err = jpeg.DecodeConfig(temp);
  173. if err != nil {
  174. fmt.Println("jpeg.DecodeConfig(temp)");
  175. return false
  176. }
  177. } else if format == "png" {
  178. typeImage = 1
  179. origin, err = png.Decode(file_origin)
  180. if err != nil {
  181. fmt.Println("png.Decode(file_origin)");
  182. log.Fatal(err)
  183. return false
  184. }
  185. temp, err = getReadSizeFile()
  186. if err != nil {
  187. fmt.Println("os.Open(temp)");
  188. log.Fatal(err)
  189. return false
  190. }
  191. config, err = png.DecodeConfig(temp);
  192. if err != nil {
  193. fmt.Println("png.DecodeConfig(temp)");
  194. return false
  195. }
  196. } else if format == "gif" {
  197. typeImage = 2
  198. origin, err = gif.Decode(file_origin)
  199. if err != nil {
  200. fmt.Println("gif.Decode(file_origin)");
  201. log.Fatal(err)
  202. return false
  203. }
  204. temp, err = getReadSizeFile()
  205. if err != nil {
  206. fmt.Println("os.Open(temp)");
  207. log.Fatal(err)
  208. return false
  209. }
  210. config, err = gif.DecodeConfig(temp);
  211. if err != nil {
  212. fmt.Println("gif.DecodeConfig(temp)");
  213. return false
  214. }
  215. } else if format == "bmp" {
  216. typeImage = 3
  217. origin, err = bmp.Decode(file_origin)
  218. if err != nil {
  219. fmt.Println("bmp.Decode(file_origin)");
  220. log.Fatal(err)
  221. return false
  222. }
  223. temp, err = getReadSizeFile()
  224. if err != nil {
  225. fmt.Println("os.Open(temp)");
  226. log.Fatal(err)
  227. return false
  228. }
  229. config, err = bmp.DecodeConfig(temp);
  230. if err != nil {
  231. fmt.Println("bmp.DecodeConfig(temp)");
  232. return false
  233. }
  234. }
  235. /** 做等比缩放 */
  236. width := uint(base) /** 基准 */
  237. height := uint(base * config.Height / config.Width)
  238. canvas := resize.Thumbnail(width, height, origin, resize.Lanczos3)
  239. file_out, err := os.Create(to)
  240. defer file_out.Close()
  241. if err != nil {
  242. log.Fatal(err)
  243. return false
  244. }
  245. if typeImage == 0 {
  246. err = jpeg.Encode(file_out, canvas, &jpeg.Options{Quality})
  247. } else if typeImage == 1 {
  248. err = png.Encode(file_out, canvas)
  249. } else if typeImage == 2{
  250. //--需要再研究
  251. err = gif.Encode(file_out, canvas, &gif.Options{Quality, nil, nil})
  252. }else if typeImage == 3{
  253. err = bmp.Encode(file_out, canvas)
  254. }else {
  255. err = png.Encode(file_out, canvas)
  256. }
  257. if err != nil {
  258. fmt.Println("压缩图片失败");
  259. return false
  260. }
  261. return true
  262. }

调用代码

__

  1. joelImageCompress. Compress()

运行指令

__

  1. e :\quan.jpg 75 300 e:\quan_ok.jpg

我在 e 盘的根上放置了一张 quan.jpg 图片。就针对它操作了。

运行结果

图片效果

运行结果

图片效果

经过测试,如果图片的后缀是被修改过的(例如jpeg改成png),会有失败的情况发生。因此,本例是不完美的解决方案。

转载文章,原文链接: 63. 图片压缩

关键字词压缩图片

分享到:

如需留言,请 登录,没有账号?请 注册

0 条评论 0 人参与

顶部 底部