android - save image into gallery

220,258

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);
}
Share:
220,258

Related videos on Youtube

Christian Giupponi
Author by

Christian Giupponi

Updated on January 12, 2022

Comments

  • Christian Giupponi
    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
      user3233280 over 10 years
      have you resolved this issue ? can u please share with me
    • user3233280
      user3233280 over 10 years
      i am also having same problem stackoverflow.com/questions/21951558/…
    • ChallengeAccepted
      ChallengeAccepted over 9 years
      For 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
      Bao Lei almost 5 years
      The accepted answer is a little outdated in 2019. I have written an updated answer here: stackoverflow.com/questions/36624756/…
  • Christian Giupponi
    Christian Giupponi over 12 years
    i tried this new code but it crashed java.lang.NoSuchFieldError: android.os.Environment.DIRECTORY_PICTURES
  • Christian Giupponi
    Christian Giupponi over 12 years
    ok thanks, so there is no way to put an image on the gallery with android < 2.2?
  • eric.itzhak
    eric.itzhak about 12 years
    This 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
    Phil almost 12 years
    Perfect - a link directly to the Android Developer website. This worked and was a simple solution.
  • Kyle Clegg
    Kyle Clegg over 11 years
    Note that your must also add <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> to your manifext.xml.
  • S-K'
    S-K' about 10 years
    Images 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
    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
    minipif almost 10 years
    Here is the correct GIST link mentioned above (needed to remove the .git at the end)
  • ShadowGod
    ShadowGod about 9 years
    You just need to remember to add the DATE_TAKEN to the values in order for it to show up on top
  • Hugo Gresse
    Hugo Gresse over 8 years
    This 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
    Jérémy Reynaud over 8 years
    Thanks for the information concerning Google Photos.
  • Jérémy Reynaud
    Jérémy Reynaud over 8 years
    Sending a broadcast may be a waste of resource when you can scan only a file: stackoverflow.com/a/5814533/43051.
  • Predrag Manojlovic
    Predrag Manojlovic almost 8 years
    This is one and only solution explaining well. Nobody else mentioned that file must be in DCIM folder. Thank you!!!
  • snachmsm
    snachmsm over 7 years
    I 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
    Siarhei about 7 years
    its's really good to know about this option, but unfortunately not works on some devices with android 6, so ContentProvider preferable solytion
  • saltandpepper
    saltandpepper over 6 years
    Environment.getExternalStoragePublicDirectory(Environment.DI‌​RECTORY_DCIM) did the trick for me. Thanks!
  • Andrew Koster
    Andrew Koster over 5 years
    Good 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
    Kopi Bryant over 5 years
    How to change the file folder name?
  • Daniel Reyhanian
    Daniel Reyhanian about 5 years
    Where do you actually pass the bitmap?
  • riggaroo
    riggaroo almost 5 years
    getExternalStoragePublicDirectory() is now deprecated on API 29. Need to use MediaStore
  • MatPag
    MatPag almost 5 years
    @riggaroo Yes you are right Rebecca, i will update the answer ASAP
  • Noor Hossain
    Noor Hossain over 4 years
    in this criteria this is the best answer
  • Michael Abyzov
    Michael Abyzov over 3 years
    Environment.getExternalStoragePublicDirectory and Intent.ACTION_MEDIA_SCANNER_SCAN_FILE are deprecated now...
  • Michael Abyzov
    Michael Abyzov over 3 years
    Environment.getExternalStoragePublicDirectory is already deprecated...
  • Michael Abyzov
    Michael Abyzov over 3 years
    MediaStore.Images.Media.insertImage(...) is already deprecated.
  • Michael Paccione
    Michael Paccione about 3 years
    Where is finalBitmap initialized in your code... it is missing in the example
  • javatar
    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
    Hank Chan about 3 years
    As of 2021, this is the only answer that works!
  • Hank Chan
    Hank Chan about 3 years
    DCIM 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
    MosesK almost 2 years
    Nice, 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().