CB-4078: Fix for orientation/scaling on Android 4.4+ devices

The only way to get rotation for photos in library (Gallery, File
System, Google Drive,etc) is to first create a temporary file from the
provider. Only then can we determine the orientation and scale the
bitmap correctly. By doing it in a central place, it eliminates reading
the inputstream repetitively in the plugin.
This commit is contained in:
swbradshaw 2016-04-27 22:27:37 -04:00
parent d4a55f20ec
commit f2b4eeded0

View File

@ -26,13 +26,11 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CordovaResourceApi;
import org.apache.cordova.LOG;
import org.apache.cordova.PermissionHelper;
import org.apache.cordova.PluginResult;
@ -40,27 +38,30 @@ import org.json.JSONArray;
import org.json.JSONException;
import android.Manifest;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.media.MediaScannerConnection;
import android.media.MediaScannerConnection.MediaScannerConnectionClient;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.util.Base64;
import android.util.Log;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PermissionInfo;
/**
* This class launches the camera view, allows the user to take a picture, closes the camera view,
@ -117,6 +118,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
private MediaScannerConnection conn; // Used to update gallery app with newly-written files
private Uri scanMe; // Uri of image to be added to content store
private Uri croppedUri;
private ExifHelper exifData; // Exif data from source
/**
@ -168,7 +170,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
this.encodingType = JPEG;
}
try {
try {
if (this.srcType == CAMERA) {
this.callTakePicture(destType, encodingType);
}
@ -230,8 +232,8 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
* or to display URI in an img tag
* img.src=result;
*
* @param quality Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
* @param returnType Set the type of image to return.
* @param encodingType JPEG or PNG
*/
public void callTakePicture(int returnType, int encodingType) {
boolean saveAlbumPermission = PermissionHelper.hasPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE);
@ -339,7 +341,6 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
/**
* Get image from photo library.
*
* @param quality Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
* @param srcType The album to get image from.
* @param returnType Set the type of image to return.
* @param encodingType
@ -373,17 +374,17 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
intent.addCategory(Intent.CATEGORY_OPENABLE);
}
} else if (this.mediaType == VIDEO) {
intent.setType("video/*");
title = GET_VIDEO;
intent.setAction(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("video/*");
title = GET_VIDEO;
intent.setAction(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
} else if (this.mediaType == ALLMEDIA) {
// I wanted to make the type 'image/*, video/*' but this does not work on all versions
// of android so I had to go with the wildcard search.
intent.setType("*/*");
title = GET_All;
intent.setAction(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
// I wanted to make the type 'image/*, video/*' but this does not work on all versions
// of android so I had to go with the wildcard search.
intent.setType("*/*");
title = GET_All;
intent.setAction(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
}
if (this.cordova != null) {
this.cordova.startActivityForResult((CordovaPlugin) this, Intent.createChooser(intent,
@ -391,52 +392,52 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
}
}
/**
* Brings up the UI to perform crop on passed image URI
*
* @param picUri
*/
private void performCrop(Uri picUri, int destType, Intent cameraIntent) {
try {
Intent cropIntent = new Intent("com.android.camera.action.CROP");
// indicate image type and Uri
cropIntent.setDataAndType(picUri, "image/*");
// set crop properties
cropIntent.putExtra("crop", "true");
/**
* Brings up the UI to perform crop on passed image URI
*
* @param picUri
*/
private void performCrop(Uri picUri, int destType, Intent cameraIntent) {
try {
Intent cropIntent = new Intent("com.android.camera.action.CROP");
// indicate image type and Uri
cropIntent.setDataAndType(picUri, "image/*");
// set crop properties
cropIntent.putExtra("crop", "true");
// indicate output X and Y
if (targetWidth > 0) {
cropIntent.putExtra("outputX", targetWidth);
}
if (targetHeight > 0) {
cropIntent.putExtra("outputY", targetHeight);
}
if (targetHeight > 0 && targetWidth > 0 && targetWidth == targetHeight) {
cropIntent.putExtra("aspectX", 1);
cropIntent.putExtra("aspectY", 1);
}
// create new file handle to get full resolution crop
croppedUri = Uri.fromFile(createCaptureFile(this.encodingType, System.currentTimeMillis() + ""));
cropIntent.putExtra("output", croppedUri);
// indicate output X and Y
if (targetWidth > 0) {
cropIntent.putExtra("outputX", targetWidth);
}
if (targetHeight > 0) {
cropIntent.putExtra("outputY", targetHeight);
}
if (targetHeight > 0 && targetWidth > 0 && targetWidth == targetHeight) {
cropIntent.putExtra("aspectX", 1);
cropIntent.putExtra("aspectY", 1);
}
// create new file handle to get full resolution crop
croppedUri = Uri.fromFile(createCaptureFile(this.encodingType, System.currentTimeMillis() + ""));
cropIntent.putExtra("output", croppedUri);
// start the activity - we handle returning in onActivityResult
// start the activity - we handle returning in onActivityResult
if (this.cordova != null) {
this.cordova.startActivityForResult((CordovaPlugin) this,
cropIntent, CROP_CAMERA + destType);
}
} catch (ActivityNotFoundException anfe) {
Log.e(LOG_TAG, "Crop operation not supported on this device");
try {
processResultFromCamera(destType, cameraIntent);
}
catch (IOException e)
{
e.printStackTrace();
Log.e(LOG_TAG, "Unable to write to file");
}
if (this.cordova != null) {
this.cordova.startActivityForResult((CordovaPlugin) this,
cropIntent, CROP_CAMERA + destType);
}
} catch (ActivityNotFoundException anfe) {
Log.e(LOG_TAG, "Crop operation not supported on this device");
try {
processResultFromCamera(destType, cameraIntent);
}
catch (IOException e)
{
e.printStackTrace();
Log.e(LOG_TAG, "Unable to write to file");
}
}
}
}
/**
* Applies all needed transformation to the image received from the camera.
@ -450,8 +451,8 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
// Create an ExifHelper to save the exif data that is lost during compression
ExifHelper exif = new ExifHelper();
String sourcePath = (this.allowEdit && this.croppedUri != null) ?
FileHelper.stripFileProtocol(this.croppedUri.toString()) :
FileHelper.stripFileProtocol(this.imageUri.toString());
FileHelper.stripFileProtocol(this.croppedUri.toString()) :
FileHelper.stripFileProtocol(this.imageUri.toString());
if (this.encodingType == JPEG) {
try {
@ -472,7 +473,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
// in the gallery and the modified image is saved in the temporary
// directory
if (this.saveToPhotoAlbum) {
galleryUri = Uri.fromFile(new File(getPicutresPath()));
galleryUri = Uri.fromFile(new File(getPicturesPath()));
if(this.allowEdit && this.croppedUri != null) {
writeUncompressedImage(this.croppedUri, galleryUri);
@ -485,7 +486,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
// If sending base64 image back
if (destType == DATA_URL) {
bitmap = getScaledBitmap(sourcePath);
bitmap = getScaledAndRotatedBitmap(sourcePath);
if (bitmap == null) {
// Try to get the bitmap from intent.
@ -499,9 +500,6 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
return;
}
if (rotate != 0 && this.correctOrientation) {
bitmap = getRotatedBitmap(rotate, bitmap, exif);
}
this.processPicture(bitmap, this.encodingType);
@ -533,7 +531,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
}
} else {
Uri uri = Uri.fromFile(createCaptureFile(this.encodingType, System.currentTimeMillis() + ""));
bitmap = getScaledBitmap(sourcePath);
bitmap = getScaledAndRotatedBitmap(sourcePath);
// Double-check the bitmap.
if (bitmap == null) {
@ -542,9 +540,6 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
return;
}
if (rotate != 0 && this.correctOrientation) {
bitmap = getRotatedBitmap(rotate, bitmap, exif);
}
// Add compressed version of captured image to returned media store Uri
OutputStream os = this.cordova.getActivity().getContentResolver().openOutputStream(uri);
@ -575,33 +570,28 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
bitmap = null;
}
private String getPicutresPath()
{
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "IMG_" + timeStamp + (this.encodingType == JPEG ? ".jpg" : ".png");
File storageDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);
String galleryPath = storageDir.getAbsolutePath() + "/" + imageFileName;
return galleryPath;
}
private String getPicturesPath()
{
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "IMG_" + timeStamp + (this.encodingType == JPEG ? ".jpg" : ".png");
File storageDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);
String galleryPath = storageDir.getAbsolutePath() + "/" + imageFileName;
return galleryPath;
}
private void refreshGallery(Uri contentUri)
{
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
mediaScanIntent.setData(contentUri);
this.cordova.getActivity().sendBroadcast(mediaScanIntent);
}
private void refreshGallery(Uri contentUri)
{
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
mediaScanIntent.setData(contentUri);
this.cordova.getActivity().sendBroadcast(mediaScanIntent);
}
private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException {
// Some content: URIs do not map to file paths (e.g. picasa).
String realPath = FileHelper.getRealPath(uri, this.cordova);
// Get filename from uri
String fileName = realPath != null ?
realPath.substring(realPath.lastIndexOf('/') + 1) :
"modified." + (this.encodingType == JPEG ? "jpg" : "png");
private String outputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String fileName = "IMG_" + timeStamp + (this.encodingType == JPEG ? ".jpg" : ".png");
String modifiedPath = getTempDirectoryPath() + "/" + fileName;
OutputStream os = new FileOutputStream(modifiedPath);
@ -612,18 +602,14 @@ private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException {
bitmap.compress(compressFormat, this.mQuality, os);
os.close();
if (realPath != null && this.encodingType == JPEG) {
// Create an ExifHelper to save the exif data that is lost during compression
ExifHelper exif = new ExifHelper();
if (exifData != null && this.encodingType == JPEG) {
try {
exif.createInFile(realPath);
exif.readExifData();
if (this.correctOrientation && this.orientationCorrected) {
exif.resetOrientation();
exifData.resetOrientation();
}
exif.createOutFile(modifiedPath);
exif.writeExifData();
exifData.createOutFile(modifiedPath);
exifData.writeExifData();
exifData = null;
} catch (IOException e) {
e.printStackTrace();
}
@ -633,7 +619,7 @@ private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException {
/**
/**
* Applies all needed transformation to the image received from the gallery.
*
* @param destType In which form should we return the image
@ -677,7 +663,7 @@ private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException {
}
Bitmap bitmap = null;
try {
bitmap = getScaledBitmap(uriString);
bitmap = getScaledAndRotatedBitmap(uriString);
} catch (IOException e) {
e.printStackTrace();
}
@ -687,20 +673,6 @@ private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException {
return;
}
if (this.correctOrientation) {
rotate = getImageOrientation(uri);
if (rotate != 0) {
Matrix matrix = new Matrix();
matrix.setRotate(rotate);
try {
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
this.orientationCorrected = true;
} catch (OutOfMemoryError oom) {
this.orientationCorrected = false;
}
}
}
// If sending base64 image back
if (destType == DATA_URL) {
this.processPicture(bitmap, this.encodingType);
@ -712,7 +684,7 @@ private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException {
if ( (this.targetHeight > 0 && this.targetWidth > 0) ||
(this.correctOrientation && this.orientationCorrected) ) {
try {
String modifiedPath = this.ouputModifiedBitmap(bitmap, uri);
String modifiedPath = this.outputModifiedBitmap(bitmap, uri);
// The modified image is cached by the app in order to get around this and not have to delete you
// application cache I'm adding the current system time to the end of the file url.
this.callbackContext.success("file://" + modifiedPath + "?" + System.currentTimeMillis());
@ -822,69 +794,19 @@ private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException {
}
}
private int getImageOrientation(Uri uri) {
int rotate = 0;
String[] cols = { MediaStore.Images.Media.ORIENTATION };
try {
Cursor cursor = cordova.getActivity().getContentResolver().query(uri,
cols, null, null, null);
if (cursor != null) {
cursor.moveToPosition(0);
rotate = cursor.getInt(0);
cursor.close();
}
} catch (Exception e) {
// You can get an IllegalArgumentException if ContentProvider doesn't support querying for orientation.
}
return rotate;
}
/**
* Figure out if the bitmap should be rotated. For instance if the picture was taken in
* portrait mode
* Write an inputstream to local disk
*
* @param rotate
* @param bitmap
* @return rotated bitmap
*/
private Bitmap getRotatedBitmap(int rotate, Bitmap bitmap, ExifHelper exif) {
Matrix matrix = new Matrix();
if (rotate == 180) {
matrix.setRotate(rotate);
} else {
matrix.setRotate(rotate, (float) bitmap.getWidth() / 2, (float) bitmap.getHeight() / 2);
}
try
{
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
exif.resetOrientation();
}
catch (OutOfMemoryError oom)
{
// You can run out of memory if the image is very large:
// http://simonmacdonald.blogspot.ca/2012/07/change-to-camera-code-in-phonegap-190.html
// If this happens, simply do not rotate the image and return it unmodified.
// If you do not catch the OutOfMemoryError, the Android app crashes.
}
return bitmap;
}
/**
* In the special case where the default width, height and quality are unchanged
* we just write the file out to disk saving the expensive Bitmap.compress function.
*
* @param uri
* @param fis - The InputStream to write
* @param dest - Destination on disk to write to
* @throws FileNotFoundException
* @throws IOException
*/
private void writeUncompressedImage(Uri src, Uri dest) throws FileNotFoundException,
private void writeUncompressedImage(InputStream fis, Uri dest) throws FileNotFoundException,
IOException {
FileInputStream fis = null;
OutputStream os = null;
try {
fis = new FileInputStream(FileHelper.stripFileProtocol(src.toString()));
os = this.cordova.getActivity().getContentResolver().openOutputStream(dest);
byte[] buffer = new byte[4096];
int len;
@ -909,6 +831,21 @@ private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException {
}
}
}
/**
* In the special case where the default width, height and quality are unchanged
* we just write the file out to disk saving the expensive Bitmap.compress function.
*
* @param src
* @throws FileNotFoundException
* @throws IOException
*/
private void writeUncompressedImage(Uri src, Uri dest) throws FileNotFoundException,
IOException {
FileInputStream fis = new FileInputStream(FileHelper.stripFileProtocol(src.toString()));
writeUncompressedImage(fis, dest);
}
/**
* Create entry in media store for image
@ -934,15 +871,15 @@ private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException {
}
/**
* Return a scaled bitmap based on the target width and height
* Return a scaled and rotated bitmap based on the target width and height
*
* @param imagePath
* @param imageUrl
* @return
* @throws IOException
*/
private Bitmap getScaledBitmap(String imageUrl) throws IOException {
// If no new width or height were specified return the original bitmap
if (this.targetWidth <= 0 && this.targetHeight <= 0) {
private Bitmap getScaledAndRotatedBitmap(String imageUrl) throws IOException {
// If no new width or height were specified, and orientation is not needed return the original bitmap
if (this.targetWidth <= 0 && this.targetHeight <= 0 && !(this.correctOrientation)) {
InputStream fileStream = null;
Bitmap image = null;
try {
@ -960,53 +897,147 @@ private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException {
return image;
}
// figure out the original width and height of the image
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
InputStream fileStream = null;
/* Copy the inputstream to a temporary file on the device.
We then use this temporary file to determine the width/height/orientation.
This is the only way to determine the orientation of the photo coming from 3rd party providers (Google Drive, Dropbox,etc)
This also ensures we create a scaled bitmap with the correct orientation
We delete the temporary file once we are done
*/
File localFile = null;
Uri galleryUri = null;
int rotate = 0;
try {
fileStream = FileHelper.getInputStreamFromUriString(imageUrl, cordova);
BitmapFactory.decodeStream(fileStream, null, options);
} finally {
InputStream fileStream = FileHelper.getInputStreamFromUriString(imageUrl, cordova);
if (fileStream != null) {
// Generate a temporary file
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String fileName = "IMG_" + timeStamp + (this.encodingType == JPEG ? ".jpg" : ".png");
localFile = new File(getTempDirectoryPath() + fileName);
galleryUri = Uri.fromFile(localFile);
writeUncompressedImage(fileStream, galleryUri);
try {
fileStream.close();
} catch (IOException e) {
LOG.d(LOG_TAG,"Exception while closing file input stream.");
String mimeType = FileHelper.getMimeType(imageUrl.toString(), cordova);
if ("image/jpeg".equalsIgnoreCase(mimeType)) {
// ExifInterface doesn't like the file:// prefix
String filePath = galleryUri.toString().replace("file://", "");
// read exifData of source
exifData = new ExifHelper();
exifData.createInFile(filePath);
// Use ExifInterface to pull rotation information
if (this.correctOrientation) {
ExifInterface exif = new ExifInterface(filePath);
rotate = exifToDegrees(exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED));
}
}
} catch (Exception oe) {
LOG.w(LOG_TAG,"Unable to read Exif data: "+ oe.toString());
rotate = 0;
}
}
}
//CB-2292: WTF? Why is the width null?
if(options.outWidth == 0 || options.outHeight == 0)
catch (Exception e)
{
LOG.e(LOG_TAG,"Exception while getting input stream: "+ e.toString());
return null;
}
// determine the correct aspect ratio
int[] widthHeight = calculateAspectRatio(options.outWidth, options.outHeight);
// Load in the smallest bitmap possible that is closest to the size we want
options.inJustDecodeBounds = false;
options.inSampleSize = calculateSampleSize(options.outWidth, options.outHeight, this.targetWidth, this.targetHeight);
Bitmap unscaledBitmap = null;
try {
fileStream = FileHelper.getInputStreamFromUriString(imageUrl, cordova);
unscaledBitmap = BitmapFactory.decodeStream(fileStream, null, options);
} finally {
if (fileStream != null) {
try {
fileStream.close();
} catch (IOException e) {
LOG.d(LOG_TAG,"Exception while closing file input stream.");
// figure out the original width and height of the image
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
InputStream fileStream = null;
try {
fileStream = FileHelper.getInputStreamFromUriString(galleryUri.toString(), cordova);
BitmapFactory.decodeStream(fileStream, null, options);
} finally {
if (fileStream != null) {
try {
fileStream.close();
} catch (IOException e) {
LOG.d(LOG_TAG, "Exception while closing file input stream.");
}
}
}
//CB-2292: WTF? Why is the width null?
if (options.outWidth == 0 || options.outHeight == 0) {
return null;
}
// User didn't specify output dimensions, but they need orientation
if (this.targetWidth <= 0 && this.targetHeight <= 0) {
this.targetWidth = options.outWidth;
this.targetHeight = options.outHeight;
}
// Setup target width/height based on orientation
int rotatedWidth, rotatedHeight;
boolean rotated= false;
if (rotate == 90 || rotate == 270) {
rotatedWidth = options.outHeight;
rotatedHeight = options.outWidth;
rotated = true;
} else {
rotatedWidth = options.outWidth;
rotatedHeight = options.outHeight;
}
// determine the correct aspect ratio
int[] widthHeight = calculateAspectRatio(rotatedWidth, rotatedHeight);
// Load in the smallest bitmap possible that is closest to the size we want
options.inJustDecodeBounds = false;
options.inSampleSize = calculateSampleSize(rotatedWidth, rotatedHeight, widthHeight[0], widthHeight[1]);
Bitmap unscaledBitmap = null;
try {
fileStream = FileHelper.getInputStreamFromUriString(galleryUri.toString(), cordova);
unscaledBitmap = BitmapFactory.decodeStream(fileStream, null, options);
} finally {
if (fileStream != null) {
try {
fileStream.close();
} catch (IOException e) {
LOG.d(LOG_TAG, "Exception while closing file input stream.");
}
}
}
if (unscaledBitmap == null) {
return null;
}
int scaledWidth = (!rotated) ? widthHeight[0] : widthHeight[1];
int scaledHeight = (!rotated) ? widthHeight[1] : widthHeight[0];
Bitmap scaledBitmap = Bitmap.createScaledBitmap(unscaledBitmap, scaledWidth, scaledHeight, true);
if (scaledBitmap != unscaledBitmap) {
unscaledBitmap.recycle();
unscaledBitmap = null;
}
if (this.correctOrientation && (rotate != 0)) {
Matrix matrix = new Matrix();
matrix.setRotate(rotate);
try {
scaledBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0, scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix, true);
this.orientationCorrected = true;
} catch (OutOfMemoryError oom) {
this.orientationCorrected = false;
}
}
return scaledBitmap;
}
if (unscaledBitmap == null) {
return null;
finally {
// delete the temporary copy
if (localFile != null) {
localFile.delete();
}
}
return Bitmap.createScaledBitmap(unscaledBitmap, widthHeight[0], widthHeight[1], true);
}
/**
@ -1027,11 +1058,11 @@ private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException {
}
// Only the width was specified
else if (newWidth > 0 && newHeight <= 0) {
newHeight = (newWidth * origHeight) / origWidth;
newHeight = (int)((double)(newWidth / (double)origWidth) * origHeight);
}
// only the height was specified
else if (newWidth <= 0 && newHeight > 0) {
newWidth = (newHeight * origWidth) / origHeight;
newWidth = (int)((double)(newHeight / (double)origHeight) * origWidth);
}
// If the user specified both a positive width and height
// (potentially different aspect ratio) then the width or height is
@ -1075,7 +1106,7 @@ private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException {
} else {
return srcHeight / dstHeight;
}
}
}
/**
* Creates a cursor that can be used to determine how many images we have.
@ -1288,4 +1319,4 @@ private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException {
this.callbackContext = callbackContext;
}
}
}