mirror of
https://github.com/apache/cordova-plugin-camera.git
synced 2025-02-23 06:43:11 +08:00
* GH-341 - GH-577 Fixed the Save Photo To Album starting from camera - Android - saveToPhotoAlbum feature fixed by taken into count content - uri. (writeUncompressedImage method) ( see: https://github.com/apache/cordova-plugin-camera/issues/611#issuecomment-700273405 ) - make saveToPhotoAlbum future proof by using the MediaStore to insert the taken image - made a method to calculate the compressFormat based on the encodingType (JPEG or PNG) - layout of the performCrop method is adjusted - removed unused rotate variable inside processResultFromGallery method * Add extra VO class to the plugin.xml * added package declaration to new VO * GH-341 - GH-577 https://github.com/apache/cordova-plugin-camera/pull/669#discussion_r504632953 listen to review
This commit is contained in:
parent
43d6591d9e
commit
ebe0517a24
@ -73,6 +73,7 @@
|
||||
<source-file src="src/android/FileHelper.java" target-dir="src/org/apache/cordova/camera" />
|
||||
<source-file src="src/android/ExifHelper.java" target-dir="src/org/apache/cordova/camera" />
|
||||
<source-file src="src/android/FileProvider.java" target-dir="src/org/apache/cordova/camera" />
|
||||
<source-file src="src/android/GalleryPathVO.java" target-dir="src/org/apache/cordova/camera" />
|
||||
<source-file src="src/android/xml/camera_provider_paths.xml" target-dir="res/xml" />
|
||||
|
||||
<js-module src="www/CameraPopoverHandle.js" name="CameraPopoverHandle">
|
||||
|
@ -21,6 +21,7 @@ package org.apache.cordova.camera;
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
@ -34,6 +35,7 @@ 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.MediaStore;
|
||||
@ -51,7 +53,6 @@ import org.json.JSONException;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
@ -405,58 +406,57 @@ 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);
|
||||
// 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
|
||||
croppedFilePath = createCaptureFile(this.encodingType, System.currentTimeMillis() + "").getAbsolutePath();
|
||||
croppedUri = Uri.parse(croppedFilePath);
|
||||
cropIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
cropIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||
cropIntent.putExtra("output", croppedUri);
|
||||
|
||||
|
||||
// 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 (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
|
||||
croppedFilePath = createCaptureFile(this.encodingType, System.currentTimeMillis() + "").getAbsolutePath();
|
||||
croppedUri = Uri.parse(croppedFilePath);
|
||||
cropIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
cropIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||
cropIntent.putExtra("output", croppedUri);
|
||||
|
||||
|
||||
// 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies all needed transformation to the image received from the camera.
|
||||
@ -494,16 +494,18 @@ 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(getPicturesPath()));
|
||||
GalleryPathVO galleryPathVO = getPicturesPath();
|
||||
galleryUri = Uri.fromFile(new File(galleryPathVO.getGalleryPath()));
|
||||
|
||||
if (this.allowEdit && this.croppedUri != null) {
|
||||
writeUncompressedImage(croppedUri, galleryUri);
|
||||
} else {
|
||||
Uri imageUri = this.imageUri;
|
||||
writeUncompressedImage(imageUri, galleryUri);
|
||||
if (Build.VERSION.SDK_INT <= 28) { // Between LOLLIPOP_MR1 and P, can be changed later to the constant Build.VERSION_CODES.P
|
||||
writeTakenPictureToGalleryLowerThanAndroidQ(galleryUri);
|
||||
} else { // Android Q or higher
|
||||
writeTakenPictureToGalleryStartingFromAndroidQ(galleryPathVO);
|
||||
}
|
||||
}
|
||||
|
||||
refreshGallery(galleryUri);
|
||||
}
|
||||
|
||||
// If sending base64 image back
|
||||
@ -567,9 +569,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
|
||||
|
||||
// Add compressed version of captured image to returned media store Uri
|
||||
OutputStream os = this.cordova.getActivity().getContentResolver().openOutputStream(uri);
|
||||
CompressFormat compressFormat = encodingType == JPEG ?
|
||||
CompressFormat.JPEG :
|
||||
CompressFormat.PNG;
|
||||
CompressFormat compressFormat = getCompressFormatForEncodingType(encodingType);
|
||||
|
||||
bitmap.compress(compressFormat, this.mQuality, os);
|
||||
os.close();
|
||||
@ -597,18 +597,41 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
|
||||
bitmap = null;
|
||||
}
|
||||
|
||||
private String getPicturesPath() {
|
||||
private void writeTakenPictureToGalleryLowerThanAndroidQ(Uri galleryUri) throws IOException {
|
||||
writeUncompressedImage(imageUri, galleryUri);
|
||||
refreshGallery(galleryUri);
|
||||
}
|
||||
|
||||
private void writeTakenPictureToGalleryStartingFromAndroidQ(GalleryPathVO galleryPathVO) throws IOException {
|
||||
// Starting from Android Q, working with the ACTION_MEDIA_SCANNER_SCAN_FILE intent is deprecated
|
||||
// https://developer.android.com/reference/android/content/Intent#ACTION_MEDIA_SCANNER_SCAN_FILE
|
||||
// we must start working with the MediaStore from Android Q on.
|
||||
ContentResolver resolver = this.cordova.getActivity().getContentResolver();
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, galleryPathVO.getGalleryFileName());
|
||||
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, getMimetypeForFormat(encodingType));
|
||||
Uri galleryOutputUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
|
||||
|
||||
InputStream fileStream = org.apache.cordova.camera.FileHelper.getInputStreamFromUriString(imageUri.toString(), cordova);
|
||||
writeUncompressedImage(fileStream, galleryOutputUri);
|
||||
}
|
||||
|
||||
private CompressFormat getCompressFormatForEncodingType(int encodingType) {
|
||||
return encodingType == JPEG ? CompressFormat.JPEG : CompressFormat.PNG;
|
||||
}
|
||||
|
||||
private GalleryPathVO getPicturesPath() {
|
||||
String timeStamp = new SimpleDateFormat(TIME_FORMAT).format(new Date());
|
||||
String imageFileName = "IMG_" + timeStamp + (this.encodingType == JPEG ? JPEG_EXTENSION : PNG_EXTENSION);
|
||||
File storageDir = Environment.getExternalStoragePublicDirectory(
|
||||
Environment.DIRECTORY_PICTURES);
|
||||
storageDir.mkdirs();
|
||||
String galleryPath = storageDir.getAbsolutePath() + "/" + imageFileName;
|
||||
return galleryPath;
|
||||
return new GalleryPathVO(storageDir.getAbsolutePath(), imageFileName);
|
||||
}
|
||||
|
||||
private void refreshGallery(Uri contentUri) {
|
||||
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
|
||||
// Starting from Android Q, working with the ACTION_MEDIA_SCANNER_SCAN_FILE intent is deprecated
|
||||
mediaScanIntent.setData(contentUri);
|
||||
this.cordova.getActivity().sendBroadcast(mediaScanIntent);
|
||||
}
|
||||
@ -640,9 +663,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
|
||||
String modifiedPath = getTempDirectoryPath() + "/" + fileName;
|
||||
|
||||
OutputStream os = new FileOutputStream(modifiedPath);
|
||||
CompressFormat compressFormat = this.encodingType == JPEG ?
|
||||
CompressFormat.JPEG :
|
||||
CompressFormat.PNG;
|
||||
CompressFormat compressFormat = getCompressFormatForEncodingType(this.encodingType);
|
||||
|
||||
bitmap.compress(compressFormat, this.mQuality, os);
|
||||
os.close();
|
||||
@ -679,7 +700,6 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
|
||||
return;
|
||||
}
|
||||
}
|
||||
int rotate = 0;
|
||||
|
||||
String fileLocation = FileHelper.getRealPath(uri, this.cordova);
|
||||
LOG.d(LOG_TAG, "File location is: " + fileLocation);
|
||||
@ -900,34 +920,11 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
|
||||
private void writeUncompressedImage(Uri src, Uri dest) throws FileNotFoundException,
|
||||
IOException {
|
||||
|
||||
FileInputStream fis = new FileInputStream(FileHelper.stripFileProtocol(src.toString()));
|
||||
InputStream fis = FileHelper.getInputStreamFromUriString(src.toString(), cordova);
|
||||
writeUncompressedImage(fis, dest);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create entry in media store for image
|
||||
*
|
||||
* @return uri
|
||||
*/
|
||||
private Uri getUriFromMediaStore() {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(MediaStore.Images.Media.MIME_TYPE, JPEG_MIME_TYPE);
|
||||
Uri uri;
|
||||
try {
|
||||
uri = this.cordova.getActivity().getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
|
||||
} catch (RuntimeException e) {
|
||||
LOG.d(LOG_TAG, "Can't write to external media storage.");
|
||||
try {
|
||||
uri = this.cordova.getActivity().getContentResolver().insert(MediaStore.Images.Media.INTERNAL_CONTENT_URI, values);
|
||||
} catch (RuntimeException ex) {
|
||||
LOG.d(LOG_TAG, "Can't write to internal media storage.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a scaled and rotated bitmap based on the target width and height
|
||||
*
|
||||
@ -1258,9 +1255,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
|
||||
*/
|
||||
public void processPicture(Bitmap bitmap, int encodingType) {
|
||||
ByteArrayOutputStream jpeg_data = new ByteArrayOutputStream();
|
||||
CompressFormat compressFormat = encodingType == JPEG ?
|
||||
CompressFormat.JPEG :
|
||||
CompressFormat.PNG;
|
||||
CompressFormat compressFormat = getCompressFormatForEncodingType(encodingType);
|
||||
|
||||
try {
|
||||
if (bitmap.compress(compressFormat, mQuality, jpeg_data)) {
|
||||
|
25
src/android/GalleryPathVO.java
Normal file
25
src/android/GalleryPathVO.java
Normal file
@ -0,0 +1,25 @@
|
||||
package org.apache.cordova.camera;
|
||||
|
||||
public class GalleryPathVO {
|
||||
private final String galleryPath;
|
||||
private String picturesDirectory;
|
||||
private String galleryFileName;
|
||||
|
||||
public GalleryPathVO(String picturesDirectory, String galleryFileName) {
|
||||
this.picturesDirectory = picturesDirectory;
|
||||
this.galleryFileName = galleryFileName;
|
||||
this.galleryPath = this.picturesDirectory + "/" + this.galleryFileName;
|
||||
}
|
||||
|
||||
public String getGalleryPath() {
|
||||
return galleryPath;
|
||||
}
|
||||
|
||||
public String getPicturesDirectory() {
|
||||
return picturesDirectory;
|
||||
}
|
||||
|
||||
public String getGalleryFileName() {
|
||||
return galleryFileName;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user