當(dāng)客戶端上傳一張圖片的時(shí)候,通常用戶不會(huì)在意上傳文件的大小。而服務(wù)端接收文件的時(shí)候,首先要保證客戶原始文件的正確保存,但是到圖片被調(diào)用的時(shí)候,圖片如果過大的話,會(huì)占用很大的帶寬。
于是有很多場景,要求服務(wù)端能夠把圖片變的小一點(diǎn)。
那么需要有原始圖片,有壓縮率,有目標(biāo)大小,還有輸出圖片。先寫個(gè)提示
tips := []string{
"輸入?yún)?shù):",
"原始圖片路徑 輸出圖片壓縮率 輸出圖片分辨率寬度 輸出圖片路徑"}
tipsLen := len(tips)
for i := 0; i < tipsLen; i++ {
fmt.Println(tips[i])
}
這些語句可以輸出一個(gè)提示信息。

提示信息
然后我們需要能夠輸入指令,并對(duì)參數(shù)進(jìn)行分解。
//--獲取命令參數(shù)
reader := bufio.NewReader(os.Stdin) //獲取輸入指令
data, _, err := reader.ReadLine() //獲取指令行信息
if err != nil {
fmt.Println(err)
}else {
strPice := strings.Split(string(data), " ") //以空格為分界,分解指令參數(shù)
if len(strPice) < 4 {
//--參數(shù)不足的時(shí)候執(zhí)行(提示,并重新等待輸入指令)
fmt.Println("輸入?yún)?shù)個(gè)數(shù)不足。需要四個(gè)參數(shù):原始圖片路徑 輸出圖片壓縮率 輸出圖片分辨率寬度 輸出圖片路徑")
play()
return
}else {
//--參數(shù)充足,分解參數(shù)并初始化變量
inputArgs.LocalPath = strPice[0]
inputArgs.Quality, err = strconv.Atoi(strPice[1])
if err != nil {
inputArgs.Quality = 100 //默認(rèn)不壓縮
}
inputArgs.Width, err = strconv.Atoi(strPice[2])
if err != nil {
inputArgs.Width = 48 //默認(rèn)常見ico圖標(biāo)寬度
}
inputArgs.OutputPath = strPice[3]
inputArgs是參數(shù)的結(jié)構(gòu),這里可以定義一個(gè)結(jié)構(gòu)體,再聲明一個(gè)變量。
/**參數(shù)結(jié)構(gòu)體*/
type InputArgs struct {
OutputPath string /** 輸出目錄 */
LocalPath string /** 輸入的目錄或文件路徑 */
Quality int /** 質(zhì)量 */
Width int /** 寬度尺寸,像素單位 */
Format string /** 格式 */
}
var inputArgs InputArgs
顯然還需要一個(gè)必要的判斷,檢查輸入的文件路徑是否為圖片路徑。
/**是否是圖片,返回值: 路徑,圖片格式,圖片名*/
func isPic(path string) (string, string, string) {
temp := strings.Split(path, ".")
if len(temp) <= 1 {
return "", "", ""
}
mapPicType := make(map[string]int64)
mapPicType["jpg"] = 1
mapPicType["jpeg"] = 1
mapPicType["png"] = 1
mapPicType["gif"] = 1
mapPicType["bmp"] = 1
if mapPicType[temp[1]] == 1 {
fmt.Println(temp[1])
return path, temp[1], temp[0]
} else {
return "", "", ""
}
}
這個(gè)函數(shù),如果確定了是一個(gè)圖片,就返回圖片的相關(guān)信息。路徑、圖片格式(圖片文件名后綴)、圖片文件名稱。如果不是圖片,就返回空。
對(duì)各種格式的圖片,采用相應(yīng)的 Encode 方法。改變大小的操作,就沒有重復(fù)造輪子了。引用"github.com/nfnt/resize"
編寫imageCompress函數(shù)進(jìn)行分別操作。
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)錯(cuò)誤");
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 = 0
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 = 1
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
}
} else if format == "gif" {
typeImage = 2
origin, err = gif.Decode(file_origin)
if err != nil {
fmt.Println("gif.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 = gif.DecodeConfig(temp);
if err != nil {
fmt.Println("gif.DecodeConfig(temp)");
return false
}
} else if format == "bmp" {
typeImage = 3
origin, err = bmp.Decode(file_origin)
if err != nil {
fmt.Println("bmp.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 = bmp.DecodeConfig(temp);
if err != nil {
fmt.Println("bmp.DecodeConfig(temp)");
return false
}
}
/** 做等比縮放 */
width := uint(base) /** 基準(zhǔn) */
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 == 0 {
err = jpeg.Encode(file_out, canvas, &jpeg.Options{Quality})
} else if typeImage == 1 {
err = png.Encode(file_out, canvas)
} else if typeImage == 2{
//--需要再研究
err = gif.Encode(file_out, canvas, &gif.Options{Quality, nil, nil})
}else if typeImage == 3{
err = bmp.Encode(file_out, canvas)
}else {
err = png.Encode(file_out, canvas)
}
if err != nil {
fmt.Println("壓縮圖片失敗");
return false
}
return true
}
其中 gif 格式還不完美。
完整代碼
/**
* CofoxS
* @Author: Jian Junbo
* @Email: junbojian@qq.com
* @Create: 2018/4/14 20:22
* Copyright (c) 2018 Jian Junbo All rights reserved.
*
* Description:
*/
package joelImageCompress
import (
"fmt"
"runtime"
"bufio"
"os"
"strings"
"strconv"
"io"
"log"
"image"
"image/jpeg"
"image/png"
"image/gif"
"github.com/nfnt/resize"
"golang.org/x/image/bmp"
)
/**打印當(dāng)前運(yùn)行*/
func Ggg() {
for i := 0; i < 3; i++ {
pc, file, line, ok := runtime.Caller(i)
f := runtime.FuncForPC(pc)
fmt.Println("This is 'runtime.Caller(", i, ")'", pc, ok, line, f.Name(), file)
}
}
/**壓縮圖片_開始*/
func Compress() {
tips := []string{
"輸入?yún)?shù):",
"原始圖片路徑 輸出圖片壓縮率 輸出圖片分辨率寬度 輸出圖片路徑"}
tipsLen := len(tips)
for i := 0; i < tipsLen; i++ {
fmt.Println(tips[i])
}
play()
}
/**執(zhí)行*/
func play() {
//--獲取命令參數(shù)
reader := bufio.NewReader(os.Stdin) //獲取輸入指令
data, _, err := reader.ReadLine() //獲取指令行信息
if err != nil {
fmt.Println(err)
} else {
strPice := strings.Split(string(data), " ") //以空格為分界,分解指令參數(shù)
if len(strPice) < 4 {
//--參數(shù)不足的時(shí)候執(zhí)行(提示,并重新等待輸入指令)
fmt.Println("輸入?yún)?shù)個(gè)數(shù)不足。需要四個(gè)參數(shù):原始圖片路徑 輸出圖片壓縮率 輸出圖片分辨率寬度 輸出圖片路徑")
play()
return
} else {
//--參數(shù)充足,分解參數(shù)并初始化變量
inputArgs.LocalPath = strPice[0]
inputArgs.Quality, err = strconv.Atoi(strPice[1])
if err != nil {
inputArgs.Quality = 100 //默認(rèn)不壓縮
}
inputArgs.Width, err = strconv.Atoi(strPice[2])
if err != nil {
inputArgs.Width = 48 //默認(rèn)常見ico圖標(biāo)寬度
}
inputArgs.OutputPath = strPice[3]
pathTemp, picType, picName := isPic(inputArgs.LocalPath)
if pathTemp == "" {
//--當(dāng)前給出的不是一個(gè)圖片
log.Fatal("這不是圖片")
} else {
//--當(dāng)前給出的是一個(gè)圖片
//--設(shè)置當(dāng)前輸出
if len(inputArgs.OutputPath) < 1 {
inputArgs.OutputPath = picName + "_" + strconv.Itoa(inputArgs.Width) + "." + picType
}
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,
picType) {
fmt.Println("生成縮略圖失敗")
} else {
fmt.Println("生成縮略圖成功")
}
Compress()
}
}
}
}
/**是否是圖片,返回值: 路徑,圖片格式,圖片名*/
func isPic(path string) (string, string, string) {
temp := strings.Split(path, ".")
if len(temp) <= 1 {
return "", "", ""
}
mapPicType := make(map[string]int64)
mapPicType["jpg"] = 1
mapPicType["jpeg"] = 1
mapPicType["png"] = 1
mapPicType["gif"] = 1
mapPicType["bmp"] = 1
if mapPicType[temp[1]] == 1 {
fmt.Println(temp[1])
return path, temp[1], temp[0]
} else {
return "", "", ""
}
}
/**參數(shù)結(jié)構(gòu)體*/
type InputArgs struct {
OutputPath string /** 輸出目錄 */
LocalPath string /** 輸入的目錄或文件路徑 */
Quality int /** 質(zhì)量 */
Width int /** 寬度尺寸,像素單位 */
Format string /** 格式 */
}
var inputArgs InputArgs
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)錯(cuò)誤");
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 = 0
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 = 1
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
}
} else if format == "gif" {
typeImage = 2
origin, err = gif.Decode(file_origin)
if err != nil {
fmt.Println("gif.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 = gif.DecodeConfig(temp);
if err != nil {
fmt.Println("gif.DecodeConfig(temp)");
return false
}
} else if format == "bmp" {
typeImage = 3
origin, err = bmp.Decode(file_origin)
if err != nil {
fmt.Println("bmp.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 = bmp.DecodeConfig(temp);
if err != nil {
fmt.Println("bmp.DecodeConfig(temp)");
return false
}
}
/** 做等比縮放 */
width := uint(base) /** 基準(zhǔn) */
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 == 0 {
err = jpeg.Encode(file_out, canvas, &jpeg.Options{Quality})
} else if typeImage == 1 {
err = png.Encode(file_out, canvas)
} else if typeImage == 2{
//--需要再研究
err = gif.Encode(file_out, canvas, &gif.Options{Quality, nil, nil})
}else if typeImage == 3{
err = bmp.Encode(file_out, canvas)
}else {
err = png.Encode(file_out, canvas)
}
if err != nil {
fmt.Println("壓縮圖片失敗");
return false
}
return true
}
調(diào)用代碼
joelImageCompress.Compress()
運(yùn)行指令
e:\quan.jpg 75 300 e:\quan_ok.jpg
我在 e 盤的根上放置了一張 quan.jpg 圖片。就針對(duì)它操作了。

運(yùn)行結(jié)果

圖片效果

運(yùn)行結(jié)果

圖片效果
經(jīng)過測(cè)試,如果圖片的后綴是被修改過的(例如jpeg改成png),會(huì)有失敗的情況發(fā)生。因此,本例是不完美的解決方案。