Golang 編寫的圖片壓縮程序,質量、尺寸壓縮,批量、單張壓縮

目錄:git

  前序github

  效果圖golang

  簡介canvas

  所有代碼函數

 

前序:ui

  接觸 golang 不久,一直是邊學邊作,邊總結,深深感到這門語言的魅力,等下要跟你們分享是最近項目 服務端 用到的圖片壓縮程序,我單獨分離了出來,作成了 exe 程序,能夠在 Window 下運行。也能夠放到 Linux 環境下編譯運行,golang 是一種靜態、跨平臺的語言。spa

 

效果圖3d

    -code

  

壓縮前 壓縮後orm

 

開始main:

  showTips 作了一些有好提示的文字輸出,execute 是核心,壓縮函數的調用也在裏面

1 func main() {
2     showTips()
3     execute()
4     time.Sleep(5 * time.Minute) /** 若是不是本身點擊退出,延時5分鐘 */
5 }

 

 提示函數

  我分離了兩種壓縮形式,批量和單張,再組合質量和尺寸,壓縮100張600K的圖片到8~9K,200px寬度,僅用了6秒左右,win 10,12G,i5,ssd。

  還能夠作徹底的,寬和高像素尺寸的限制,只須要改變幾個參數,你們先來看看程序運行的時候顯示給用戶的提示信息:

  對於批量壓縮,自動遍歷用戶輸入的文件夾裏面的全部符合格式的文件,並進行壓縮。

 1 func showTips()  {
 2     tips := []string{
 3         "請輸入文件夾或圖片路徑:",
 4         "若是輸入文件夾,那麼該目錄的圖片將會被批量壓縮;",
 5         "若是是圖片路徑,那麼將會被單獨壓縮處理。",
 6         "例如:",
 7         "C:/Users/lzq/Desktop/headImages/ 75 200",
 8         "指桌面 headImages 文件夾,裏面的圖片質量壓縮到75%,寬分辨率爲200,高是等比例計算",
 9         "C:/Users/lzq/Desktop/headImages/1.jpg 75 200",
10         "指桌面的 headImages 文件夾裏面的 1.jpg 圖片,質量壓縮到75%,寬分辨率爲200,高是等比例計算 ",
11         "請輸入:"}
12     itemLen := len(tips)
13     for i :=0;i<itemLen;i++ {
14         if i == itemLen -1 {
15             fmt.Printf(tips[i])
16         }else{
17             fmt.Println(tips[i])
18         }
19     }
20 }

 

壓縮結構體:

  這個比較簡單,其他添加能夠自定義

1 type InputArgs struct {
2     OutputPath string  /** 輸出目錄 */
3     LocalPath  string  /** 輸入的目錄或文件路徑 */
4     Quality    int     /** 質量 */
5     Width      int     /** 寬度尺寸,像素單位 */
6 }

 

圖片格式驗證

  自定義支持的文件格式,主要是圖片的格式,同時拆分返回一些關鍵的信息,例如尾綴

 1 /** 是不是圖片 */
 2 func isPictureFormat(path string) (string,string,string) {
 3     temp := strings.Split(path,".")
 4     if len(temp) <=1 {
 5         return "","",""
 6     }
 7     mapRule := make(map[string]int64)
 8     mapRule["jpg"]  = 1
 9     mapRule["png"]  = 1
10     mapRule["jpeg"] = 1
11     // fmt.Println(temp[1]+"---")
12     /** 添加其餘格式 */
13     if mapRule[temp[1]] == 1  {
14         println(temp[1])
15         return path,temp[1],temp[0]
16     }else{
17         return "","",""
18     }
19 }

 

