Sharing Bitmap via Android Intent
Solution 1
I found 2 variants of the solution. Both involve saving Bitmap to storage, but the image will not appear in the gallery.
First variant:
Saving to external storage
- but to private folder of the app.
- for API <= 18 it requires permission, for newer it does not.
1. Setting permissions
Add into AndroidManifest.xml before tag
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18"/>
2. Saving method:
/**
* Saves the image as PNG to the app's private external storage folder.
* @param image Bitmap to save.
* @return Uri of the saved file or null
*/
private Uri saveImageExternal(Bitmap image) {
//TODO - Should be processed in another thread
Uri uri = null;
try {
File file = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "to-share.png");
FileOutputStream stream = new FileOutputStream(file);
image.compress(Bitmap.CompressFormat.PNG, 90, stream);
stream.close();
uri = Uri.fromFile(file);
} catch (IOException e) {
Log.d(TAG, "IOException while trying to write file for sharing: " + e.getMessage());
}
return uri;
}
3. Checking storage accesibility
External storage might not be accessible, so you should check it before trying to save: https://developer.android.com/training/data-storage/files
/**
* Checks if the external storage is writable.
* @return true if storage is writable, false otherwise
*/
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
}
Second variant
Saving to cacheDir using FileProvider. It does not require any permissions.
1. Setup FileProvider in AndroidManifest.xml
<manifest>
...
<application>
...
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.mydomain.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
...
</application>
</manifest>
2. Add path to the res/xml/file_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<cache-path name="shared_images" path="images/"/>
</paths>
</resources>
3. Saving method:
/**
* Saves the image as PNG to the app's cache directory.
* @param image Bitmap to save.
* @return Uri of the saved file or null
*/
private Uri saveImage(Bitmap image) {
//TODO - Should be processed in another thread
File imagesFolder = new File(getCacheDir(), "images");
Uri uri = null;
try {
imagesFolder.mkdirs();
File file = new File(imagesFolder, "shared_image.png");
FileOutputStream stream = new FileOutputStream(file);
image.compress(Bitmap.CompressFormat.PNG, 90, stream);
stream.flush();
stream.close();
uri = FileProvider.getUriForFile(this, "com.mydomain.fileprovider", file);
} catch (IOException e) {
Log.d(TAG, "IOException while trying to write file for sharing: " + e.getMessage());
}
return uri;
}
More info about file provider - https://developer.android.com/reference/android/support/v4/content/FileProvider
Compressing and saving can be time-consuming, therefore this should be done in a different thread
Actual sharing
/**
* Shares the PNG image from Uri.
* @param uri Uri of image to share.
*/
private void shareImageUri(Uri uri){
Intent intent = new Intent(android.content.Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_STREAM, uri);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setType("image/png");
startActivity(intent);
}
Solution 2
As CommonsWare stated you need to get the URI to the bitmap and pass that as your Extra.
String bitmapPath = Images.Media.insertImage(getContentResolver(), bitmap,"title", null);
Uri bitmapUri = Uri.parse(bitmapPath);
...
intent.putExtra(Intent.EXTRA_STREAM, bitmapUri );
Solution 3
Finally, I got the solution:
Step 1 : Share Intent handling Block. This will Pop Up your window with list of Applications in you phone
public void share_bitMap_to_Apps() {
Intent i = new Intent(Intent.ACTION_SEND);
i.setType("image/*");
ByteArrayOutputStream stream = new ByteArrayOutputStream();
/*compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] bytes = stream.toByteArray();*/
i.putExtra(Intent.EXTRA_STREAM, getImageUri(mContext, getBitmapFromView(relative_me_other)));
try {
startActivity(Intent.createChooser(i, "My Profile ..."));
} catch (android.content.ActivityNotFoundException ex) {
ex.printStackTrace();
}
}
Step 2 : Converting your view to Bitmap
public static Bitmap getBitmapFromView(View view) {
// Define a bitmap with the same size as the view
Bitmap returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
// Bind a canvas to it
Canvas canvas = new Canvas(returnedBitmap);
// Get the view's background
Drawable bgDrawable = view.getBackground();
if (bgDrawable != null)
// has background drawable, then draw it on the canvas
bgDrawable.draw(canvas);
else
// does not have background drawable, then draw white background on the canvas
canvas.drawColor(Color.WHITE);
// draw the view on the canvas
view.draw(canvas);
// return the bitmap
return returnedBitmap;
}
Step 3 : To get The URI from Bitmap Image
public Uri getImageUri(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);
}
Solution 4
ImageButton capture_share = (ImageButton) findViewById(R.id.share);
capture_share.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String bitmapPath = MediaStore.Images.Media.insertImage(getContentResolver(), bitmap,"title", null);
Uri bitmapUri = Uri.parse(bitmapPath);
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("image/png");
intent.putExtra(Intent.EXTRA_STREAM, bitmapUri);
startActivity(Intent.createChooser(intent, "Share"));
}
});
Solution 5
Quoting the documentation:
A content: URI holding a stream of data associated with the Intent, used with ACTION_SEND to supply the data being sent.
b
, therefore, is not supposed to be a Bitmap
, but rather a Uri
pointing to a Bitmap
, served by a ContentProvider
. For example, you could write the Bitmap
to a file, then use FileProvider
to serve it.
Related videos on Youtube
Jhilmil Chatterjee
Updated on July 09, 2022Comments
-
Jhilmil Chatterjee almost 2 years
In my android app, I have a bitmap (say b) and a button. Now when I click on the button, I want to share the bitmap. I am making use of the below code inside my
onClick()
to achieve this :-Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("image/png"); intent.putExtra(Intent.EXTRA_STREAM, b); startActivity(Intent.createChooser(intent , "Share"));
I was expecting a list of all application which are able to handle this intent but I get nothing. There is no list of apps nor is there any error in android studio. My application just get hanged for sometime and then quits.
I have checked the bitmap and it is fine (its not null).
Where am I a going wrong ?
-
TylerH about 6 yearsPossible duplicate of How to attach a Bitmap when launching ACTION_SEND intent
-
-
appsthatmatter over 7 yearsdon't forget to require android.permission.WRITE_EXTERNAL_STORAGE
-
Rohit Poudel almost 7 yearsAdd some description to answer for clear understanding. @lalit Baghel
-
Jaydip Kalkani about 6 yearsIt works but also stores image. so, image is also showing in gallary. How can i avoid saving image or showing this into gallary.
-
Shajeel Afzal about 6 yearsAny solution to do it without write external storage?
-
daka about 6 years@JaydipKalkani I need this too, but maybe we cant.
-
Morse almost 6 yearsThis is the best solution I think , step-by-step detailed explanation. Sharing with images stored in cache is better if security is of concern. I had missed a step of adding xml and provider so it was not working but finally followed the steps and it works now.
-
Pandurang Yachwad over 5 yearsBest solution over internet for sharing over email.
-
Mathijs over 4 yearsThe new package name for the FileProvider since Android X is:
androidx.core.content.FileProvider
. -
Raphael C almost 3 years
insertImage
deprecated in API level 29. inserting of images should be performed using MediaColumns#IS_PENDING, which offers richer control over lifecycle. (which will also be deprecated soon enough lol)