android - save image into gallery
Solution 1
MediaStore.Images.Media.insertImage(getContentResolver(), yourBitmap, yourTitle , yourDescription);
The former code will add the image at the end of the gallery. If you want to modify the date so it appears at the beginning or any other metadata, see the code below (Cortesy of S-K, samkirton):
https://gist.github.com/samkirton/0242ba81d7ca00b475b9
/**
* Android internals have been modified to store images in the media folder with
* the correct date meta data
* @author samuelkirton
*/
public class CapturePhotoUtils {
/**
* A copy of the Android internals insertImage method, this method populates the
* meta data with DATE_ADDED and DATE_TAKEN. This fixes a common problem where media
* that is inserted manually gets saved at the end of the gallery (because date is not populated).
* @see android.provider.MediaStore.Images.Media#insertImage(ContentResolver, Bitmap, String, String)
*/
public static final String insertImage(ContentResolver cr,
Bitmap source,
String title,
String description) {
ContentValues values = new ContentValues();
values.put(Images.Media.TITLE, title);
values.put(Images.Media.DISPLAY_NAME, title);
values.put(Images.Media.DESCRIPTION, description);
values.put(Images.Media.MIME_TYPE, "image/jpeg");
// Add the date meta data to ensure the image is added at the front of the gallery
values.put(Images.Media.DATE_ADDED, System.currentTimeMillis());
values.put(Images.Media.DATE_TAKEN, System.currentTimeMillis());
Uri url = null;
String stringUrl = null; /* value to be returned */
try {
url = cr.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
if (source != null) {
OutputStream imageOut = cr.openOutputStream(url);
try {
source.compress(Bitmap.CompressFormat.JPEG, 50, imageOut);
} finally {
imageOut.close();
}
long id = ContentUris.parseId(url);
// Wait until MINI_KIND thumbnail is generated.
Bitmap miniThumb = Images.Thumbnails.getThumbnail(cr, id, Images.Thumbnails.MINI_KIND, null);
// This is for backward compatibility.
storeThumbnail(cr, miniThumb, id, 50F, 50F,Images.Thumbnails.MICRO_KIND);
} else {
cr.delete(url, null, null);
url = null;
}
} catch (Exception e) {
if (url != null) {
cr.delete(url, null, null);
url = null;
}
}
if (url != null) {
stringUrl = url.toString();
}
return stringUrl;
}
/**
* A copy of the Android internals StoreThumbnail method, it used with the insertImage to
* populate the android.provider.MediaStore.Images.Media#insertImage with all the correct
* meta data. The StoreThumbnail method is private so it must be duplicated here.
* @see android.provider.MediaStore.Images.Media (StoreThumbnail private method)
*/
private static final Bitmap storeThumbnail(
ContentResolver cr,
Bitmap source,
long id,
float width,
float height,
int kind) {
// create the matrix to scale it
Matrix matrix = new Matrix();
float scaleX = width / source.getWidth();
float scaleY = height / source.getHeight();
matrix.setScale(scaleX, scaleY);
Bitmap thumb = Bitmap.createBitmap(source, 0, 0,
source.getWidth(),
source.getHeight(), matrix,
true
);
ContentValues values = new ContentValues(4);
values.put(Images.Thumbnails.KIND,kind);
values.put(Images.Thumbnails.IMAGE_ID,(int)id);
values.put(Images.Thumbnails.HEIGHT,thumb.getHeight());
values.put(Images.Thumbnails.WIDTH,thumb.getWidth());
Uri url = cr.insert(Images.Thumbnails.EXTERNAL_CONTENT_URI, values);
try {
OutputStream thumbOut = cr.openOutputStream(url);
thumb.compress(Bitmap.CompressFormat.JPEG, 100, thumbOut);
thumbOut.close();
return thumb;
} catch (FileNotFoundException ex) {
return null;
} catch (IOException ex) {
return null;
}
}
}
Solution 2
Actually, you can save you picture at any place. If you want to save in a public space, so any other application can access, use this code:
storageDir = new File(
Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES
),
getAlbumName()
);
The picture doesn't go to the album. To do this, you need to call a scan:
private void galleryAddPic() {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File(mCurrentPhotoPath);
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
this.sendBroadcast(mediaScanIntent);
}
You can found more info at https://developer.android.com/training/camera/photobasics.html#TaskGallery
Solution 3
I've tried a lot of things to let this work on Marshmallow and Lollipop. Finally i ended up moving the saved picture to the DCIM folder (new Google Photo app scan images only if they are inside this folder apparently)
public static File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
.format(System.currentTimeInMillis());
File storageDir = new File(Environment
.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) + "/Camera/");
if (!storageDir.exists())
storageDir.mkdirs();
File image = File.createTempFile(
timeStamp, /* prefix */
".jpeg", /* suffix */
storageDir /* directory */
);
return image;
}
And then the standard code for scanning files which you can find in the Google Developers site too.
public static void addPicToGallery(Context context, String photoPath) {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File(photoPath);
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
context.sendBroadcast(mediaScanIntent);
}
Please remember that this folder could not be present in every device in the world and that starting from Marshmallow (API 23), you need to request the permission to WRITE_EXTERNAL_STORAGE to the user.
Solution 4
According to this course, the correct way to do this is:
Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES
)
This will give you the root path for the gallery directory.
Solution 5
private void galleryAddPic() {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File(mCurrentPhotoPath);
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
this.sendBroadcast(mediaScanIntent);
}
Related videos on Youtube
Christian Giupponi
Updated on January 12, 2022Comments
-
Christian Giupponi over 2 years
i have an app with a gallery of images and i want that the user can save it into his own gallery. I've created an option menu with a single voice "save" to allow that but the problem is...how can i save the image into the gallery?
this is my code:
@Override public boolean onOptionsItemSelected(MenuItem item) { // Handle item selection switch (item.getItemId()) { case R.id.menuFinale: imgView.setDrawingCacheEnabled(true); Bitmap bitmap = imgView.getDrawingCache(); File root = Environment.getExternalStorageDirectory(); File file = new File(root.getAbsolutePath()+"/DCIM/Camera/img.jpg"); try { file.createNewFile(); FileOutputStream ostream = new FileOutputStream(file); bitmap.compress(CompressFormat.JPEG, 100, ostream); ostream.close(); } catch (Exception e) { e.printStackTrace(); } return true; default: return super.onOptionsItemSelected(item); } }
i'm not sure of this part of code:
File root = Environment.getExternalStorageDirectory(); File file = new File(root.getAbsolutePath()+"/DCIM/Camera/img.jpg");
is it correct to save into the gallery? unfortunately the code doesn't work :(
-
user3233280 over 10 yearshave you resolved this issue ? can u please share with me
-
user3233280 over 10 yearsi am also having same problem stackoverflow.com/questions/21951558/…
-
ChallengeAccepted over 9 yearsFor those of you who are still having issues saving the file, it might be because your url contains illegal characters such as "?", ":", and "-" Remove those and it should work. This is a common error in foreign devices and the android emulators. See more about it here: stackoverflow.com/questions/11394616/…
-
Bao Lei almost 5 yearsThe accepted answer is a little outdated in 2019. I have written an updated answer here: stackoverflow.com/questions/36624756/…
-
-
Christian Giupponi over 12 yearsi tried this new code but it crashed java.lang.NoSuchFieldError: android.os.Environment.DIRECTORY_PICTURES
-
Christian Giupponi over 12 yearsok thanks, so there is no way to put an image on the gallery with android < 2.2?
-
eric.itzhak about 12 yearsThis saves the image, but to the end of the gallery though when you take a picture with camera it's saves on top. How can i save the image to top of gallery?
-
Phil almost 12 yearsPerfect - a link directly to the Android Developer website. This worked and was a simple solution.
-
Kyle Clegg over 11 yearsNote that your must also add <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> to your manifext.xml.
-
S-K' about 10 yearsImages are not saved at the top of the gallery because internally insertImage does not add any date meta data. Please see this GIST: gist.github.com/0242ba81d7ca00b475b9.git it is an exact copy of the insertImage method but it adds the date meta date to ensure the image is added at the front of the gallery.
-
sebastianf182 about 10 years@S-K'I can't access that URL. Please update it and I will update my answer so it has both options. Cheers
-
minipif almost 10 yearsHere is the correct GIST link mentioned above (needed to remove the
.git
at the end) -
ShadowGod about 9 yearsYou just need to remember to add the DATE_TAKEN to the values in order for it to show up on top
-
Hugo Gresse over 8 yearsThis is way a nice simple solution as we don't need to change the whole implementation and that we can create a custom folder for the apps.
-
Jérémy Reynaud over 8 yearsThanks for the information concerning Google Photos.
-
Jérémy Reynaud over 8 yearsSending a broadcast may be a waste of resource when you can scan only a file: stackoverflow.com/a/5814533/43051.
-
Predrag Manojlovic almost 8 yearsThis is one and only solution explaining well. Nobody else mentioned that file must be in DCIM folder. Thank you!!!
-
snachmsm over 7 yearsI had to add
values.put(MediaStore.Images.Media.DATE_MODIFIED, System.currentTimeMillis()/1000);
line, some Samsung devices and/or TouchWizz versions requires that... even if DOC says to NOT set this field (also informs that value is in seconds, so /1000) -
Siarhei about 7 yearsits's really good to know about this option, but unfortunately not works on some devices with android 6, so
ContentProvider
preferable solytion -
saltandpepper over 6 years
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)
did the trick for me. Thanks! -
Andrew Koster over 5 yearsGood answer, but it would be better with the addition of the "galleryAddPic" method from the other answers here, since you will usually want the Gallery app to notice new pictures.
-
Kopi Bryant over 5 yearsHow to change the file folder name?
-
Daniel Reyhanian about 5 yearsWhere do you actually pass the bitmap?
-
riggaroo almost 5 years
getExternalStoragePublicDirectory()
is now deprecated on API 29. Need to use MediaStore -
MatPag almost 5 years@riggaroo Yes you are right Rebecca, i will update the answer ASAP
-
Noor Hossain over 4 yearsin this criteria this is the best answer
-
Michael Abyzov over 3 years
Environment.getExternalStoragePublicDirectory
andIntent.ACTION_MEDIA_SCANNER_SCAN_FILE
are deprecated now... -
Michael Abyzov over 3 years
Environment.getExternalStoragePublicDirectory
is already deprecated... -
Michael Abyzov over 3 years
MediaStore.Images.Media.insertImage(...)
is already deprecated. -
Michael Paccione about 3 yearsWhere is finalBitmap initialized in your code... it is missing in the example
-
javatar about 3 years@MichealPaccione Obviously you need to have your image in a Bitmap. If you having problem in creating bitmap object of the image you need to save, then its a different case. try resolving it first.
-
Hank Chan about 3 yearsAs of 2021, this is the only answer that works!
-
Hank Chan about 3 yearsDCIM directory stores images in File app, as should be the use cases now for all Android phones. Gallery app no longer exists on Pixel.
-
MosesK almost 2 yearsNice, am able to save the image into the android gallery and when I check the image in the gallery its actually in that location. But how do I actually read the image / retrieve the image from the gallery to show it to an imageview ? For anybody wondering you can pass in the content resolver by calling the system function getContentResolver().