文件夾遍歷

  主要用於批量壓縮,作了所輸入的目錄的圖片文件遍歷,和要保存到的文件夾的建立,和採用納秒級作壓縮後的圖片的名稱。

 1 func getFilelist(path string) {
 2     /** 建立輸出目錄 */
 3     errC := os.MkdirAll(inputArgs.OutputPath, 0777)
 4     if errC != nil {
 5         fmt.Printf("%s", errC)
 6         return
 7     }
 8     err := filepath.Walk(path, func(pathFound string, f os.FileInfo, err error) error {
 9         if ( f == nil ) {
10             return err
11         }
12         if f.IsDir() { /** 是不是目錄 */
13             return nil
14         }
15         // println(pathFound)
16         /** 找到一個文件 */
17         /** 判斷是否是圖片 */
18         localPath,format,_ := isPictureFormat(pathFound)
19         /** 隨機數 */
20         t := time.Now()
21         millis := t.Nanosecond() /** 納秒 */
22         outputPath := inputArgs.OutputPath+strconv.FormatInt(int64(millis),10)+"."+format
23         if localPath!="" {
24             if !imageCompress(
25                 func() (io.Reader,error){
26                     return os.Open(localPath)
27                 },
28                 func() (*os.File,error) {
29                     return os.Open(localPath)
30                 },
31                 outputPath,
32                 inputArgs.Quality,
33                 inputArgs.Width,format) {
34                 fmt.Println("生成縮略圖失敗")
35             }else{
36                 fmt.Println("生成縮略圖成功 "+outputPath)
37             }
38         }
39         return nil
40     })
41     if err != nil {
42         fmt.Printf("輸入的路徑信息有誤 %v\n", err)
43     }
44 }

 

壓縮前處理函數:

  主要作了壓縮結構體數據的配置,和驗證用戶路徑的輸入以及最終壓縮輸出文件目錄的路徑組合。這裏有個坑點,對於控制檯的數據獲取,最好使用 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) < 3 {
        fmt.Printf("輸入有誤,參數數量不足,請從新輸入或退出程序:")
        execute()
        return
    }

    inputArgs.LocalPath = strPice[0]
    inputArgs.Quality,_ = strconv.Atoi(strPice[1])
    inputArgs.Width,_   = strconv.Atoi(strPice[2])

    pathTemp,format,top := isPictureFormat(inputArgs.LocalPath)
    if pathTemp == "" {
        /** 目錄 */
        /** 若是輸入目錄,那麼是批量 */
        fmt.Println("開始批量壓縮...")
        rs := []rune(inputArgs.LocalPath)
        end := len(rs)
        substr := string(rs[end-1:end])
        if substr=="/" {
            /** 有 / */
            rs := []rune(inputArgs.LocalPath)
            end := len(rs)
            substr := string(rs[0:end-1])
            endIndex := strings.LastIndex(substr,"/")
            inputArgs.OutputPath = string(rs[0:endIndex])+"/LghImageCompress/";
        }else {
            endIndex := strings.LastIndex(inputArgs.LocalPath,"/")
            inputArgs.OutputPath = string(rs[0: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 庫。所謂的寬高徹底自定義的修改,就在這裏,我是採用了等比例縮放,因此只須要傳入其中一項。裏面分兩次讀寫同一個文件是由於一次用於尺寸讀取,並且兩次是不能共用的,會出錯。

 

 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 = 1
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 = 0
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     }
68     /** 作等比縮放 */
69     width  := uint(base) /** 基準 */
70     height := uint(base*config.Height/config.Width)
71 
72     canvas := resize.Thumbnail(width, height, origin, resize.Lanczos3)
73     file_out, err := os.Create(to)
74     defer file_out.Close()
75     if err != nil {
76         log.Fatal(err)
77         return false
78     }
79     if typeImage==0 {
80         err = png.Encode(file_out, canvas)
81         if err!=nil {
82             fmt.Println("壓縮圖片失敗");
83             return false
84         }
85     }else{
86         err = jpeg.Encode(file_out, canvas, &jpeg.Options{Quality})
87         if err!=nil {
88             fmt.Println("壓縮圖片失敗");
89             return false
90         }
91     }
92 
93     return true
94 }

 

 

 

 

所有代碼

  gitHub: https://github.com/af913337456/golang_image_compress

相關文章
相關標籤/搜索