通常图片web上传后,会进行image.Decode() 解码、resize.Reszie()图片压缩、jpeg.Encode()编码保存等处理。
但部分图片在处理过后,图片显示会被旋转。通常在于苹果手机拍出的照片,而安卓手机正常。
这是苹果手机等设备拍照后,图片文件上带有orientation方向属性,系统打开显示时会自动根据方向属性进行调整,让我们看起来是正常的。
而后台处理后,orientation方向属性丢失(类似安卓手机拍的照片),导致保存后的新图片被旋转。
可以通过 github.com/rwcarlsen/goexif 包获取图片文件orientation方向属性,再处理期间进行图片旋转
以下为相关处理函数
注:个人感觉目前图片旋转处理方法效率不是很高,期待有人可以优化一下
import "github.com/rwcarlsen/goexif/exif"
//方向判断
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
}
// 旋转90度
func rotate90(m image.Image) image.Image {
rotate90 := image.NewRGBA(image.Rect(0, 0, m.Bounds().Dy(), m.Bounds().Dx()))
// 矩阵旋转
for x := m.Bounds().Min.Y; x < m.Bounds().Max.Y; x++ {
for y := m.Bounds().Max.X - 1; y >= m.Bounds().Min.X; y-- {
// 设置像素点
rotate90.Set(m.Bounds().Max.Y-x, y, m.At(y, x))
}
}
return rotate90
}
// 旋转180度
func rotate180(m image.Image) image.Image {
rotate180 := image.NewRGBA(image.Rect(0, 0, m.Bounds().Dx(), m.Bounds().Dy()))
// 矩阵旋转
for x := m.Bounds().Min.X; x < m.Bounds().Max.X; x++ {
for y := m.Bounds().Min.Y; y < m.Bounds().Max.Y; y++ {
// 设置像素点
rotate180.Set(m.Bounds().Max.X-x, m.Bounds().Max.Y-y, m.At(x, y))
}
}
return rotate180
}
// 旋转270度
func rotate270(m image.Image) image.Image {
rotate270 := image.NewRGBA(image.Rect(0, 0, m.Bounds().Dy(), m.Bounds().Dx()))
// 矩阵旋转
for x := m.Bounds().Min.Y; x < m.Bounds().Max.Y; x++ {
for y := m.Bounds().Max.X - 1; y >= m.Bounds().Min.X; y-- {
// 设置像素点
rotate270.Set(x, m.Bounds().Max.X-y, m.At(y, x))
}
}
return rotate270
}
ReadOrientation
方法会获取orientation
的值,总共有0~8这几种情况
orientationUnspecified = 0
orientationNormal = 1
orientationFlipH = 2
orientationRotate180 = 3
orientationFlipV = 4
orientationTranspose = 5
orientationRotate270 = 6
orientationTransverse = 7
orientationRotate90 = 8
实用参考例子
import "github.com/nfnt/resize"
//压缩图片
func MakeThumbnail(imagePath, savePath string) error {
ori := ReadOrientation(imagePath)
file, _ := os.Open(imagePath)
defer file.Close()
img, _, err := image.Decode(file)
if err != nil {
return err
}
//苹果手机拍照的图片,会有方向属性Orientation,
//经过Decode和Encode,编码处理后,方向属性会丢失,导致图片被旋转
switch ori {
case 6://90度图片旋转
img = rotate90(img)
case 3:
img = rotate180(img)
case 8:
img = rotate270(img)
}
w := 900
h := 1200
// 调用resize库进行图片缩放
m := resize.Resize(uint(w), uint(h), img, resize.Lanczos3)
// 需要保存的文件
imgfile, _ := os.Create(savePath)
defer imgfile.Close()
// 以jepg格式保存文件
err = jpeg.Encode(imgfile, m, &jpeg.Options{70})
if err != nil {
return err
}
return nil
}
func main(){
MakeThumbnail("原图.jpg","新图.jpg")
}