I would track this jira bug for monitoring progress on the issue, although it's been open since 2011 so don't hold your breath!
If you don't want to wait years for a fix, you'll have to create a custom Android module for Titanium in order to get this working correctly. Here is what the module contents should look like:
/**
* This file was auto-generated by the Titanium Module SDK helper for Android
* Appcelerator Titanium Mobile
* Copyright (c) 2009-2010 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the Apache Public License
* Please see the LICENSE included with this distribution for details.
*
* the solution for ImageFactoryModule was coming from this ticket
* https://jira.appcelerator.org/browse/TIMOB-3427
* https://github.com/freshheads/fh.imagefactory
*/
package com.company.utils;
import java.util.HashMap;
import java.util.Map;
import org.appcelerator.kroll.KrollDict;
import org.appcelerator.kroll.KrollModule;
import org.appcelerator.kroll.annotations.Kroll;
import org.appcelerator.titanium.TiApplication;
import org.appcelerator.kroll.common.Log;
import org.appcelerator.kroll.common.TiConfig;
import org.appcelerator.kroll.common.Log;
import org.appcelerator.titanium.util.TiConvert;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;
@Kroll.module(name="Utils", id="com.company.utils")
public class UtilsModule extends KrollModule
{
// Standard Debugging variables
private static final String TAG = "com.company.utils";
@Kroll.constant public static final String TAG_ORIENTATION = ExifInterface.TAG_ORIENTATION;
@Kroll.constant public static final int ORIENTATION_ROTATE_180 = ExifInterface.ORIENTATION_ROTATE_180;
@Kroll.constant public static final int ORIENTATION_ROTATE_270 = ExifInterface.ORIENTATION_ROTATE_270;
@Kroll.constant public static final int ORIENTATION_ROTATE_90 = ExifInterface.ORIENTATION_ROTATE_90;
public UtilsModule() {
super();
}
@Kroll.onAppCreate
public static void onAppCreate(TiApplication app) {
}
// Methods
/**
* Auto rotate and resize to the desired maximum size keeping aspect
*
* @param filename
* @param size
* @param quality
* @return
*/
@Kroll.method
public Boolean rotateResizeImage(String filename, int size, int quality)
{
Log.i(TAG, "In rotateResizeImage");
File imageFile = null;
FileInputStream fileInputStream = null;
FileInputStream fileInputStream2 = null;
FileOutputStream fileOutputStream = null;
Bitmap scaledBitmap = null;
Bitmap resizedBitmap = null;
try
{
// Determine the orientation
int rotation = getRotation(filename);
// Read the file path into a File
imageFile = new File(convertPath(filename));
// Decode once to determine size
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inJustDecodeBounds = true;
fileInputStream = new FileInputStream(imageFile);
BitmapFactory.decodeStream(fileInputStream, null, opts);
Log.i(TAG, "Original image size: " + opts.outWidth + "x" + opts.outHeight);
// Determine scaling based on size
int sample = 1;
while (opts.outWidth / sample / 2 >= size || opts.outHeight / sample / 2 >= size) {
sample *= 2;
}
opts = new BitmapFactory.Options();
opts.inSampleSize = sample;
Log.i(TAG, "Sample size: " + sample);
// Decode with scaling applied to save a huge amount of memory
fileInputStream2 = new FileInputStream(imageFile);
scaledBitmap = BitmapFactory.decodeStream(fileInputStream2, null, opts);
Log.i(TAG, "Sampled image size: " + opts.outWidth + "x" + opts.outHeight);
// Create the appropriate Matrix to resize and rotate then create Bitmap
float scale = (float)size / (float)(opts.outWidth > opts.outHeight ? opts.outWidth : opts.outHeight);
Matrix matrix = new Matrix();
matrix.postRotate(rotation);
matrix.postScale(scale, scale);
resizedBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0, (int)scaledBitmap.getWidth(), (int)scaledBitmap.getHeight(), matrix, true);
Log.i(TAG, "Scaled image size: " + resizedBitmap.getWidth() + "x" + resizedBitmap.getHeight());
// Delete old file
imageFile.delete();
Log.i(TAG, "Deleted old file");
// Create new file
imageFile.createNewFile();
Log.i(TAG, "Created new file");
// Copy rotated, resized image to new file
fileOutputStream = new FileOutputStream(imageFile);
resizedBitmap.compress(Bitmap.CompressFormat.JPEG, quality, fileOutputStream);
fileOutputStream.flush();
Log.i(TAG, "Copied rotated, resized image to new file");
return true;
}
catch (Exception e)
{
Log.e(TAG, "ERROR: " + e.toString());
return false;
}
finally {
if(imageFile != null) {
imageFile = null;
}
if(fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {
}
fileInputStream = null;
}
if(fileInputStream2 != null) {
try {
fileInputStream2.close();
} catch (IOException e) {
}
fileInputStream2 = null;
}
if(fileOutputStream != null) {
try {
fileOutputStream.close();
} catch (IOException e) {
}
fileOutputStream = null;
}
if(scaledBitmap != null) {
scaledBitmap.recycle();
scaledBitmap = null;
}
if(resizedBitmap != null) {
resizedBitmap.recycle();
resizedBitmap = null;
}
}
}
private Integer getRotation(String filename) {
int orientation = TiConvert.toInt(getExifTag(filename, TAG_ORIENTATION));
Log.i(TAG, "Detected orientation: " + orientation);
int rotation = 0;
switch (orientation)
{
case ORIENTATION_ROTATE_90:
rotation = 90;
break;
case ORIENTATION_ROTATE_180:
rotation = 180;
break;
case ORIENTATION_ROTATE_270:
rotation = 270;
break;
}
Log.i(TAG, "Determined rotation: " + rotation);
return rotation;
}
private String getExifTag(String filename, String tag)
{
String property = "";
ExifInterface exif;
filename = convertPath(filename);
try {
//Log.i(TAG, "Read Exif tag: " + tag + ", from file: " + filename);
exif = new ExifInterface(filename);
property = exif.getAttribute(tag);
//Log.i(TAG, "Exif tag value: " + property);
}
catch (IOException e)
{
property = "";
Log.e(TAG, "IO Exception occured, file probably does not exist.");
}
return property;
}
private String convertPath(String path)
{
//Log.i(TAG, "Open FileInputStream for path: " + path);
if (path.startsWith("file://") || path.startsWith("content://") || path.startsWith("appdata://") || path.startsWith("appdata-private://"))
{
path = path.replaceAll("file://", "");
path = path.replaceAll("content://", "");
path = path.replaceAll("appdata:///?", "/mnt/sdcard/" + TiApplication.getInstance().getPackageName() + "/");
path = path.replaceAll("appdata-private:///?", "/data/data/" + TiApplication.getInstance().getPackageName() + "/app_appdata/");
//Log.i(TAG, "Converted path to: " + path);
}
return path;
}
}
And below is how you will consume it in your Titanium app, just pass in e.media after taking the picture:
function rotateAndResize (media, width, quality) {
var utilsModule = require('com.company.utils');
// Create file to store photo.
var dataDirectory = Ti.Filesystem.getApplicationDataDirectory();
var fileName = String.format('Company_Photo_%s.jpg', moment().format('YYYY-MM-DD-HH-mm-ss-SSS-ZZ'));
var file = Ti.Filesystem.getFile(dataDirectory, fileName);
var fileNativePath = file.nativePath;
// Write media to file.
file.write(media);
file = null;
// Rotate photo in file, resize, and adjust quality.
utilsModule.rotateResizeImage(fileNativePath, width || 640, quality || 80);
// Get new and improved media out of file.
media = Ti.Filesystem.getFile(fileNativePath);
return media;
}