Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

image/jpeg: correct for EXIF orientation? #4341

Open
bradfitz opened this issue Nov 4, 2012 · 29 comments
Open

image/jpeg: correct for EXIF orientation? #4341

bradfitz opened this issue Nov 4, 2012 · 29 comments
Labels
Milestone

Comments

@bradfitz
Copy link
Contributor

bradfitz commented Nov 4, 2012

JPEG files can embed EXIF metadata specifying one of 8 mirroring+rotation options.  Only
2-3 of these are in common use, from people holding their phones sideways when taking
pictures.

It would be nice of the image/jpeg package could, perhaps optionally, correct for these.

Camlistore will be doing it on its own, but it seems like something the image/jpeg
package is in a good position to do automatically.

It's probably only safe to do the left-90 and right-90 ones automatically (and only when
width & height change), so users can detect whether the operation has already been
done and not apply the transformation again, as orientation-fixing code has to do anyway
(because you can't trust whether upstream software in the wild fixed the metadata for
you when it flipped-and-resaved the image, so you also have to check the before &
after dimensions).

If we want to do this in image/jpeg, I've attached a screenshot of the 8 modes and a
tarball of 16 JPEG files: 1 for each mode without EXIF, and 1 for each mode with the
Orientation field set to "fix" the image back to a lowercase eff letter.  The
f files are written on 8x8 pixel boundaries, so we can do pixel-wise compares in tests
safely.

Attachments:

  1. exif-orientations.png (22969 bytes)
  2. f.tar (30720 bytes)
@gopherbot
Copy link

Comment 1 by jsummers3456:

Did you intentionally put JFIF segments in your sample files? According to the JFIF
specification, JFIF files always use top-left orientation. So, the orientation of your
images seems to be ambiguous. I don't know whether there's a standard way to resolve it.

@bradfitz
Copy link
Contributor Author

bradfitz commented Nov 8, 2012

Comment 2:

JFIF segments weren't intentional.  I made the original image in Gimp and made each flip
and mirror by hand (also in Gimp), saved them all, and then used the "exif" tool in
Debian to create the EXIF header and force the Orientation fields.
Both Nautilus and OS X render all the images in the same way, fwiw.

@rsc
Copy link
Contributor

rsc commented Dec 30, 2012

Comment 3:

Labels changed: added priority-later, removed priority-triage.

Status changed to Thinking.

@nigeltao
Copy link
Contributor

Comment 4:

There is a larger concern of decoding all of a JPEG's EXIF metadata. The right API might
be for image/jpeg to provide EXIF data, and image/draw to provide 90-degree rotations.
This is analagous to jpeg decoding to an image.YCbCr; if you want an image.RGBA then it
is the caller's responsibility to explicitly perform the conversion (via image/draw). On
the other hand, single-pass decode-and-rotate can be more efficient.
I'm wary of adding new API so close to an API freeze. I'm marking this bug as out of
scope for the Go 1.1 timeframe.

Labels changed: removed go1.1maybe.

@mewmew
Copy link
Contributor

mewmew commented Feb 20, 2013

Comment 5:

EXIF orientation is notably hard and it has been incorrectly implemented a number of
times. [1]
Just pointing it out so that it can be implemented correctly for Go, once and for all.
[1]: http://recursive-design.com/blog/2012/07/28/exif-orientation-handling-is-a-ghetto/

@rsc
Copy link
Contributor

rsc commented Jul 30, 2013

Comment 6:

Labels changed: added go1.2maybe.

@rsc
Copy link
Contributor

rsc commented Jul 30, 2013

Comment 7:

Labels changed: added feature.

@robpike
Copy link
Contributor

robpike commented Aug 19, 2013

Comment 8:

Not happening for 1.2.

Labels changed: added go1.3maybe, removed go1.2maybe.

@robpike
Copy link
Contributor

robpike commented Aug 20, 2013

Comment 9:

Labels changed: removed go1.3maybe.

@rsc
Copy link
Contributor

rsc commented Nov 27, 2013

Comment 10:

Labels changed: added go1.3maybe.

@rsc
Copy link
Contributor

rsc commented Nov 27, 2013

Comment 11:

Labels changed: removed feature.

@rsc
Copy link
Contributor

rsc commented Dec 4, 2013

Comment 12:

Labels changed: added release-none, removed go1.3maybe.

@rsc
Copy link
Contributor

rsc commented Dec 4, 2013

Comment 13:

Labels changed: added repo-main.

@gopherbot
Copy link

Comment 14 by artem@volkhin.com:

Any update on this?

@nigeltao
Copy link
Contributor

Comment 15:

No news to report.

@Macilias
Copy link

Macilias commented Apr 9, 2018

