1、指定路徑處理
package main
import (
"bytes"
"fmt"
"image"
"image/jpeg"
"io/ioutil"
"math"
"os"
"code.google.com/p/graphics-go/graphics"
"github.com/rwcarlsen/goexif/exif"
)
// png圖片沒(méi)有Orientation信息
func ReadOrientation(filename string) int {
file, err := os.Open(filename)
if err != nil {
fmt.Println("failed to open file, err: ", err)
return 0
}
defer file.Close()
x, err := exif.Decode(file)
if err != nil {
fmt.Println("failed to decode file, err: ", err)
return 0
}
orientation, err := x.Get(exif.Orientation)
if err != nil {
fmt.Println("failed to get orientation, err: ", err)
return 0
}
orientVal, err := orientation.Int(0)
if err != nil {
fmt.Println("failed to convert type of orientation, err: ", err)
return 0
}
fmt.Println("the value of photo orientation is :", orientVal)
return orientVal
}
func RotateImage(src []byte, angle int) ([]byte, error) {
var img, _, err = image.Decode(bytes.NewReader(src))
//var img, err = GetImage(src)
if err != nil {
return src, err
}
angle = angle % 360
//弧度轉(zhuǎn)換
radian := float64(angle) * math.Pi / 180.0
cos := math.Cos(float64(radian))
sin := math.Sin(radian)
//原圖的寬高
w := float64(img.Bounds().Dx())
h := float64(img.Bounds().Dy())
//新圖高寬
W := int((math.Max(math.Abs(float64(w*cos-h*sin)), math.Abs(w*cos+h*sin))))
H := int((math.Max(math.Abs(w*sin-h*cos), math.Abs(w*sin+h*cos))))
dst := image.NewNRGBA(image.Rect(0, 0, W, H))
err = graphics.Rotate(dst, img, &graphics.RotateOptions{radian})
if err != nil {
return src, err
}
file, err := os.Create("newImage.jpg")
if err != nil {
return src, err
}
defer file.Close()
err = jpeg.Encode(file, dst, &jpeg.Options{50})
if err != nil {
return src, err
}
return nil, nil
}
func main() {
ori := ReadOrientation("bebRotated.jpg")//先讀取該圖片的原始方向拄氯,方向值參考上圖平项,
data, err := ioutil.ReadFile("bebRotated.jpg")根據(jù)方向值疟呐,旋轉(zhuǎn)圖片
if err != nil {
fmt.Println(err)
return
}
fmt.Println(ori)
//根據(jù)圖片原始信息的Orientation判斷需要轉(zhuǎn)多少度
if ori == 6 {
RotateImage(data, 90)
}
if ori == 3 {
RotateImage(data, 180)
}
if ori == 8 {
RotateImage(data, 270)
}
}
2、上傳文件方式處理
package main
import (
"bytes"
"fmt"
"image"
"image/jpeg"
"image/png"
"io/ioutil"
"mime/multipart"
"net/http"
"os"
"path"
"strings"
"testing"
"github.com/labstack/echo"
)
func uploadImage(c echo.Context) error {
return createFiles(c, "out/", "/index.html")
}
// createFiles 批量創(chuàng)建文件createFiles(file,"public/crops/","/result_crop")
func createFiles(c echo.Context, savePath, resultUrl string) (err error) {
savePath = GetPath(savePath)
var form *multipart.Form
form, err = c.MultipartForm()
if err != nil {
err = c.String(http.StatusOK, fmt.Sprintf("獲取文件失敗埋酬,error:%s", err.Error()))
return
}
files := form.File["files"]
if len(files) <= 0 {
err = c.String(http.StatusOK, "未上傳任何文件")
return
}
// 清除歷史目錄中的圖片
var dir []os.FileInfo
dir, err = ioutil.ReadDir(savePath)
if err != nil {
err = c.String(http.StatusOK, fmt.Sprintf("文件名目錄不存在哨啃,savePath:%s", savePath))
}
for _, d := range dir {
os.RemoveAll(path.Join([]string{savePath, d.Name()}...))
}
// 批量創(chuàng)建文件
for _, file := range files {
err = createFile(file, savePath)
if err != nil {
return c.String(http.StatusOK, err.Error())
}
}
return c.HTML(http.StatusOK, fmt.Sprintf("<p> successfully </p><script>location.href='%s'</script>", resultUrl))
}
// createFile 創(chuàng)建文件 createFile(file,"public/crops/")
func createFile(file *multipart.FileHeader, savePath string) (err error) {
var img image.Image
img, err = getFileImage(file)
if err != nil {
return
}
// create image file
out, err := os.Create(savePath + file.Filename)
if err != nil {
return err
}
defer out.Close()
// write new image to file
err = jpeg.Encode(out, img, nil)
if err != nil {
return err
}
return
}
func getFileImage(file *multipart.FileHeader) (img image.Image, err error) {
var fileName, ext string
src, err := file.Open()
if err != nil {
err = fmt.Errorf("文件【%s】打開(kāi)失敗,error:%s", fileName, err.Error())
return
}
defer src.Close()
fileName = strings.ToLower(file.Filename)
ext = path.Ext(file.Filename)
if ext == ".jpg" || ext == ".jpeg" {
var data []byte
data, err = ioutil.ReadAll(src)
if err != nil {
err = fmt.Errorf("文件【%s】讀取失敗写妥,error:%s", fileName, err.Error())
return
}
// ======= 根據(jù)相機(jī)圖片原始信息的Orientation判斷需要轉(zhuǎn)多少度 =======
// 為什么不直接使用imgFile 而使用 bytes.NewReader(data)拳球,原因:無(wú)論image.Decode和image.DecodeConfig消耗從傳入的字節(jié)io.Reade,imgFile已在ioutil.ReadAll中消費(fèi)過(guò)珍特,說(shuō)明:https://stackoverflow.com/questions/62846156/image-decode-unknown-format
ori := ReadOrientation(bytes.NewReader(data))
if ori == 6 {
img, err = RotateImage(bytes.NewReader(data), 90)
} else if ori == 3 {
img, err = RotateImage(bytes.NewReader(data), 180)
} else if ori == 8 {
img, err = RotateImage(bytes.NewReader(data), 270)
} else {
// 非相機(jī)照片處理邏輯
img, err = jpeg.Decode(bytes.NewReader(data))
}
if err != nil {
err = fmt.Errorf("處理文件【%s】失敗祝峻,ori:%d,error:%s", fileName, ori, err.Error())
return
}
} else if ext == ".png" {
img, err = png.Decode(src)
} else {
err = fmt.Errorf("文件【%s】格式錯(cuò)誤扎筒,僅支持.jpg莱找、.jpeg、.png格式", fileName)
return
}
if err != nil {
err = fmt.Errorf(fmt.Sprintf("文件【%s】讀取發(fā)送錯(cuò)誤嗜桌,error:%s", fileName, err.Error()))
return
}
return
}
func TestImage(t *testing.T) {
e := echo.New()
e.POST("/uploadImage", uploadImage)
e.Logger.Fatal(e.Start(":8081"))
}