mirror of
https://gitee.com/shuto/cordova-plugin-camera.git
synced 2025-04-22 20:56:22 +08:00
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:
parent
d4a55f20ec
commit
f2b4eeded0
@ -26,13 +26,11 @@ import java.io.FileOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.net.URI;
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import org.apache.cordova.CallbackContext;
|
import org.apache.cordova.CallbackContext;
|
||||||
import org.apache.cordova.CordovaPlugin;
|
import org.apache.cordova.CordovaPlugin;
|
||||||
import org.apache.cordova.CordovaResourceApi;
|
|
||||||
import org.apache.cordova.LOG;
|
import org.apache.cordova.LOG;
|
||||||
import org.apache.cordova.PermissionHelper;
|
import org.apache.cordova.PermissionHelper;
|
||||||
import org.apache.cordova.PluginResult;
|
import org.apache.cordova.PluginResult;
|
||||||
@ -40,27 +38,30 @@ import org.json.JSONArray;
|
|||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
|
import android.annotation.TargetApi;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.ActivityNotFoundException;
|
import android.content.ActivityNotFoundException;
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Bitmap.CompressFormat;
|
import android.graphics.Bitmap.CompressFormat;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
import android.graphics.Matrix;
|
import android.graphics.Matrix;
|
||||||
|
import android.media.ExifInterface;
|
||||||
import android.media.MediaScannerConnection;
|
import android.media.MediaScannerConnection;
|
||||||
import android.media.MediaScannerConnection.MediaScannerConnectionClient;
|
import android.media.MediaScannerConnection.MediaScannerConnectionClient;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
|
import android.provider.DocumentsContract;
|
||||||
import android.provider.MediaStore;
|
import android.provider.MediaStore;
|
||||||
import android.util.Base64;
|
import android.util.Base64;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.PackageManager.NameNotFoundException;
|
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,
|
* 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 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 scanMe; // Uri of image to be added to content store
|
||||||
private Uri croppedUri;
|
private Uri croppedUri;
|
||||||
|
private ExifHelper exifData; // Exif data from source
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -230,8 +232,8 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
|
|||||||
* or to display URI in an img tag
|
* or to display URI in an img tag
|
||||||
* img.src=result;
|
* 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 returnType Set the type of image to return.
|
||||||
|
* @param encodingType JPEG or PNG
|
||||||
*/
|
*/
|
||||||
public void callTakePicture(int returnType, int encodingType) {
|
public void callTakePicture(int returnType, int encodingType) {
|
||||||
boolean saveAlbumPermission = PermissionHelper.hasPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE);
|
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.
|
* 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 srcType The album to get image from.
|
||||||
* @param returnType Set the type of image to return.
|
* @param returnType Set the type of image to return.
|
||||||
* @param encodingType
|
* @param encodingType
|
||||||
@ -472,7 +473,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
|
|||||||
// in the gallery and the modified image is saved in the temporary
|
// in the gallery and the modified image is saved in the temporary
|
||||||
// directory
|
// directory
|
||||||
if (this.saveToPhotoAlbum) {
|
if (this.saveToPhotoAlbum) {
|
||||||
galleryUri = Uri.fromFile(new File(getPicutresPath()));
|
galleryUri = Uri.fromFile(new File(getPicturesPath()));
|
||||||
|
|
||||||
if(this.allowEdit && this.croppedUri != null) {
|
if(this.allowEdit && this.croppedUri != null) {
|
||||||
writeUncompressedImage(this.croppedUri, galleryUri);
|
writeUncompressedImage(this.croppedUri, galleryUri);
|
||||||
@ -485,7 +486,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
|
|||||||
|
|
||||||
// If sending base64 image back
|
// If sending base64 image back
|
||||||
if (destType == DATA_URL) {
|
if (destType == DATA_URL) {
|
||||||
bitmap = getScaledBitmap(sourcePath);
|
bitmap = getScaledAndRotatedBitmap(sourcePath);
|
||||||
|
|
||||||
if (bitmap == null) {
|
if (bitmap == null) {
|
||||||
// Try to get the bitmap from intent.
|
// Try to get the bitmap from intent.
|
||||||
@ -499,9 +500,6 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rotate != 0 && this.correctOrientation) {
|
|
||||||
bitmap = getRotatedBitmap(rotate, bitmap, exif);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.processPicture(bitmap, this.encodingType);
|
this.processPicture(bitmap, this.encodingType);
|
||||||
|
|
||||||
@ -533,7 +531,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Uri uri = Uri.fromFile(createCaptureFile(this.encodingType, System.currentTimeMillis() + ""));
|
Uri uri = Uri.fromFile(createCaptureFile(this.encodingType, System.currentTimeMillis() + ""));
|
||||||
bitmap = getScaledBitmap(sourcePath);
|
bitmap = getScaledAndRotatedBitmap(sourcePath);
|
||||||
|
|
||||||
// Double-check the bitmap.
|
// Double-check the bitmap.
|
||||||
if (bitmap == null) {
|
if (bitmap == null) {
|
||||||
@ -542,9 +540,6 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rotate != 0 && this.correctOrientation) {
|
|
||||||
bitmap = getRotatedBitmap(rotate, bitmap, exif);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add compressed version of captured image to returned media store Uri
|
// Add compressed version of captured image to returned media store Uri
|
||||||
OutputStream os = this.cordova.getActivity().getContentResolver().openOutputStream(uri);
|
OutputStream os = this.cordova.getActivity().getContentResolver().openOutputStream(uri);
|
||||||
@ -575,7 +570,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
|
|||||||
bitmap = null;
|
bitmap = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getPicutresPath()
|
private String getPicturesPath()
|
||||||
{
|
{
|
||||||
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
|
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
|
||||||
String imageFileName = "IMG_" + timeStamp + (this.encodingType == JPEG ? ".jpg" : ".png");
|
String imageFileName = "IMG_" + timeStamp + (this.encodingType == JPEG ? ".jpg" : ".png");
|
||||||
@ -593,15 +588,10 @@ private void refreshGallery(Uri contentUri)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException {
|
private String outputModifiedBitmap(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");
|
|
||||||
|
|
||||||
|
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
|
||||||
|
String fileName = "IMG_" + timeStamp + (this.encodingType == JPEG ? ".jpg" : ".png");
|
||||||
String modifiedPath = getTempDirectoryPath() + "/" + fileName;
|
String modifiedPath = getTempDirectoryPath() + "/" + fileName;
|
||||||
|
|
||||||
OutputStream os = new FileOutputStream(modifiedPath);
|
OutputStream os = new FileOutputStream(modifiedPath);
|
||||||
@ -612,18 +602,14 @@ private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException {
|
|||||||
bitmap.compress(compressFormat, this.mQuality, os);
|
bitmap.compress(compressFormat, this.mQuality, os);
|
||||||
os.close();
|
os.close();
|
||||||
|
|
||||||
if (realPath != null && this.encodingType == JPEG) {
|
if (exifData != null && this.encodingType == JPEG) {
|
||||||
// Create an ExifHelper to save the exif data that is lost during compression
|
|
||||||
ExifHelper exif = new ExifHelper();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
exif.createInFile(realPath);
|
|
||||||
exif.readExifData();
|
|
||||||
if (this.correctOrientation && this.orientationCorrected) {
|
if (this.correctOrientation && this.orientationCorrected) {
|
||||||
exif.resetOrientation();
|
exifData.resetOrientation();
|
||||||
}
|
}
|
||||||
exif.createOutFile(modifiedPath);
|
exifData.createOutFile(modifiedPath);
|
||||||
exif.writeExifData();
|
exifData.writeExifData();
|
||||||
|
exifData = null;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
@ -677,7 +663,7 @@ private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException {
|
|||||||
}
|
}
|
||||||
Bitmap bitmap = null;
|
Bitmap bitmap = null;
|
||||||
try {
|
try {
|
||||||
bitmap = getScaledBitmap(uriString);
|
bitmap = getScaledAndRotatedBitmap(uriString);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
@ -687,20 +673,6 @@ private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException {
|
|||||||
return;
|
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 sending base64 image back
|
||||||
if (destType == DATA_URL) {
|
if (destType == DATA_URL) {
|
||||||
this.processPicture(bitmap, this.encodingType);
|
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) ||
|
if ( (this.targetHeight > 0 && this.targetWidth > 0) ||
|
||||||
(this.correctOrientation && this.orientationCorrected) ) {
|
(this.correctOrientation && this.orientationCorrected) ) {
|
||||||
try {
|
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
|
// 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.
|
// application cache I'm adding the current system time to the end of the file url.
|
||||||
this.callbackContext.success("file://" + modifiedPath + "?" + System.currentTimeMillis());
|
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
|
* Write an inputstream to local disk
|
||||||
* portrait mode
|
|
||||||
*
|
*
|
||||||
* @param rotate
|
* @param fis - The InputStream to write
|
||||||
* @param bitmap
|
* @param dest - Destination on disk to write to
|
||||||
* @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
|
|
||||||
* @throws FileNotFoundException
|
* @throws FileNotFoundException
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
private void writeUncompressedImage(Uri src, Uri dest) throws FileNotFoundException,
|
private void writeUncompressedImage(InputStream fis, Uri dest) throws FileNotFoundException,
|
||||||
IOException {
|
IOException {
|
||||||
FileInputStream fis = null;
|
|
||||||
OutputStream os = null;
|
OutputStream os = null;
|
||||||
try {
|
try {
|
||||||
fis = new FileInputStream(FileHelper.stripFileProtocol(src.toString()));
|
|
||||||
os = this.cordova.getActivity().getContentResolver().openOutputStream(dest);
|
os = this.cordova.getActivity().getContentResolver().openOutputStream(dest);
|
||||||
byte[] buffer = new byte[4096];
|
byte[] buffer = new byte[4096];
|
||||||
int len;
|
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
|
* 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
|
* @return
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
private Bitmap getScaledBitmap(String imageUrl) throws IOException {
|
private Bitmap getScaledAndRotatedBitmap(String imageUrl) throws IOException {
|
||||||
// If no new width or height were specified return the original bitmap
|
// If no new width or height were specified, and orientation is not needed return the original bitmap
|
||||||
if (this.targetWidth <= 0 && this.targetHeight <= 0) {
|
if (this.targetWidth <= 0 && this.targetHeight <= 0 && !(this.correctOrientation)) {
|
||||||
InputStream fileStream = null;
|
InputStream fileStream = null;
|
||||||
Bitmap image = null;
|
Bitmap image = null;
|
||||||
try {
|
try {
|
||||||
@ -960,12 +897,61 @@ private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException {
|
|||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 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 {
|
||||||
|
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 {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
LOG.e(LOG_TAG,"Exception while getting input stream: "+ e.toString());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
// figure out the original width and height of the image
|
// figure out the original width and height of the image
|
||||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||||
options.inJustDecodeBounds = true;
|
options.inJustDecodeBounds = true;
|
||||||
InputStream fileStream = null;
|
InputStream fileStream = null;
|
||||||
try {
|
try {
|
||||||
fileStream = FileHelper.getInputStreamFromUriString(imageUrl, cordova);
|
fileStream = FileHelper.getInputStreamFromUriString(galleryUri.toString(), cordova);
|
||||||
BitmapFactory.decodeStream(fileStream, null, options);
|
BitmapFactory.decodeStream(fileStream, null, options);
|
||||||
} finally {
|
} finally {
|
||||||
if (fileStream != null) {
|
if (fileStream != null) {
|
||||||
@ -977,21 +963,40 @@ private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//CB-2292: WTF? Why is the width null?
|
//CB-2292: WTF? Why is the width null?
|
||||||
if(options.outWidth == 0 || options.outHeight == 0)
|
if (options.outWidth == 0 || options.outHeight == 0) {
|
||||||
{
|
|
||||||
return null;
|
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
|
// determine the correct aspect ratio
|
||||||
int[] widthHeight = calculateAspectRatio(options.outWidth, options.outHeight);
|
int[] widthHeight = calculateAspectRatio(rotatedWidth, rotatedHeight);
|
||||||
|
|
||||||
|
|
||||||
// Load in the smallest bitmap possible that is closest to the size we want
|
// Load in the smallest bitmap possible that is closest to the size we want
|
||||||
options.inJustDecodeBounds = false;
|
options.inJustDecodeBounds = false;
|
||||||
options.inSampleSize = calculateSampleSize(options.outWidth, options.outHeight, this.targetWidth, this.targetHeight);
|
options.inSampleSize = calculateSampleSize(rotatedWidth, rotatedHeight, widthHeight[0], widthHeight[1]);
|
||||||
Bitmap unscaledBitmap = null;
|
Bitmap unscaledBitmap = null;
|
||||||
try {
|
try {
|
||||||
fileStream = FileHelper.getInputStreamFromUriString(imageUrl, cordova);
|
fileStream = FileHelper.getInputStreamFromUriString(galleryUri.toString(), cordova);
|
||||||
unscaledBitmap = BitmapFactory.decodeStream(fileStream, null, options);
|
unscaledBitmap = BitmapFactory.decodeStream(fileStream, null, options);
|
||||||
} finally {
|
} finally {
|
||||||
if (fileStream != null) {
|
if (fileStream != null) {
|
||||||
@ -1006,7 +1011,33 @@ private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Bitmap.createScaledBitmap(unscaledBitmap, widthHeight[0], widthHeight[1], true);
|
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;
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
// delete the temporary copy
|
||||||
|
if (localFile != null) {
|
||||||
|
localFile.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1027,11 +1058,11 @@ private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException {
|
|||||||
}
|
}
|
||||||
// Only the width was specified
|
// Only the width was specified
|
||||||
else if (newWidth > 0 && newHeight <= 0) {
|
else if (newWidth > 0 && newHeight <= 0) {
|
||||||
newHeight = (newWidth * origHeight) / origWidth;
|
newHeight = (int)((double)(newWidth / (double)origWidth) * origHeight);
|
||||||
}
|
}
|
||||||
// only the height was specified
|
// only the height was specified
|
||||||
else if (newWidth <= 0 && newHeight > 0) {
|
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
|
// If the user specified both a positive width and height
|
||||||
// (potentially different aspect ratio) then the width or height is
|
// (potentially different aspect ratio) then the width or height is
|
||||||
|
Loading…
x
Reference in New Issue
Block a user