1. 程式人生 > >異想家部落格圖片批量壓縮程式

異想家部落格圖片批量壓縮程式

為了方便給自己的部落格配圖,用Golang寫了一個指令碼處理,現分享出來,有需要的朋友也可以參考修改使用。

壓縮規則

1、圖片都等比例壓縮,不破壞長寬比。

2、如果是橫屏圖片,壓縮到寬度為1280,高度適應。

3、如果是豎屏圖片,壓縮到高度為1000,寬度適應。

4、如果解析度小於這個,不壓縮。

5、支援png、jpg、jpeg。

使用方法

go build jfzBlogPicCompress.go

原圖放在當前目錄下的raw目錄中,壓縮後的圖片生成在thumb目錄下,執行生成的二進位制檔案即可,壓縮完5s後程序退出。

原始碼

檔名jfzBlogPicCompress.go:

package main

import (
    "fmt"
    "github.com/nfnt/resize"
    "image"
    "image/jpeg"
    "image/png"
    "io"
    "log"
    "os"
    "path/filepath"
    "strings"
    "time"
)

type InputArgs struct {
    OutputPath string /** 輸出目錄 */
    LocalPath  string /** 輸入的目錄或檔案路徑 */
    Quality    int    /** 質量 */
    Width      int    /** 寬度尺寸,畫素單位 */
    Format     string /** 格式 */
}

var inputArgs InputArgs

func main() {
    execute()
    fmt.Printf("處理完成,5秒後自動退出……")
    time.Sleep(5 * time.Second) /** 如果不是自己點選退出,延時5s */
}

//  執行壓縮
func execute() {
    fmt.Println("開始批量壓縮...")

    inputArgs.LocalPath = "./raw/"
    inputArgs.OutputPath = "./thumb/"
    inputArgs.Quality = 90
    inputArgs.Width = 1280
    fmt.Println("壓縮規則:寬度1280,如果是豎圖,高度1000  壓縮質量:", inputArgs.Quality)

    GetFilelist(inputArgs.LocalPath)
    fmt.Println("圖片儲存在:" + inputArgs.OutputPath)
}

// 遍歷輸入原圖目錄的圖片
func GetFilelist(path string) {
    /** 建立輸出目錄 */
    errC := os.MkdirAll(inputArgs.OutputPath, 0777)
    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
        }
        // 檔案是否是圖片
        localPath, format, _ := isPictureFormat(pathFound)
        outputPath := strings.Replace(localPath, "raw", "thumb", 1)
        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)
    }
}

// 壓縮演算法
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)
    if format == "jpg" || format == "jpeg" {
        // jpg 格式 1
        typeImage = 1
        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" {
        // png 格式 0
        typeImage = 0
        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
        }
    }
    // 等比縮放(壓縮到1280的寬,如果圖片是豎著的,限定高最多1000)
    fixBase := base
    heightBase := fixBase * config.Height / config.Width
    if config.Height > config.Width {
        heightBase = 1000
        fixBase = heightBase * config.Width / config.Height
    }

    // 基準
    width := uint(fixBase)
    height := uint(heightBase)

    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 == 0 {
        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
}

// 是否是圖片
func isPictureFormat(path string) (string, string, string) {
    temp := strings.Split(path, ".")
    if len(temp) <= 1 {
        return "", "", ""
    }
    mapRule := make(map[string]int64)
    // 在這裡可以新增其他格式
    mapRule["jpg"] = 1
    mapRule["JPG"] = 1
    mapRule["png"] = 1
    mapRule["PNG"] = 1
    mapRule["jpeg"] = 1
    mapRule["JPEG"] = 1
    if mapRule[temp[1]] == 1 {
        println(temp[1])
        return path, temp[1], temp[0]
    } else {
        return "", "", ""
    }
}

參考

程式碼參考了golang_image_compress,改為了適合自己部落格使用,源程式的程式碼更通用,更推薦在它基礎上修改