Texture loads do not honor EXIF rotation tag and can't be fixed because of sandboxing

I am loading images from the internet, and some of them are coming in with incorrect rotations.

I have ported some .NET code to sniff the EXIF information from the files, and sure enough, the images that come in ‘wrong’ all have EXIF tags that want the rotation to be some other way.

Because the images are security sandboxed, I can’t fix them on load by moving the pixels around. I have managed to rotate them by some very ugly code using GUIUtility.RotateAroundPivot calculations, but I need to know when and how to display them rotated and without the EXIF information I went around Unity to get, I wouldn’t know how to do the rotation.

I suppose if you were using them as textures, you would mangle the UV coordinates to flip them around but that’s still an ugly thing to have to do when the simplest solution is to reorient the images on load to be right side up, and thereby match all of the assumptions built in to Unity and most everything else.

So it seems there ought to be a way to ask for images to be loaded correctly when you get them, and/or the EXIF information from the image should be made available after it’s loaded so it’s easy to figure out if it needs to be displayed in a different orientation.

It also seems that if I can get at the EXIF data, I could in fact drop in a full blown JPEG decoder here and have myself a non-sandboxed image loaded from the interwebz… but that’s a different matter :wink:

NOTE: Go here to get a mostly working EXIF reading library for .NET

http://www.codeproject.com/Articles/47486/Understanding-and-Reading-Exif-Data

Once you have this, take ExifIds.cs, ExifIO.cs, ExifReader.cs, ExifTag.cs and JpegInfo.cs from the ExifLib folder into your project. There will be an error on the public static JpegInfo ReadJpeg(FileInfo fi) function … clone the function and comment out the original, then alter the clone like so:

		public static JpegInfo ReadJpeg(byte[] fiBYTES, string Name)
		{

			DateTime then = DateTime.Now;
			using (MemoryStream fs = new MemoryStream(fiBYTES))
			{
				ExifReader reader = new ExifReader(fs);
				reader.info.FileSize = (int)fs.Length;
				reader.info.FileName = Name;
				reader.info.LoadTime = (DateTime.Now - then);
				return reader.info;
			}
		}

You can use this like so:

	IEnumerator GetImage(string url)
	{
		WWW www = new WWW(url);
		Debug.Log ("Fetching image " + url);
		yield return www;
		if (!System.String.IsNullOrEmpty(www.error))
			Debug.Log(www.error);
		else
		{
			Debug.Log("Finished Getting Image -> SIZE: " + www.bytes.Length.ToString ());
			ExifLib.JpegInfo jpi = ExifLib.ExifReader.ReadJpeg(www.bytes, "Foo");
			Debug.Log ("EXIF: " + jpi.Orientation.ToString());
		}
	}
1 Like

Nice work. The WWW class can load JPEG and PNG images. The reader built into the runtime code just reads the pixel data. EXIF isn’t part of either of these formats so it is completely ignored. (Whether that’s something that should be added to Unity is of course a different discussion.)

Maybe some methods on the WWW class to flip the orientation of the images without stepping over the line in the sandbox could be added. There are a lot of these images out there on the internet and that would give a way for devs to add a user driver rotation control at least. If they want to pull in the code above and do it automagically they would not have to jump through any UV or GUI rotation hoops.

Graham – perfect example of use case

Whenever you tinker with the camera in Android, you essentially need the exif info

Example, our P31 friends … http://support.prime31.com/11667/android-prompttotakephoto-front-camera-upside-down

Exif info would be great, you guys should do it

So does anyone know how to get the correct orientation when selecting a photo from the gallery on Android and iOS especially in trying to resolve the 90 degree rotation issue with portrait images?

Sorry to necro but…no news about that? ^^

2 Likes

running into this issue too