Share canvas image on android - android

Hello so I write a small game where in the end you can share your result. The result is written on an image using canvas. The problem is when sharing i get the error "Error, could not locate the file". The error is seen on screen only and not reflected in logcat. I've already spent countless hours trying to solve it, but nothing seems to work. I get no errors what so ever but the file still appears to be impossible to share. Does anyone has a suggestion on why it does not work?
Quick recap: Load bitmap, make it a canvas, paint it, check for permissions to save, save it, get the URI of the saved file, use the URI inside of the share intent. I really don't see what is missing.
The canvas painting part was tested separately and I was able to share the bitmap to Facebook using fb library. Unfortunately android native share does not allow to share bitmaps without saving them.
In manifest I have WRITE and READ permissions for both internal and external storage. I would really appreciate any help.
Share button on click listener:
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.Myimage);
mutableBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
Canvas canvas = new Canvas(mutableBitmap);
Paint paint = new Paint();
paint.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
paint.setColor(Color.BLACK);
paint.setTextSize(170);
int top_margin = 1000;
int left_margin = 1700;
canvas.drawText("You got a ton of points", left_margin, top_margin, paint);
ActivityCompat.requestPermissions(test_process.this,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE},1);
Permission result:
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case 1: {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
sharethis(mutableBitmap);
} else {
Toast.makeText(test_process.this, "Permission denied to read your External storage", Toast.LENGTH_SHORT).show();
}
return;
}
}
}
Share method:
public void sharethis(Bitmap bitmap){
File file_path = getFilesDir();
File file = new File(file_path, "resultImg.jpg");
FileOutputStream fOut;
try {
fOut = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fOut);
fOut.flush();
fOut.close();
} catch (Exception e) {
e.printStackTrace();
Log.i("file saving problem", String.valueOf(e));
}
Uri uri = Uri.fromFile(file);
Uri uriContent = getImageContentUri(this, file);
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.setType("image/jpeg");
Log.i("Uri", String.valueOf(uri));
Log.i("UriContent", String.valueOf(uriContent));
intent.putExtra(Intent.EXTRA_STREAM, uriContent);
startActivity(Intent.createChooser(intent, "Share Cover Image"));
}
And URI convertor:
public static Uri getImageContentUri(Context context, File imageFile) {
String filePath = imageFile.getAbsolutePath();
Cursor cursor = context.getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
new String[] { MediaStore.Images.Media._ID },
MediaStore.Images.Media.DATA + "=? ",
new String[] { filePath }, null);
if (cursor != null && cursor.moveToFirst()) {
int id = cursor.getInt(cursor
.getColumnIndex(MediaStore.MediaColumns._ID));
Uri baseUri = Uri.parse("content://media/external/images/media");
return Uri.withAppendedPath(baseUri, "" + id);
} else {
if (imageFile.exists()) {
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DATA, filePath);
return context.getContentResolver().insert(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
} else {
return null;
}
}
}

getImageContentUri() is not going to work. Your file is on internal storage; third-party apps, including the MediaStore, have no access to it.
Get rid of getImageContentUri(). Set up FileProvider to serve files from getFilesDir(). Then, use FileProvider.getUriForFile() to get a Uri that you can use in your ACTION_SEND Intent.
Also:
You will need to add FLAG_GRANT_READ_URI_PERMISSION to the ACTION_SEND Intent
You do not need READ_EXTERNAL_STORAGE for any of this

Related

Camera Intent - how to?