Hi, had the same problem, fixed it by providing a function which replaces the original image with a copy of referenced image (jpg, png or gif). The replaced copy has all necessary operation, which are needed to reverse its orientation to 1, applied. The result is a image with corrected orientation and without exif data.
You can find it here:
https://github.com/Macilias/go-images-orientation

@edwvee
Copy link

edwvee commented May 31, 2018

That's sad that there is nothing has been solved yet. Even no mentioning of that in official guides and etc.

@edwvee
Copy link

edwvee commented Jun 2, 2018

Wrote image.Decode replacement handling EXIF orientation: https://github.com/edwvee/exiffix

@TACIXAT
Copy link

TACIXAT commented Jul 21, 2022

Sorry, I know this isn't the spot for it, but if anyone needs a workaround -

package main

import (
	"github.com/disintegration/imaging"
	"github.com/rwcarlsen/goexif/exif"
	"github.com/rwcarlsen/goexif/tiff"
	imagego "image"
	_ "image/jpeg"
	"log"
	"os"
)

func main() {
	f, err := os.Open("test.jpg")
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()

	x, err := exif.Decode(f)
	if err != nil {
		// EOF no exif
		log.Fatal(err)
	}

	tag, err := x.Get(exif.Orientation)
	if err != nil {
		// tag not present
		log.Fatal(err)
	}

	// reset for image decode
	off, err := f.Seek(0, 0)
	if err != nil {
		log.Fatal(err)
	}

	if off != 0 {
		log.Fatal("Not at beginning of file.")
	}

	img, _, err := imagego.Decode(f)
	if err != nil {
		log.Fatal(err)
	}

	if tag.Count == 1 && tag.Format() == tiff.IntVal {
		orientation, err := tag.Int(0)
		if err != nil {
			log.Fatal(err)
		}

		log.Println(orientation)

		switch orientation {
		case 3: // rotate 180
			img = imaging.Rotate180(img)
		case 6: // rotate 270
			img = imaging.Rotate270(img)
		case 8: //rotate 90
			img = imaging.Rotate90(img)
		}
	}
}

@dzpt
Copy link

dzpt commented Sep 18, 2022

After 10 years and the issue is still there

@earthboundkid
Copy link
Contributor

We could have a little party Nov 4, 2022. 😆 Seriously, I saw some photos on my kids school website with the orientation wrong last week and thought "oh, they must have that EXIF bug." I would be surprised if that website was Go powered though. Seems like a common enough bug that it should really be snipped out.

@amoss
Copy link

amoss commented Oct 31, 2022

Four days away from the big anniversary! 🎉🎊🥳 Arrived here fixing this bug for a photo upload / thumbnail service. Good to see that it has a long pedigree. While there was some initial reluctance to fix this because the exif decode complicates the interface, would it not be possible to handle rotation as a loss-less operation within the current interface?

@earthboundkid
Copy link
Contributor

Yeah, I think someone just needs to find a weekend to sit down a write a good patch.

@endlesstravel
Copy link

endlesstravel commented Dec 15, 2022

I just ran into this "bug", and found this issue.
Hasn't been fixed yet, surprised 😭

@ncruces
Copy link
Contributor

ncruces commented Jun 6, 2023

The thing is how do you define the API with no compatibility breakages.
Do you just assume you're always supposed to rotate, period?

@earthboundkid
Copy link
Contributor

Yes, I think ignoring the EXIF rotation was always a bug, and no one ever wanted it.

@ncruces
Copy link
Contributor

ncruces commented Jun 6, 2023

But then everyone who is handling this after the fact (rotating the output after the decode) will be broken by the fix.

@meblum
Copy link

meblum commented Dec 11, 2023

@TACIXAT since you are using imaging, how about simply calling imaging.Decode(f, imaging.AutoOrientation(true))?

kensanata added a commit to kensanata/oddmu that referenced this issue Feb 20, 2024
If you upload an unedited image from an iPhone, the EXIF data
indicates how it should be oriented. Oddmu used to resize images strip
the EXIF data, resulting in resized images that were not oriented
correctly. If the EXIF data is stripped, the image has to be rotated.
In order to do this, the exiffix single-function library is used to
work around "image/jpeg: correct for EXIF orientation? #4341", opened
in 2012. See golang/go#4341 for more
information and a link to https://github.com/edwvee/exiffix.
@wjkoh
Copy link

wjkoh commented Mar 27, 2024

I have come across another solution from @disintegration, which was written 7 years ago and can be found at https://github.com/disintegration/imageorient. It is unfortunate that many of the Go libraries related to image processing appear to be inactive. It would be beneficial to incorporate this type of solution into the standard library and ensure its maintenance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests