diff --git a/framework/src/org/apache/cordova/CameraLauncher.java b/framework/src/org/apache/cordova/CameraLauncher.java index 1afaf8db..3520247b 100755 --- a/framework/src/org/apache/cordova/CameraLauncher.java +++ b/framework/src/org/apache/cordova/CameraLauncher.java @@ -20,6 +20,7 @@ package org.apache.cordova; import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; @@ -43,6 +44,7 @@ import android.graphics.Matrix; import android.graphics.Bitmap.CompressFormat; import android.net.Uri; import android.provider.MediaStore; +import android.util.Log; /** * This class launches the camera view, allows the user to take a picture, closes the camera view, @@ -277,6 +279,7 @@ public class CameraLauncher extends Plugin { Bitmap retval = Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true); bitmap.recycle(); + System.gc(); return retval; } @@ -310,20 +313,12 @@ public class CameraLauncher extends Plugin { // If image available if (resultCode == Activity.RESULT_OK) { try { - // Read in bitmap of captured image - Bitmap bitmap; - try { - bitmap = android.provider.MediaStore.Images.Media.getBitmap(this.cordova.getActivity().getContentResolver(), imageUri); - } catch (FileNotFoundException e) { - Uri uri = intent.getData(); - android.content.ContentResolver resolver = this.cordova.getActivity().getContentResolver(); - bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri)); - } - - bitmap = scaleBitmap(bitmap); + Bitmap bitmap = null; // If sending base64 image back if (destType == DATA_URL) { + bitmap = scaleBitmap(getBitmapFromResult(intent)); + this.processPicture(bitmap); checkForDuplicateImage(DATA_URL); } @@ -348,6 +343,27 @@ public class CameraLauncher extends Plugin { } } + // If all this is true we shouldn't compress the image. + if (this.targetHeight == -1 && this.targetWidth == -1 && this.mQuality == 100) { + FileInputStream fis = new FileInputStream(FileUtils.stripFileProtocol(imageUri.toString())); + OutputStream os = this.cordova.getActivity().getContentResolver().openOutputStream(uri); + byte[] buffer = new byte[4096]; + int len; + while ((len = fis.read(buffer)) != -1) { + os.write(buffer, 0, len); + } + os.flush(); + os.close(); + fis.close(); + + checkForDuplicateImage(FILE_URI); + + this.success(new PluginResult(PluginResult.Status.OK, uri.toString()), this.callbackId); + return; + } + + bitmap = scaleBitmap(getBitmapFromResult(intent)); + // Add compressed version of captured image to returned media store Uri OutputStream os = this.cordova.getActivity().getContentResolver().openOutputStream(uri); bitmap.compress(Bitmap.CompressFormat.JPEG, this.mQuality, os); @@ -390,7 +406,7 @@ public class CameraLauncher extends Plugin { Uri uri = intent.getData(); android.content.ContentResolver resolver = this.cordova.getActivity().getContentResolver(); - // If you ask for video or all media type you will automatically get back a file URI + // If you ask for video or all media type you will automatically get back a file URI // and there will be no attempt to resize any returned data if (this.mediaType != PICTURE) { this.success(new PluginResult(PluginResult.Status.OK, uri.toString()), this.callbackId); @@ -447,7 +463,7 @@ public class CameraLauncher extends Plugin { bitmap.recycle(); bitmap = null; - // The resized image is cached by the app in order to get around this and not have to delete you + // The resized 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.success(new PluginResult(PluginResult.Status.OK, ("file://" + fileName + "?" + System.currentTimeMillis())), this.callbackId); System.gc(); @@ -471,6 +487,19 @@ public class CameraLauncher extends Plugin { } } + private Bitmap getBitmapFromResult(Intent intent) + throws IOException, FileNotFoundException { + Bitmap bitmap = null; + try { + bitmap = android.provider.MediaStore.Images.Media.getBitmap(this.ctx.getActivity().getContentResolver(), imageUri); + } catch (FileNotFoundException e) { + Uri uri = intent.getData(); + android.content.ContentResolver resolver = this.ctx.getActivity().getContentResolver(); + bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri)); + } + return bitmap; + } + /** * Creates a cursor that can be used to determine how many images we have. * diff --git a/framework/src/org/apache/cordova/Capture.java b/framework/src/org/apache/cordova/Capture.java index a2dfafdc..cd115d40 100644 --- a/framework/src/org/apache/cordova/Capture.java +++ b/framework/src/org/apache/cordova/Capture.java @@ -19,6 +19,7 @@ package org.apache.cordova; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; @@ -32,10 +33,11 @@ import org.json.JSONObject; import android.app.Activity; import android.content.ContentValues; import android.content.Intent; -import android.graphics.Bitmap; +import android.database.Cursor; import android.graphics.BitmapFactory; import android.media.MediaPlayer; import android.net.Uri; +import android.provider.MediaStore; import android.util.Log; public class Capture extends Plugin { @@ -61,6 +63,7 @@ public class Capture extends Plugin { private double duration; // optional duration parameter for video recording private JSONArray results; // The array of results to be returned to the user private Uri imageUri; // Uri of captured image + private int numPics; // Number of pictures before capture activity //private CordovaInterface cordova; @@ -202,6 +205,9 @@ public class Capture extends Plugin { * Sets up an intent to capture images. Result handled by onActivityResult() */ private void captureImage() { + // Save the number of images currently on disk for later + this.numPics = queryImgDB().getCount(); + Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); // Specify file so that large image is captured and returned @@ -256,14 +262,6 @@ public class Capture extends Plugin { // It crashes in the emulator and on my phone with a null pointer exception // To work around it I had to grab the code from CameraLauncher.java try { - // Create an ExifHelper to save the exif data that is lost during compression - ExifHelper exif = new ExifHelper(); - exif.createInFile(DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()) + "/Capture.jpg"); - exif.readExifData(); - - // Read in bitmap of captured image - Bitmap bitmap = android.provider.MediaStore.Images.Media.getBitmap(this.cordova.getActivity().getContentResolver(), imageUri); - // Create entry in media store for image // (Don't use insertImage() because it uses default compression setting of 50 - no way to change it) ContentValues values = new ContentValues(); @@ -281,23 +279,22 @@ public class Capture extends Plugin { return; } } - - // Add compressed version of captured image to returned media store Uri + FileInputStream fis = new FileInputStream(DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()) + "/Capture.jpg"); OutputStream os = this.cordova.getActivity().getContentResolver().openOutputStream(uri); - bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os); + byte[] buffer = new byte[4096]; + int len; + while ((len = fis.read(buffer)) != -1) { + os.write(buffer, 0, len); + } + os.flush(); os.close(); - - bitmap.recycle(); - bitmap = null; - System.gc(); - - // Restore exif data to file - exif.createOutFile(FileUtils.getRealPathFromURI(uri, this.cordova)); - exif.writeExifData(); + fis.close(); // Add image to results results.put(createMediaFile(uri)); + checkForDuplicateImage(); + if (results.length() >= limit) { // Send Uri back to JavaScript for viewing image this.success(new PluginResult(PluginResult.Status.OK, results), this.callbackId); @@ -405,4 +402,36 @@ public class Capture extends Plugin { public void fail(JSONObject err) { this.error(new PluginResult(PluginResult.Status.ERROR, err), this.callbackId); } + + + /** + * Creates a cursor that can be used to determine how many images we have. + * + * @return a cursor + */ + private Cursor queryImgDB() { + return this.cordova.getActivity().getContentResolver().query( + android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, + new String[] { MediaStore.Images.Media._ID }, + null, + null, + null); + } + + /** + * Used to find out if we are in a situation where the Camera Intent adds to images + * to the content store. + */ + private void checkForDuplicateImage() { + Cursor cursor = queryImgDB(); + int currentNumOfImages = cursor.getCount(); + + // delete the duplicate file if the difference is 2 + if ((currentNumOfImages - numPics) == 2) { + cursor.moveToLast(); + int id = Integer.valueOf(cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media._ID))) - 1; + Uri uri = Uri.parse(MediaStore.Images.Media.EXTERNAL_CONTENT_URI + "/" + id); + this.cordova.getActivity().getContentResolver().delete(uri, null, null); + } + } }