Sorry to bother you guys, but I am not able to get a solution where In we take picture using intents. I know the default behavior of native camera is to save the picture at default directory/place of O.S. The thing is I have some requirements where I do not want to save the picture when clicked using camera app. There has to be a solution of this issue, be it like once we take a picture we could delete it right away, or there should be an alternate by which we won't allow O.S to save Image, please help.
Here is a piece of code I tried, tried several ways by creating a directory and then deleting file, nothing works.
public void takeImageFromCamera() {
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cameraIntent, CAMERA_REQUEST);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// Check for the integer request code originally supplied to startResolutionForResult().
if (requestCode == CAMERA_REQUEST && resultCode == RESULT_OK) {
if (isCameraPermissionGranted()) {
bitmap= (Bitmap) data.getExtras().get("data");
// bitmap = processReuiredImage(picUri);
getProfileDetailViaFace(encodeImageBitmapToString(bitmap));
Log.d("path",String.valueOf(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES)));
// getApplicationContext().getContentResolver().delete(, "/storage/emulated/0/Pictures", null);
// mediaStorageDir.getPath().delete();
} else {
requestCameraPermission();
}
}
public void takeImageFromCamera() {
File file = getOutputMediaFile(CAMERA_FILE_TYPE);
if (Build.VERSION.SDK_INT >= 24) {
try {
Method m = StrictMode.class.getMethod("disableDeathOnFileUriExposure");
m.invoke(null);
} catch (Exception e) {
e.printStackTrace();
}
}
picUri = Uri.fromFile(file);
Intent takePictureIntent = new
Intent(MediaStore.ACTION_IMAGE_CAPTURE_SECURE);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, picUri);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(takePictureIntent, CAMERA_REQUEST);
}
}
private File getOutputMediaFile(int type) {
mediaStorageDir = new
File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), "peppercard");
/**Create the storage directory if it does not exist*/
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
return null;
}
}
/**Create a media file name*/
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
if (type == CAMERA_FILE_TYPE) {
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"IMG_" + timeStamp + ".jpeg");
} else {
return null;
}
}
return mediaFile;
}
The thing is I have some requirements where I do not want to save the picture when clicked using camera app
The decision of whether or not to save an image is up to the camera app, not you. There are hundreds of camera apps that might respond to ACTION_IMAGE_CAPTURE, and the developers of those apps can do whatever they want.
There has to be a solution of this issue, be it like once we take a picture we could delete it right away, or there should be an alternate by which we won't allow O.S to save Image,
Take the photo yourself, using the camera APIs or libraries that wrap around them (e.g., CameraKit-Android, Fotoapparat).
There has to be a solution of this issue, be it like once we take
a picture we could delete it right away
Indeed there is. You could specify a path (even using a file provider) where the camera app has to put the image in a file.
Then when the camera app is done you can get the image from that file and then delete the file.
Have a look at Intent.EXTRA_OUTPUT.
Pretty standard your question. You can find a lot of example code on this site.
Final I have found the answer after waiting from past 2 days, yay..It will not save the file as I am just deleting the file after returning from the activity.
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, null, null, null)
int column_index_data = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToLast();
String imagePath = cursor.getString(column_index_data);
Bitmap bitmapImage = BitmapFactory.decodeFile(imagePath );
Log.d("bitmapImage", bitmapImage.toString()); /*delete file after taking picture*/
Log.d("imagePath", imagePath.toString());
File f = new File(imagePath);
if (f.exists()){
f.delete();
}
sendBroadcast(newIntent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,Uri.fromFile(f)));

ImageView not populating from file path

