Golang how can I upload external images without rotating them

huangapple go评论70阅读模式
英文:

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
Golang how can I upload external images without rotating them

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
		}
    }

Golang how can I upload external images without rotating them

答案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:

https://github.com/rwcarlsen/goexif

答案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

huangapple
  • 本文由 发表于 2017年3月22日 01:53:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/42934694.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定