Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-14559] Android: imageAsResized and imageAsThumbnail don't include EXIF data

GitHub Issuen/a
TypeBug
PriorityCritical
StatusClosed
ResolutionFixed
Resolution Date2014-05-28T16:05:53.000+0000
Affected Version/sn/a
Fix Version/s2014 Sprint 07, 2014 Sprint 07 SDK, Release 3.3.0
ComponentsAndroid
Labelsmodule_media, parity, qe-testadded
ReporterDirlei DionĂ­sio
AssigneeSunila
Created2013-06-28T23:16:16.000+0000
Updated2014-08-31T09:07:56.000+0000

Description

*Problem* The picture is always recorded in landscape, but when the device is in portrait mode the orientation flag in EXIF indicates that the picture should be rotated to portrait whenever some app wants to shown pictures in the right orientation. That applies to Titanium apps too. The thing is using either Ti.Blob.imageAsResized or imageAsThumbnail methods on Android removes the orientation flag from the resulting image. Thus any app that wants to show the new image will not be able to determine if the the image should be displayed in landscape or portrait mode and will default to landscape, causing portrait images to be seen sideways. The included code sample shows that happening on Android. The desired behaviour would be Android's implementation of Ti.Blob.imageAsResized and imageAsThumbnail keeping the orientation flag intact in the new image data. The iOS implementation of these methods works fine and it would be reasonable to have both platforms offering the same semantics for this use case. I figure out that Titanium.Blob.imageAsResized and Titanium.Blob.imageAsThumbnail generate images that don't include exif data on Android. Thus, photos captured in portrait mode and resized with one of this methods are always displayed in landscape mode when using ImageView, even when autorotate = true. I can do a workaround rotating the ImageView, but it doesn't work when we're using leftImage or rightImage of a TableViewRow. The code bellow works fine on iOS, but not on Android. *Test case*
var dir = Ti.Platform.osname === 'android' ? Ti.Filesystem.externalStorageDirectory : Ti.Filesystem.applicationDataDirectory, original = dir + 'original.jpg', resized = dir + 'resized.jpg';

var win = Titanium.UI.createWindow({
	exitOnClose : true,
	fullscreen : false
}), img1, img2;

var refreshImages = function() {
	if (img1) {
		win.remove(img1);
		img1 = null;
	}

	img1 = Ti.UI.createImageView({
		autorotate : true,
		top : 10,
		height : 150,
		width : 150,
		image : original
	});
	win.add(img1);

	if (img2) {
		win.remove(img2);
		img2 = null;
	}

	img2 = Ti.UI.createImageView({
		autorotate : true,
		top : 170,
		height : 150,
		width : 150,
		image : resized
	});
	win.add(img2);

	/*

	 This is a workaround, but I can't do this on leftImage or rightImage of a TableViewRow

	 if (Ti.Platform.osname === 'android') {
	 var t = Titanium.UI.create2DMatrix();
	 t = t.rotate(90);
	 img2.animate({transform: t});
	 }

	 */
};

refreshImages();

var b = Ti.UI.createButton({
	bottom : 10,
	left : 10,
	right : 10,
	height : 50,
	width : Ti.UI.FILL,
	title : 'camera'
});
b.addEventListener('click', function() {
	var params = {
		saveToPhotoGallery : false,
		success : function(e) {
			Ti.Filesystem.getFile(original).write(e.media);
			//img1.image = original; does not refresh image on android

			var blob = e.media.imageAsThumbnail(150, 1, 10);
			//var blob = e.media.imageAsResized(150, 150); // same problem

			Ti.Filesystem.getFile(resized).write(blob);
			//img2.image = resized; does not refresh image on android

			refreshImages();
		},
		error : function(e) {
			Ti.API.error('Camera error: ' + JSON.stringify(e));
		},
		saveToPhotoGallery : false,
		alowEditing : false,
		mediaTypes : [Ti.Media.MEDIA_TYPE_PHOTO]
	};

	if (Ti.Platform.model === 'Simulator' || Ti.Platform.model.indexOf('sdk') !== -1) {
		Ti.Media.openPhotoGallery(params);
	} else {
		Ti.Media.showCamera(params);
	};
});

win.add(b);

win.open();

Comments

  1. Eduardo Gomez 2013-07-11

    [Moved to main project]
  2. Dirlei DionĂ­sio 2013-07-15

    [Moved to description]
  3. Fokke Zandbergen 2013-12-04

    This really needs to be fixed guys. Taking photos with Android cameras is useless now.
  4. Fokke Zandbergen 2014-01-22

    This Titanium modules fixes this problem: https://github.com/freshheads/fh.imagefactory Please steal this code and get it in the SDK ;)
  5. Sunila 2014-02-07

    Read Exif data and if needed rotate image. https://github.com/appcelerator/titanium_mobile/pull/5339
  6. Lokesh Choudhary 2014-05-06

    Verified the fix by using the code in the ticket. Now, after the pic has been taken both the images appear in landscape whereas in case of a failure the second image is in landscape mode. Closing as this is fixed. Environment: Appc Studio : 3.3.0.201405011408 Ti SDK : 3.3.0.v20140502133323 Mac OSX : 10.8.5 Alloy : 1.4.0-dev CLI - 3.3.0-dev Samsung Galaxy S4 running android 4.2.2 Nexus 5 - android 4.4.2
  7. Michael Gangolf 2014-08-27

    I've tested this on Android 4.4.4 with SDK 3.3.0, sgs2
       // portrait photo (orientation 6 in exif)
       Ti.API.info(w + " " + h + " " + r);    // 3264 2448 1.3333333333333333
       Ti.API.info("1280 x " + (1280/r));  // 1280 x 960
       var blob = imageFile.imageAsResized(1280, 1280 / r);
       Ti.API.info(blob.width + " " + blob.height);  //960 1280	
       
       //crop
       blob = blob.imageAsCropped({
       	width : blob.width, height : 720, x: 0 , y : 0
       }); 
       // FAIL ==> Unable to crop the image. Illegal Argument: x + width must be <= bitmap.width()
       
    landscape photo
       // landscape photo (orientation 3 in exif)
       Ti.API.info(w + " " + h + " " + r);    // 3264 2448 1.3333333333333333
       Ti.API.info("1280 x " + (1280/r));  // 1280 x 960
       var blob = imageFile.imageAsResized(1280, 1280 / r);
       Ti.API.info(blob.width + " " + blob.height);  //1280 960	
       
       //crop
       blob = blob.imageAsCropped({
       	width : blob.width, height : 720, x: 0 , y : 0
       });  // working fine
       
    imageAsResized didn't rotate the image in the portrait mode or it didn't include the exif so imageAsCropped knows that it needs to rotate it
  8. Michael Gangolf 2014-08-31

    BTW, on a Nexus 4 exif is undefined but the image width/height is according to the rotation: portrait: w:2448, h:3264, exif: undefined landscape: w:3264, h:2448, exif: undefined

JSON Source