I can't get my ImageViews to update from either URI or file path - they just don't show an image
Intent to capture image:
Intent photo = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(photo, 1);
On ActivityResult
protected void onActivityResult(int requestCode, int resultCode, Intent data){
super.onActivityResult(requestCode, resultCode, data);
Uri imageUri = data.getData();
filePath = getRealPathFromURI(this, imageUri);
}
GetRealPathFromURI class:
public String getRealPathFromURI(Context context, Uri contentUri) {
Cursor cursor = null;
try {
String[] proj = { MediaStore.Images.Media.DATA };
cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} finally {
if (cursor != null) {
cursor.close();
}
}
}
It then inserts 'filePath' from onActivityResult in to a db
Retrieving from db and updating ImageViews
imgfilepath[y] = cursorc.getString(cursorc.getColumnIndex("IMAGE"));
imgFile[y] = new File(imgfilepath[y]);
Uri uri = Uri.fromFile(imgFile[y]);
String path = uri.getPath();
mImage.setImageURI(uri);
I've tried so many different ways to setImageBitmap etc which haven't worked (I can't remember all of them) - Can anyone see why this is not showing the image?
The image is in emulated storage and not the SD card.
EDIT:
I've added EXTRA_OUTPUT tag but I can't see the image in DDMS anywhere & the camera does not exit after taking the picture/accepting the image
Intent photo = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
final File root = new File(Environment.getExternalStorageDirectory() + File.separator + "MyDir" + File.separator);
root.mkdirs();
final String fname = "img_"+ System.currentTimeMillis() + ".jpg";
final File sdImageMainDirectory = new File(root, fname);
mImageUri = Uri.fromFile(sdImageMainDirectory);
photo.putExtra(MediaStore.EXTRA_OUTPUT, mImageUri);
startActivityForResult(photo, 1);
Uri imageUri = data.getData();
ACTION_IMAGE_CAPTURE does not return a Uri.
The image is in emulated storage
Perhaps that one camera app does, in which case that camera app has a bug, to go along with the return-a-Uri bug.
There are thousands of Android device models. These ship with hundreds of different camera apps pre-installed, and there are hundreds more available from the Play Store and elsewhere. Many will have ACTION_IMAGE_CAPTURE implementations. Most should follow the documented protocol. None should save the image for your request, because you did not tell the camera app where to save the image.
Either:
Provide a location, via EXTRA_OUTPUT, for the camera app to save the image to, then load the image from that location, or
Use data.getExtra("data") to get a Bitmap that represents a thumbnail-sized image, if you do not provide EXTRA_OUTPUT

Get uri of picture taken by camera

When the user takes a picture with the camera, I want the image displayed in an ImageView and I want to save the Uri to an online database. I heard saving the Uri of a picture is better than saving the path.
So this is how I start the camera:
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(getFile(getActivity())));
String a = String.valueOf(Uri.fromFile(getFile(getActivity())));
intent.putExtra("photo_uri", a);
startActivityForResult(intent, PICK_FROM_CAMERA);
where
private File getFile(Context context){
File sdCard = Environment.getExternalStorageDirectory();
File directory = new File (sdCard.getAbsolutePath() + "/Myapp");
if (!directory.exists()) {
directory.mkdirs();
}
String filename = "bl" + System.currentTimeMillis() + ".jpg";
File newFile = new File(directory, filename);
return newFile;
}
In onActivityResult:
Bundle extras = data.getExtras();
String photo_uri = extras.getString("photo_uri"); //null
This is always null. Btw before sending the intent the Uri looks like file://... instead of content:// which is the uri when I open an image from the gallery. I don't know if that's a problem.
Also, should I save the path instead of the Uri to the database? I read that the Uri can be complicated in certain phones or Android versions. When I let the user select an image from the gallery, I save the Uri to the database, so I think the best way is saving the Uri in this case as well.
I tried out many variations, but I get null every time I try to pass a variable with the intent...
After starting the intent:
Intent intentPicture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intentPicture,PICK_FROM_CAMERA);
In onActivityResult:
case PICK_FROM_CAMERA:
Uri selectedImageUri = data.getData();
InputStream imageStream = null;
try {
imageStream = getContentResolver().openInputStream(selectedImageUri);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Bitmap yourSelectedImage = BitmapFactory.decodeStream(imageStream);
break;
That's all.

Download image from new Google+ (plus) Photos Application

Recently Google added the Photos app for Google+ (plus) and it shows up when you launch an Intent to choose an image. However, if I select an image from Google+ Photos and try to use it in my application none of my current logic is able to return a usable URI or URL to actually get an image that I can download and manipulate. I'm currently using the "common" methods to try to manipulate the URI that can be found here on Stack Overflow and elsewhere. I can provide code if needed, but at this point I think it's kind of irrelevant since it works well for everything else except this new app. Any ideas on how to get a usable image?
The URI looks something like the following:
content://com.google.android.apps.photos.content/0/https%3A%2F%2Flh5.googleusercontent.com%<a bunch of letters and numbers here>
The MediaColumns.DATA info always returns null and the MediaColumns.DISPLAY_NAME always returns image.jpg no matter what I select from the Google Photos app. If I try to paste everything from https to the end in my browser, nothing comes up. Not sure how to get usable info from this.
When receiving the data intent, you should use the contentResolver to get the photos.
Here's what you should do:
String url = intent.getData().toString();
Bitmap bitmap = null;
InputStream is = null;
if (url.startsWith("content://com.google.android.apps.photos.content")){
is = getContentResolver().openInputStream(Uri.parse(url));
bitmap = BitmapFactory.decodeStream(is);
}
I did faced issues selecting images from new Google Photos app. I was able to resolve it by below code.
It works for me, basically what i did is i am checking if there is any authority is there or not in content URI. If it is there i am writing to temporary file and returning path of that temporary image. You can skip compression part while writing to temporary image
public static String getImageUrlWithAuthority(Context context, Uri uri) {
InputStream is = null;
if (uri.getAuthority() != null) {
try {
is = context.getContentResolver().openInputStream(uri);
Bitmap bmp = BitmapFactory.decodeStream(is);
return writeToTempImageAndGetPathUri(context, bmp).toString();
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
public static Uri writeToTempImageAndGetPathUri(Context inContext, Bitmap inImage) {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
String path = MediaStore.Images.Media.insertImage(inContext.getContentResolver(), inImage, "Title", null);
return Uri.parse(path);
}
P.S. : I have answered a similar question here
You have to use projection in order to get ImageColumns.DATA (or MediaColumns.DATA):
private String getRealPathFromURI(Uri contentURI) {
// Projection makes ContentResolver to get needed columns only
String[] medData = { MediaStore.Images.Media.DATA };
Cursor cursor = getContentResolver().query(contentURI, medData, null, null, null);
// this is how you can simply get Bitmap
Bitmap bmp = MediaStore.Images.Media.getBitmap(getContentResolver(), contentURI);
// After using projection cursor will have needed DATA column
cursor.moveToFirst();
final int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
return cursor.getString(idx);
}

Get Path and Filename from Camera intent result

I want to make a picture with the camera intent and save it to the default DCIM folder. Then I want to get the path/filename where the picture is stored.
I am trying it with the following code:
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, TAKE_PICTURE);
With this code, the camera opens and after I have taken one picture it closes and saves the picture to the default image folder (usually /dcim/camera or sdcard/dcim/camera...)
but how can I get the path and filename of the taken picture now?
I have tried almost everything in onActivityResult
I tried
String result = data.getData();
and
String result = data.getDataString();
and
String result = data.toURI();
and
Uri uri = data.getData();
etc.
I researched the last two days to find a solution for this, there are many articles on the web and on stackoverflow but nothing works.
I don't want a thumbnail, I only want the path (uri?) to the image that the camera has taken.
Thank you for any help
EDIT:
When I try:
path=Environment.DIRECTORY_DCIM + "/test.jpg";
File file = new File(path);
Uri outputFileUri = Uri.fromFile(file);
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
startActivityForResult(intent, TAKE_PICTURE);
it does not store the image as test.jpg but with the normal image name 2011-10-03.....jpg (but that is ok too, i only need the path to the image, it does not matter what the name is).
Best regards
EDIT Again
path=Environment.getExternalStorageDirectory().getPath() + "/DCIM/Camera/";
File file = new File(path,"test111111111.jpg");
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
Uri outputFileUri = Uri.fromFile(file);
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
startActivityForResult(intent, TAKE_PICTURE);
When I try this, it stores the image to the right folder and with the given name (e.g. test111111.jpg).
But how can I get the filepath now in onActivityResult?
The picture will be stored twice, first on gallery folder, and after on the file you especified on putExtra(MediaStore.EXTRA_OUTPUT, path) method.
You can obtain the last picture taken doing that:
/**
* Gets the last image id from the media store
* #return
*/
private int getLastImageId(){
final String[] imageColumns = { MediaStore.Images.Media._ID, MediaStore.Images.Media.DATA };
final String imageOrderBy = MediaStore.Images.Media._ID+" DESC";
Cursor imageCursor = managedQuery(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageColumns, null, null, imageOrderBy);
if(imageCursor.moveToFirst()){
int id = imageCursor.getInt(imageCursor.getColumnIndex(MediaStore.Images.Media._ID));
String fullPath = imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA));
Log.d(TAG, "getLastImageId::id " + id);
Log.d(TAG, "getLastImageId::path " + fullPath);
imageCursor.close();
return id;
}else{
return 0;
}
}
This sample was based on post: Deleting a gallery image after camera intent photo taken
you can use like this in onActivityResult()
if(requestCode==CAMERA_CAPTURE)
{
Cursor cursor = getContentResolver().query(Media.EXTERNAL_CONTENT_URI, new String[]{Media.DATA, Media.DATE_ADDED, MediaStore.Images.ImageColumns.ORIENTATION}, Media.DATE_ADDED, null, "date_added ASC");
if(cursor != null && cursor.moveToFirst())
{
do
{
String picturePath =cursor.getString(cursor.getColumnIndex(Media.DATA));
Uri selectedImage = Uri.parse(picturePath);
}
while(cursor.moveToNext());
cursor.close();
File out = new File(picturePath);
try
{
mOriginal = decodeFile(out);
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
mSelected.setImageBitmap(mOriginal);
}
}
When you are starting the ACTION_IMAGE_CAPTURE you can pass an extra MediaStore.EXTRA_OUTPUT as the URI of the file where you want to save the picture.
Here is a simple example:
File file = new File(path);
Uri outputFileUri = Uri.fromFile(file);
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
startActivityForResult(intent, TAKE_PICTURE);
EDIT: I just tried on my device and file.createNewFile() solved the problem for me.

Categories

Resources