{ "id": "116664", "key": "TIMOB-14559", "fields": { "issuetype": { "id": "1", "description": "A problem which impairs or prevents the functions of the product.", "name": "Bug", "subtask": false }, "project": { "id": "10153", "key": "TIMOB", "name": "Titanium SDK/CLI", "projectCategory": { "id": "10100", "description": "Titanium and related SDKs used in application development", "name": "Client" } }, "fixVersions": [ { "id": "15939", "description": "2014 Sprint 07", "name": "2014 Sprint 07", "archived": true, "released": true, "releaseDate": "2014-04-11" }, { "id": "15940", "description": "2014 Sprint 07 SDK", "name": "2014 Sprint 07 SDK", "archived": true, "released": true, "releaseDate": "2014-04-11" }, { "id": "15422", "description": "Release 3.3.0", "name": "Release 3.3.0", "archived": false, "released": true, "releaseDate": "2014-07-16" } ], "resolution": { "id": "1", "description": "A fix for this issue is checked into the tree and tested.", "name": "Fixed" }, "resolutiondate": "2014-05-28T16:05:53.000+0000", "created": "2013-06-28T23:16:16.000+0000", "epic": { "id": 105183, "key": "TIMOB-11818", "name": "Android: Camera Bugs", "summary": "Android: Address deficiencies in the Camera implementation", "color": { "key": "color_1" }, "done": false }, "priority": { "name": "Critical", "id": "1" }, "labels": [ "module_media", "parity", "qe-testadded" ], "versions": [], "issuelinks": [ { "id": "30154", "type": { "id": "10003", "name": "Relates", "inward": "relates to", "outward": "relates to" }, "outwardIssue": { "id": "64059", "key": "TIMOB-3427", "fields": { "summary": "Ti API: Provide EXIF data interface", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "priority": { "name": "Low", "id": "4" }, "issuetype": { "id": "2", "description": "A new feature of the product, which has yet to be developed.", "name": "New Feature", "subtask": false } } } } ], "assignee": { "name": "sunila", "key": "sunila", "displayName": "Sunila", "active": true, "timeZone": "Asia/Kolkata" }, "updated": "2014-08-31T09:07:56.000+0000", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "components": [ { "id": "10202", "name": "Android", "description": "Android Platform" } ], "description": "*Problem*\r\nThe 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.\r\n\r\nThe 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.\r\n\r\nThe included code sample shows that happening on Android.\r\n\r\nThe 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.\r\n\r\nI 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.\r\n\r\nI can do a workaround rotating the ImageView, but it doesn't work when we're using leftImage or rightImage of a TableViewRow.\r\n\r\nThe code bellow works fine on iOS, but not on Android.\r\n\r\n*Test case*\r\n{code:javascript}\r\nvar dir = Ti.Platform.osname === 'android' ? Ti.Filesystem.externalStorageDirectory : Ti.Filesystem.applicationDataDirectory, original = dir + 'original.jpg', resized = dir + 'resized.jpg';\r\n\r\nvar win = Titanium.UI.createWindow({\r\n\texitOnClose : true,\r\n\tfullscreen : false\r\n}), img1, img2;\r\n\r\nvar refreshImages = function() {\r\n\tif (img1) {\r\n\t\twin.remove(img1);\r\n\t\timg1 = null;\r\n\t}\r\n\r\n\timg1 = Ti.UI.createImageView({\r\n\t\tautorotate : true,\r\n\t\ttop : 10,\r\n\t\theight : 150,\r\n\t\twidth : 150,\r\n\t\timage : original\r\n\t});\r\n\twin.add(img1);\r\n\r\n\tif (img2) {\r\n\t\twin.remove(img2);\r\n\t\timg2 = null;\r\n\t}\r\n\r\n\timg2 = Ti.UI.createImageView({\r\n\t\tautorotate : true,\r\n\t\ttop : 170,\r\n\t\theight : 150,\r\n\t\twidth : 150,\r\n\t\timage : resized\r\n\t});\r\n\twin.add(img2);\r\n\r\n\t/*\r\n\r\n\t This is a workaround, but I can't do this on leftImage or rightImage of a TableViewRow\r\n\r\n\t if (Ti.Platform.osname === 'android') {\r\n\t var t = Titanium.UI.create2DMatrix();\r\n\t t = t.rotate(90);\r\n\t img2.animate({transform: t});\r\n\t }\r\n\r\n\t */\r\n};\r\n\r\nrefreshImages();\r\n\r\nvar b = Ti.UI.createButton({\r\n\tbottom : 10,\r\n\tleft : 10,\r\n\tright : 10,\r\n\theight : 50,\r\n\twidth : Ti.UI.FILL,\r\n\ttitle : 'camera'\r\n});\r\nb.addEventListener('click', function() {\r\n\tvar params = {\r\n\t\tsaveToPhotoGallery : false,\r\n\t\tsuccess : function(e) {\r\n\t\t\tTi.Filesystem.getFile(original).write(e.media);\r\n\t\t\t//img1.image = original; does not refresh image on android\r\n\r\n\t\t\tvar blob = e.media.imageAsThumbnail(150, 1, 10);\r\n\t\t\t//var blob = e.media.imageAsResized(150, 150); // same problem\r\n\r\n\t\t\tTi.Filesystem.getFile(resized).write(blob);\r\n\t\t\t//img2.image = resized; does not refresh image on android\r\n\r\n\t\t\trefreshImages();\r\n\t\t},\r\n\t\terror : function(e) {\r\n\t\t\tTi.API.error('Camera error: ' + JSON.stringify(e));\r\n\t\t},\r\n\t\tsaveToPhotoGallery : false,\r\n\t\talowEditing : false,\r\n\t\tmediaTypes : [Ti.Media.MEDIA_TYPE_PHOTO]\r\n\t};\r\n\r\n\tif (Ti.Platform.model === 'Simulator' || Ti.Platform.model.indexOf('sdk') !== -1) {\r\n\t\tTi.Media.openPhotoGallery(params);\r\n\t} else {\r\n\t\tTi.Media.showCamera(params);\r\n\t};\r\n});\r\n\r\nwin.add(b);\r\n\r\nwin.open();\r\n{code} ", "attachment": [], "flagged": false, "summary": "Android: imageAsResized and imageAsThumbnail don't include EXIF data", "creator": { "name": "dirleidionisio", "key": "dirleidionisio", "displayName": "Dirlei Dionísio", "active": true, "timeZone": "America/Sao_Paulo" }, "subtasks": [], "reporter": { "name": "dirleidionisio", "key": "dirleidionisio", "displayName": "Dirlei Dionísio", "active": true, "timeZone": "America/Sao_Paulo" }, "environment": "Nexus S, Android 4.1.2, Ti SDK 3.1.1.GA, tool-api-level 17, targetSdkVersion 13", "comment": { "comments": [ { "id": "261495", "author": { "name": "egomez", "key": "egomez", "displayName": "Eduardo Gomez", "active": false, "timeZone": "America/Los_Angeles" }, "body": "[Moved to main project]", "updateAuthor": { "name": "egomez", "key": "egomez", "displayName": "Eduardo Gomez", "active": false, "timeZone": "America/Los_Angeles" }, "created": "2013-07-11T20:39:06.000+0000", "updated": "2013-07-15T21:38:59.000+0000" }, { "id": "261869", "author": { "name": "dirleidionisio", "key": "dirleidionisio", "displayName": "Dirlei Dionísio", "active": true, "timeZone": "America/Sao_Paulo" }, "body": "[Moved to description]", "updateAuthor": { "name": "egomez", "key": "egomez", "displayName": "Eduardo Gomez", "active": false, "timeZone": "America/Los_Angeles" }, "created": "2013-07-15T20:55:13.000+0000", "updated": "2013-07-15T21:37:49.000+0000" }, { "id": "282372", "author": { "name": "fokkezb", "key": "fokke", "displayName": "Fokke Zandbergen", "active": true, "timeZone": "Europe/Amsterdam" }, "body": "This really needs to be fixed guys. Taking photos with Android cameras is useless now.", "updateAuthor": { "name": "fokkezb", "key": "fokke", "displayName": "Fokke Zandbergen", "active": true, "timeZone": "Europe/Amsterdam" }, "created": "2013-12-04T13:43:21.000+0000", "updated": "2013-12-04T13:43:21.000+0000" }, { "id": "289200", "author": { "name": "fokkezb", "key": "fokke", "displayName": "Fokke Zandbergen", "active": true, "timeZone": "Europe/Amsterdam" }, "body": "This Titanium modules fixes this problem: https://github.com/freshheads/fh.imagefactory\r\n\r\nPlease steal this code and get it in the SDK ;)", "updateAuthor": { "name": "fokkezb", "key": "fokke", "displayName": "Fokke Zandbergen", "active": true, "timeZone": "Europe/Amsterdam" }, "created": "2014-01-22T10:30:41.000+0000", "updated": "2014-01-22T10:30:41.000+0000" }, { "id": "291916", "author": { "name": "sunila", "key": "sunila", "displayName": "Sunila", "active": true, "timeZone": "Asia/Kolkata" }, "body": "Read Exif data and if needed rotate image.\r\n\r\nhttps://github.com/appcelerator/titanium_mobile/pull/5339", "updateAuthor": { "name": "sunila", "key": "sunila", "displayName": "Sunila", "active": true, "timeZone": "Asia/Kolkata" }, "created": "2014-02-07T17:04:50.000+0000", "updated": "2014-02-07T17:04:50.000+0000" }, { "id": "303701", "author": { "name": "lchoudhary", "key": "lchoudhary", "displayName": "Lokesh Choudhary", "active": true, "timeZone": "America/Los_Angeles" }, "body": "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.\r\n\r\nClosing as this is fixed.\r\n\r\nEnvironment:\r\nAppc Studio : 3.3.0.201405011408\r\nTi SDK : 3.3.0.v20140502133323\r\nMac OSX : 10.8.5\r\nAlloy : 1.4.0-dev\r\nCLI - 3.3.0-dev\r\nSamsung Galaxy S4 running android 4.2.2\r\nNexus 5 - android 4.4.2", "updateAuthor": { "name": "lchoudhary", "key": "lchoudhary", "displayName": "Lokesh Choudhary", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2014-05-06T20:43:06.000+0000", "updated": "2014-05-06T20:43:06.000+0000" }, { "id": "320543", "author": { "name": "michael", "key": "michael", "displayName": "Michael Gangolf", "active": true, "timeZone": "Europe/Berlin" }, "body": "I've tested this on Android 4.4.4 with SDK 3.3.0, sgs2\r\n{code}\r\n// portrait photo (orientation 6 in exif)\r\nTi.API.info(w + \" \" + h + \" \" + r); // 3264 2448 1.3333333333333333\r\nTi.API.info(\"1280 x \" + (1280/r)); // 1280 x 960\r\nvar blob = imageFile.imageAsResized(1280, 1280 / r);\r\nTi.API.info(blob.width + \" \" + blob.height); //960 1280\t\r\n\r\n//crop\r\nblob = blob.imageAsCropped({\r\n\twidth : blob.width, height : 720, x: 0 , y : 0\r\n}); \r\n// FAIL ==> Unable to crop the image. Illegal Argument: x + width must be <= bitmap.width()\r\n{code}\r\n\r\nlandscape photo\r\n{code}\r\n// landscape photo (orientation 3 in exif)\r\nTi.API.info(w + \" \" + h + \" \" + r); // 3264 2448 1.3333333333333333\r\nTi.API.info(\"1280 x \" + (1280/r)); // 1280 x 960\r\nvar blob = imageFile.imageAsResized(1280, 1280 / r);\r\nTi.API.info(blob.width + \" \" + blob.height); //1280 960\t\r\n\r\n//crop\r\nblob = blob.imageAsCropped({\r\n\twidth : blob.width, height : 720, x: 0 , y : 0\r\n}); // working fine\r\n{code}\r\n\r\nimageAsResized 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", "updateAuthor": { "name": "michael", "key": "michael", "displayName": "Michael Gangolf", "active": true, "timeZone": "Europe/Berlin" }, "created": "2014-08-27T08:50:01.000+0000", "updated": "2014-08-27T08:50:01.000+0000" }, { "id": "321160", "author": { "name": "michael", "key": "michael", "displayName": "Michael Gangolf", "active": true, "timeZone": "Europe/Berlin" }, "body": "BTW, on a Nexus 4 exif is undefined but the image width/height is according to the rotation:\r\n\r\nportrait: \r\nw:2448, h:3264, exif: undefined\r\n\r\nlandscape: \r\nw:3264, h:2448, exif: undefined\r\n\r\n", "updateAuthor": { "name": "michael", "key": "michael", "displayName": "Michael Gangolf", "active": true, "timeZone": "Europe/Berlin" }, "created": "2014-08-31T09:07:56.000+0000", "updated": "2014-08-31T09:07:56.000+0000" } ], "maxResults": 8, "total": 8, "startAt": 0 } } }