Golang 如何在不旋转的情况下上传外部图像
Golang how can I upload external images without rotating them
几周来我一直在研究图像上传功能,我即将完成它。我使用 Golang 作为后端语言,其目的是将从 IOS 设备发送的图像上传到 amazon s3 。在上传图像的过程中,我也调整了它们的大小,这主要导致了问题 decode 方法有时会旋转我不想要的图像
file, handler, err := r.FormFile("file")
if err != nil {
fmt.Println("Error Uploading Image")
return
}
defer file.Close()
// the code below sometimes rotates an image
img,err := imaging.Decode(file)
if err != nil {
print("Imaging Open error")
}
new_image := imaging.Resize(img,400,400, imaging.Lanczos)
我正在使用的库是这个 https://github.com/disintegration/imaging 这太棒了,他们展示的例子是这个
src, err := imaging.Open("testdata/lena_512.png")
if err != nil {
log.Fatalf("Open failed: %v", err)
}
src = imaging.Resize(src, 256, 0, imaging.Lanczos)
这个例子很好,但是我的图像没有存储在本地,它们来自 IOS 设备,我可以做些什么来解决这个问题吗?我的一些图片是这样保存的
有些图像是这样旋转的,这是解码方法做的
我可以通过 旋转 图像来纠正它,但是其他一些没有被 decode 旋转的图像最终被旋转旋转 270 方法 .
img,err := imaging.Decode(file)
if err != nil {
print("Imaging Open error")
}
// rotate the image
img = imaging.Rotate270(img)
new_image := imaging.Resize(img,400,400, imaging.Lanczos)
这就是图像的保存方式和旋转后的样子。有什么办法可以上传外部图像而无需使用解码或只修复解码问题吗? Imaging.Resize 第一个参数采用 image.Image 类型,这是我的完整代码
func myImages(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
var buff bytes.Buffer
file, handler, err := r.FormFile("file")
if err != nil {
fmt.Println("Error Uploading Image")
return
}
defer file.Close()
img,err := imaging.Decode(file)
if err != nil {
print("Imaging Open error")
}
new_image := imaging.Resize(img,400,400, imaging.Lanczos)
var buf bytes.Buffer
err = imaging.Encode(&buf,new_image, imaging.JPEG)
if err != nil {
log.Println(err)
return
}
}
不幸的是,go stdlib 图像包不处理用 exif 标签标记为旋转的图像(比如那些在设备上倒置拍摄的图像)。关于这个的错误在这里:
https://github.com/golang/go/issues/4341
你可以在 camlistore 中看到一个处理这个的例子,但是它相当复杂:
https://camlistore.googlesource.com/camlistore/+/master/pkg/images/images.go
首先你必须解码 exif 选项 (DecodeOpts),然后你必须检查它的方向(可能有 8 个),然后根据需要旋转。这很痛苦,目前还没有简单的解决方案。你可以使用这个包来读取 exif 数据:
我遇到了同样的问题并在两个库的帮助下解决了它:
go get -u github.com/disintegration/imaging
go get -u github.com/rwcarlsen/goexif/exif
使用 exif 你可以获得图像的实际方向,使用 imaging 你可以执行恢复图像所需的操作图像到方向 1。
由于替换后的图像没有留下 exif 信息,因此结果显示正确。
// ReadImage makes a copy of image (jpg,png or gif) and applies
// all necessary operation to reverse its orientation to 1
// The result is a image with corrected orientation and without
// exif data.
func ReadImage(fpath string) *image.Image {
var img image.Image
var err error
// deal with image
ifile, err := os.Open(fpath)
if err != nil {
logrus.Warnf("could not open file for image transformation: %s", fpath)
return nil
}
defer ifile.Close()
filetype, err := GetSuffix(fpath)
if err != nil {
return nil
}
if filetype == "jpg" {
img, err = jpeg.Decode(ifile)
if err != nil {
return nil
}
} else if filetype == "png" {
img, err = png.Decode(ifile)
if err != nil {
return nil
}
} else if filetype == "gif" {
img, err = gif.Decode(ifile)
if err != nil {
return nil
}
}
// deal with exif
efile, err := os.Open(fpath)
if err != nil {
logrus.Warnf("could not open file for exif decoder: %s", fpath)
}
defer efile.Close()
x, err := exif.Decode(efile)
if err != nil {
if x == nil {
// ignore - image exif data has been already stripped
}
logrus.Errorf("failed reading exif data in [%s]: %s", fpath, err.Error())
}
if x != nil {
orient, _ := x.Get(exif.Orientation)
if orient != nil {
logrus.Infof("%s had orientation %s", fpath, orient.String())
img = reverseOrientation(img, orient.String())
} else {
logrus.Warnf("%s had no orientation - implying 1", fpath)
img = reverseOrientation(img, "1")
}
imaging.Save(img, fpath)
}
return &img
}
// reverseOrientation amply`s what ever operation is necessary to transform given orientation
// to the orientation 1
func reverseOrientation(img image.Image, o string) *image.NRGBA {
switch o {
case "1":
return imaging.Clone(img)
case "2":
return imaging.FlipV(img)
case "3":
return imaging.Rotate180(img)
case "4":
return imaging.Rotate180(imaging.FlipV(img))
case "5":
return imaging.Rotate270(imaging.FlipV(img))
case "6":
return imaging.Rotate270(img)
case "7":
return imaging.Rotate90(imaging.FlipV(img))
case "8":
return imaging.Rotate90(img)
}
logrus.Errorf("unknown orientation %s, expect 1-8", o)
return imaging.Clone(img)
}
您也可以在这里找到这个实现:
https://github.com/Macilias/go-images-orientation
几周来我一直在研究图像上传功能,我即将完成它。我使用 Golang 作为后端语言,其目的是将从 IOS 设备发送的图像上传到 amazon s3 。在上传图像的过程中,我也调整了它们的大小,这主要导致了问题 decode 方法有时会旋转我不想要的图像
file, handler, err := r.FormFile("file")
if err != nil {
fmt.Println("Error Uploading Image")
return
}
defer file.Close()
// the code below sometimes rotates an image
img,err := imaging.Decode(file)
if err != nil {
print("Imaging Open error")
}
new_image := imaging.Resize(img,400,400, imaging.Lanczos)
我正在使用的库是这个 https://github.com/disintegration/imaging 这太棒了,他们展示的例子是这个
src, err := imaging.Open("testdata/lena_512.png")
if err != nil {
log.Fatalf("Open failed: %v", err)
}
src = imaging.Resize(src, 256, 0, imaging.Lanczos)
这个例子很好,但是我的图像没有存储在本地,它们来自 IOS 设备,我可以做些什么来解决这个问题吗?我的一些图片是这样保存的
有些图像是这样旋转的,这是解码方法做的
我可以通过 旋转 图像来纠正它,但是其他一些没有被 decode 旋转的图像最终被旋转旋转 270 方法 .
img,err := imaging.Decode(file)
if err != nil {
print("Imaging Open error")
}
// rotate the image
img = imaging.Rotate270(img)
new_image := imaging.Resize(img,400,400, imaging.Lanczos)
这就是图像的保存方式和旋转后的样子。有什么办法可以上传外部图像而无需使用解码或只修复解码问题吗? Imaging.Resize 第一个参数采用 image.Image 类型,这是我的完整代码
func myImages(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
var buff bytes.Buffer
file, handler, err := r.FormFile("file")
if err != nil {
fmt.Println("Error Uploading Image")
return
}
defer file.Close()
img,err := imaging.Decode(file)
if err != nil {
print("Imaging Open error")
}
new_image := imaging.Resize(img,400,400, imaging.Lanczos)
var buf bytes.Buffer
err = imaging.Encode(&buf,new_image, imaging.JPEG)
if err != nil {
log.Println(err)
return
}
}
不幸的是,go stdlib 图像包不处理用 exif 标签标记为旋转的图像(比如那些在设备上倒置拍摄的图像)。关于这个的错误在这里:
https://github.com/golang/go/issues/4341
你可以在 camlistore 中看到一个处理这个的例子,但是它相当复杂:
https://camlistore.googlesource.com/camlistore/+/master/pkg/images/images.go
首先你必须解码 exif 选项 (DecodeOpts),然后你必须检查它的方向(可能有 8 个),然后根据需要旋转。这很痛苦,目前还没有简单的解决方案。你可以使用这个包来读取 exif 数据:
我遇到了同样的问题并在两个库的帮助下解决了它:
go get -u github.com/disintegration/imaging
go get -u github.com/rwcarlsen/goexif/exif
使用 exif 你可以获得图像的实际方向,使用 imaging 你可以执行恢复图像所需的操作图像到方向 1。 由于替换后的图像没有留下 exif 信息,因此结果显示正确。
// ReadImage makes a copy of image (jpg,png or gif) and applies
// all necessary operation to reverse its orientation to 1
// The result is a image with corrected orientation and without
// exif data.
func ReadImage(fpath string) *image.Image {
var img image.Image
var err error
// deal with image
ifile, err := os.Open(fpath)
if err != nil {
logrus.Warnf("could not open file for image transformation: %s", fpath)
return nil
}
defer ifile.Close()
filetype, err := GetSuffix(fpath)
if err != nil {
return nil
}
if filetype == "jpg" {
img, err = jpeg.Decode(ifile)
if err != nil {
return nil
}
} else if filetype == "png" {
img, err = png.Decode(ifile)
if err != nil {
return nil
}
} else if filetype == "gif" {
img, err = gif.Decode(ifile)
if err != nil {
return nil
}
}
// deal with exif
efile, err := os.Open(fpath)
if err != nil {
logrus.Warnf("could not open file for exif decoder: %s", fpath)
}
defer efile.Close()
x, err := exif.Decode(efile)
if err != nil {
if x == nil {
// ignore - image exif data has been already stripped
}
logrus.Errorf("failed reading exif data in [%s]: %s", fpath, err.Error())
}
if x != nil {
orient, _ := x.Get(exif.Orientation)
if orient != nil {
logrus.Infof("%s had orientation %s", fpath, orient.String())
img = reverseOrientation(img, orient.String())
} else {
logrus.Warnf("%s had no orientation - implying 1", fpath)
img = reverseOrientation(img, "1")
}
imaging.Save(img, fpath)
}
return &img
}
// reverseOrientation amply`s what ever operation is necessary to transform given orientation
// to the orientation 1
func reverseOrientation(img image.Image, o string) *image.NRGBA {
switch o {
case "1":
return imaging.Clone(img)
case "2":
return imaging.FlipV(img)
case "3":
return imaging.Rotate180(img)
case "4":
return imaging.Rotate180(imaging.FlipV(img))
case "5":
return imaging.Rotate270(imaging.FlipV(img))
case "6":
return imaging.Rotate270(img)
case "7":
return imaging.Rotate90(imaging.FlipV(img))
case "8":
return imaging.Rotate90(img)
}
logrus.Errorf("unknown orientation %s, expect 1-8", o)
return imaging.Clone(img)
}
您也可以在这里找到这个实现: https://github.com/Macilias/go-images-orientation