Add image to Media Gallery - Android
Thanks @zgc7009, you set me on the right track. I used some of your code, and this is the end result for anyone else wanting to solve.
The problem indeed was that I was storing the image in my application's local storage.
File storedImagePath = generateImagePath("player", "png");
if (!compressAndSaveImage(storedImagePath, bitmap)) {
return null;
}
Uri url = addImageToGallery(context.getContentResolver(), "png", storedImagePath);
Where the three methods used are:
Generate Path
private static File getImagesDirectory() {
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + File.separator + IMAGE_DIR);//Environment.getExternalStorageDirectory()
if (!file.mkdirs() && !file.isDirectory()) {
Log.e("mkdir", "Directory not created");
}
return file;
}
public static File generateImagePath(String title, String imgType) {
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy-hh-mm-ss");
return new File(getImagesDirectory(), title + "_" + sdf.format(new Date()) + "." + imgType);
}
Compress And Save
public boolean compressAndSaveImage(File file, Bitmap bitmap) {
boolean result = false;
try {
FileOutputStream fos = new FileOutputStream(file);
if (result = bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos)) {
Log.w("image manager", "Compression success");
}
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
Add To Gallery
public Uri addImageToGallery(ContentResolver cr, String imgType, File filepath) {
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.TITLE, "player");
values.put(MediaStore.Images.Media.DISPLAY_NAME, "player");
values.put(MediaStore.Images.Media.DESCRIPTION, "");
values.put(MediaStore.Images.Media.MIME_TYPE, "image/" + imgType);
values.put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis());
values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis());
values.put(MediaStore.Images.Media.DATA, filepath.toString());
return cr.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
}
You could also use MediaStore's static methods...
public String addImageToGallery(ContentResolver cr, File filepath) {
try {
return MediaStore.Images.Media.insertImage(cr, filepath.toString(),
filepath.getName(), "Image Description");
} catch (FileNotFoundException e) {
e.printStackTrace();
return e.getMessage();
}
}
The String
returned from insertImage
is the same as calling toString()
on the Uri
object in the accepted answer.
I know this is an older post but I hope this can help others who still find their way here.
I would put this as a comment as I don't have time to really go into detail about things, but it's obviously too long. Try something like this (I use this for storing bitmaps to the gallery). As a note, it doesn't seem you are doing anything but scanning an image. Right now it seems you are storing the file to your internal storage, not your phones content (gallery).
Assume we are running this from ActivityA.class that extends Activity
/**
* Will save our card (currently set as a bitmap) as a jpeg and save it into our devices
* native photo gallery. Unfortunately, the default method for this will add the image to the bottom
* of the gallery by default, that is no good. This more complex method that utilizes Android's
* native methods will allow us to store the bitmap at the top of the gallery by setting it's
* meta data to today's date.
*/
public class SaveBitmapToDevice extends AsyncTask<Bitmap, Void, String>{
private final ShareType type;
public SaveBitmapToDevice(ShareType type){
this.type = type;
}
@Override
protected String doInBackground(Bitmap... cards) {
return insertImageIntoGallery(getContentResolver(), cards[0], getString(R.string.card_gallery_title),
getString(R.string.card_gallery_label));
}
/**
* 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(android.content.ContentResolver, Bitmap, String, String).
* If the MediaStore not available, we will redirect the file to our alternative source, the SD card.
*/
public String insertImageIntoGallery(ContentResolver cr, Bitmap source, String title, String description) {
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.TITLE, title);
values.put(MediaStore.Images.Media.DISPLAY_NAME, title);
values.put(MediaStore.Images.Media.DESCRIPTION, description);
values.put(MediaStore.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(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis());
values.put(MediaStore.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 = MediaStore.Images.Thumbnails.getThumbnail(cr, id, MediaStore.Images.Thumbnails.MINI_KIND, null);
// This is for backward compatibility.
storeThumbnail(cr, miniThumb, id, 50F, 50F, MediaStore.Images.Thumbnails.MICRO_KIND);
} else {
cr.delete(url, null, null);
return storeToAlternateSd(source, title);
// url = null;
}
} catch (Exception e) {
if (url != null) {
cr.delete(url, null, null);
return storeToAlternateSd(source, title);
// url = null;
}
}
savedOnSD = false;
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 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(MediaStore.Images.Thumbnails.KIND,kind);
values.put(MediaStore.Images.Thumbnails.IMAGE_ID,(int)id);
values.put(MediaStore.Images.Thumbnails.HEIGHT,thumb.getHeight());
values.put(MediaStore.Images.Thumbnails.WIDTH,thumb.getWidth());
Uri url = cr.insert(MediaStore.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) {
Log.e("IMAGE_COMPRESSION_ERROR", "File not found");
ex.printStackTrace();
return null;
} catch (IOException ex) {
Log.e("IMAGE_COMPRESSION_ERROR", "IO Exception");
ex.printStackTrace();
return null;
}
}
/**
* If we have issues saving into our MediaStore, save it directly to our SD card. We can then interact with this file
* directly, opposed to pulling from the MediaStore. Again, this is a backup method if things don't work out as we
* would expect (seeing as most devices will have a MediaStore).
*
* @param src
* @param title
* @return - the file's path
*/
private String storeToAlternateSd(Bitmap src, String title){
if(src == null)
return null;
File sdCardDirectory = new File(Environment.getExternalStorageDirectory() + File.separator + "My Cards");
if(!sdCardDirectory.exists())
sdCardDirectory.mkdir();
SimpleDateFormat sdf = new SimpleDateFormat("MM-dd-yyyy - (hh.mm.a)", Locale.US);
File image = new File(sdCardDirectory, title + " -- [" + sdf.format(new Date()) + "].jpg");
try {
FileOutputStream imageOut = new FileOutputStream(image);
src.compress(Bitmap.CompressFormat.JPEG, 100, imageOut);
imageOut.close();
savedOnSD = true;
return image.getAbsolutePath();
} catch (FileNotFoundException ex) {
ex.printStackTrace();
return null;
} catch (IOException ex) {
ex.printStackTrace();
return null;
}
}
@Override
public void onPostExecute(String url){
if(url != null){
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
if(savedOnSD){
File file = new File(url);
if(file.exists())
intent.setDataAndType(Uri.fromFile(file), "image/jpeg");
else
return;
}
else
intent.setDataAndType(Uri.parse(url), "image/jpeg");
ActivityA.this.startActivity(intent);
}
else
Toast.makeText(ActivityA.this, getString(R.string.error_compressing), Toast.LENGTH_SHORT).show();
}
}