Golang how can i load external images without rotating them

I've been working on the image upload feature for a couple of weeks now and I just did it. I am using Golang as my base language and it is for loading images sent from IOS devices to amazon s3. In the process of loading the images I also resize them and this caused problems, first of all the decoding method sometimes rotates the images which I don't 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 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)

      

This example is good, however my images are not stored locally, they are coming from IOS devices, is there something I can do to fix this issue? Some of my images are saved this way

Some images rotate in the same way as Decode method does Some images are rotated and saved like this

I can correct it by rotating the image, but some other images that cannot be rotated decode are rotated using 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 way the image is saved and after that I rotate it. Can I load external images without using decoding or just fixing the decoding problem? Imaging.Resize first parameter takes image.Image type and here is my complete 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
        }
    }

      

enter image description here

+3


source to share


2 answers


Unfortunately, the stdlib image package does not handle images that are marked as rotated using exif tags (such as those taken upside down on the device). The error is here:

https://github.com/golang/go/issues/4341

You can see an example of handling this in camlistore, but it's pretty important:



https://camlistore.googlesource.com/camlistore/+/master/pkg/images/images.go

First you need to decode the exif options (DecodeOpts), then you have to check which one has an orientation (out of 8 possible) and then rotate as needed. This is painful and there is no easy solution yet. You can use this package to read exif data, though:

https://github.com/rwcarlsen/goexif

+6


source


I had the same problem and solved it with two libraries:

go get -u github.com/disintegration/imaging
go get -u github.com/rwcarlsen/goexif/exif

      

with exif, you can get the actual orientation of the image and the image , you can perform the operations required to return the image to orientation 1. Since the changed image has no exif information left, the result will be 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 also find this implementation: https://github.com/Macilias/go-images-orientation

-1


source







All Articles