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图片没有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
//弧度转换
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")根据方向值,旋转图片
if err != nil {
fmt.Println(err)
return
}
fmt.Println(ori)
//根据图片原始信息的Orientation判断需要转多少度
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 批量创建文件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()}...))
}
// 批量创建文件
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 创建文件 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】打开失败,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
}
// ======= 根据相机图片原始信息的Orientation判断需要转多少度 =======
// 为什么不直接使用imgFile 而使用 bytes.NewReader(data),原因:无论image.Decode和image.DecodeConfig消耗从传入的字节io.Reade,imgFile已在ioutil.ReadAll中消费过,说明: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 {
// 非相机照片处理逻辑
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】格式错误,仅支持.jpg、.jpeg、.png格式", fileName)
return
}
if err != nil {
err = fmt.Errorf(fmt.Sprintf("文件【%s】读取发送错误,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"))
}
网友评论