英文:
Golang how can I upload external images without rotating them
问题
我已经几周来一直在开发一个图片上传功能,现在差不多完成了。我使用Golang作为后端语言,它的目的是将从iOS设备发送的图片上传到Amazon S3。在上传图片的过程中,我还会对其进行调整大小,但这导致了一些问题,主要是decode方法有时会旋转图片,而我并不希望这样。
我使用的库是这个: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方法引起的。
我可以通过旋转图片来纠正它,但是其他一些没有被decode旋转的图片最终会被Rotate270方法旋转。
这是我旋转后保存的图片。有没有办法在不使用decode的情况下上传外部图片,或者修复decode的问题?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
}
}
英文:
I have been working on an image upload functionality for a few weeks and I just about have it done. I am using Golang as a backend language and it's purpose is to upload images sent from IOS devices to amazon s3 . In the process of uploading the image I also resize them and this has caused problems primarily the decode method sometimes rotates images which I do not want
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)
The library I am using is this one https://github.com/disintegration/imaging which is fantastic and the example they showed was this
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)
That example is fine however my images are not stored locally they are coming from IOS devices is there something that I can do to fix this problem ? Some of my images are being saved like this
Some images are rotated like this and it is the Decode method doing it
I can correct it by rotating the image however some other images that do not get rotated by decode end up being rotated by the Rotate270 method .
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)
This is how the image is saved and looks after I rotate it . Is there someway I can upload external images without having to use decode or just fixing the decode issue ? Imaging.Resize first parameter takes in type image.Image and here is my full code
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
}
}
答案1
得分: 8
很抱歉,go标准库的图像包不处理被exif标签标记为旋转的图像(比如那些倒置拍摄的图像)。关于这个问题的bug报告在这里:
https://github.com/golang/go/issues/4341
你可以在camlistore中看到处理这个问题的示例,但是它相当复杂:
https://camlistore.googlesource.com/camlistore/+/master/pkg/images/images.go
首先,你需要解码exif选项(DecodeOpts),然后检查它的方向(8个可能的方向之一),然后根据需要进行旋转。这是一个痛苦的过程,目前还没有简单的解决方案。不过,你可以使用这个包来读取exif数据:
https://github.com/rwcarlsen/goexif
英文:
Unfortunately the go stdlib image package does not handle images which are marked as rotated with exif tags (like those here taken on a device upside down). The bug about this is here:
https://github.com/golang/go/issues/4341
You can see an example of handling this in camlistore, but it is quite involved:
https://camlistore.googlesource.com/camlistore/+/master/pkg/images/images.go
First you have to decode exif options (DecodeOpts), then you have to check which orientation it has (out of 8 possible), then rotate as necessary. It's painful and there is no easy solution as yet. You can use this package to read exif data though:
答案2
得分: 1
我遇到了同样的问题,并通过两个库解决了它:
go get -u github.com/disintegration/imaging
go get -u github.com/rwcarlsen/goexif/exif
使用 exif 库,你可以获取图像的实际方向,使用 imaging 库,你可以执行将图像恢复到方向1所需的操作。由于替换后的图像没有剩余的exif信息,结果将显示正确。
// ReadImage复制图像(jpg、png或gif)并应用所有必要的操作以将其方向恢复为1
// 结果是一个具有修正方向且没有exif数据的图像。
func ReadImage(fpath string) *image.Image {
var img image.Image
var err error
// 处理图像
ifile, err := os.Open(fpath)
if err != nil {
logrus.Warnf("无法打开图像转换文件:%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
}
}
// 处理exif
efile, err := os.Open(fpath)
if err != nil {
logrus.Warnf("无法打开exif解码文件:%s", fpath)
}
defer efile.Close()
x, err := exif.Decode(efile)
if err != nil {
if x == nil {
// 忽略 - 图像exif数据已被删除
}
logrus.Errorf("在[%s]中读取exif数据失败:%s", fpath, err.Error())
}
if x != nil {
orient, _ := x.Get(exif.Orientation)
if orient != nil {
logrus.Infof("%s的方向为%s", fpath, orient.String())
img = reverseOrientation(img, orient.String())
} else {
logrus.Warnf("%s没有方向 - 暗示为1", fpath)
img = reverseOrientation(img, "1")
}
imaging.Save(img, fpath)
}
return &img
}
// reverseOrientation执行任何必要的操作,将给定的方向转换为方向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("未知的方向%s,期望为1-8", o)
return imaging.Clone(img)
}
你也可以在这里找到这个实现:
https://github.com/Macilias/go-images-orientation
英文:
I had the same problem and solved it with a help of two libraries:
go get -u github.com/disintegration/imaging
go get -u github.com/rwcarlsen/goexif/exif
with exif you can obtain the actual orientation of the image and with imaging you can perform the operations which are needed to revert the image to orientation 1.
Since a replaced image has no exif information left, the result is then shown correctly.
// 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)
}
You can find this implementation also here:
https://github.com/Macilias/go-images-orientation
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论