android - enregistrer l'image dans la galerie

91

J'ai une application avec une galerie d'images et je veux que l'utilisateur puisse l'enregistrer dans sa propre galerie. J'ai créé un menu d'options avec une seule voix "enregistrer" pour permettre cela, mais le problème est ... comment puis-je enregistrer l'image dans la galerie?

c'est mon 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);
            }
        }

je ne suis pas sûr de cette partie du code:

File root = Environment.getExternalStorageDirectory();
                File file = new File(root.getAbsolutePath()+"/DCIM/Camera/img.jpg");

est-il correct d'enregistrer dans la galerie? malheureusement le code ne fonctionne pas :(

Christian Giupponi
la source
Avez-vous résolu ce problème ? pouvez-vous s'il vous plaît partager avec moi
user3233280
J'ai aussi le même problème stackoverflow.com/questions/21951558/…
user3233280
Pour ceux d'entre vous qui rencontrent encore des problèmes pour enregistrer le fichier, cela peut être dû au fait que votre URL contient des caractères illégaux tels que "?", ":" Et "-" Supprimez-les et cela devrait fonctionner. Il s'agit d'une erreur courante dans les appareils étrangers et les émulateurs Android. Pour en savoir plus, cliquez ici: stackoverflow.com/questions/11394616/…
ChallengeAccepted
La réponse acceptée est un peu dépassée en 2019. J'ai écrit une réponse mise à jour ici: stackoverflow.com/questions/36624756/...
Bao Lei

Réponses:

168
MediaStore.Images.Media.insertImage(getContentResolver(), yourBitmap, yourTitle , yourDescription);

L'ancien code ajoutera l'image à la fin de la galerie. Si vous souhaitez modifier la date pour qu'elle apparaisse au début ou toute autre métadonnée, voir le code ci-dessous (Cortesy of SK, 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;
        }
    }
}
sfratini
la source
22
Cela enregistre l'image, mais à la fin de la galerie, lorsque vous prenez une photo avec un appareil photo, elle est enregistrée en haut. Comment puis-je enregistrer l'image en haut de la galerie?
eric.itzhak
19
Notez que vous devez également ajouter <uses-permission android: name = "android.permission.WRITE_EXTERNAL_STORAGE" /> à votre manifext.xml.
Kyle Clegg
3
Les images ne sont pas enregistrées en haut de la galerie car insertImage en interne n'ajoute aucune métadonnée de date. S'il vous plaît voir ce GIST: gist.github.com/0242ba81d7ca00b475b9.git c'est une copie exacte de la méthode insertImage mais il ajoute la date méta date pour s'assurer que l'image est ajoutée à l'avant de la galerie.
S-K '18
1
@ S-K'Je ne peux pas accéder à cette URL. Veuillez le mettre à jour et je mettrai à jour ma réponse afin qu'elle ait les deux options. Cheers
sfratini
6
Voici le lien GIST correct mentionné ci-dessus (nécessaire pour supprimer le .gità la fin)
minipif
48

En fait, vous pouvez enregistrer votre image à tout endroit. Si vous souhaitez enregistrer dans un espace public, afin que toute autre application puisse y accéder, utilisez ce code:

storageDir = new File(
    Environment.getExternalStoragePublicDirectory(
        Environment.DIRECTORY_PICTURES
    ), 
    getAlbumName()
);

La photo ne va pas dans l'album. Pour ce faire, vous devez appeler un 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);
}

Vous pouvez trouver plus d'informations sur https://developer.android.com/training/camera/photobasics.html#TaskGallery

Sigrist
la source
1
C'est une solution simple et agréable car nous n'avons pas besoin de modifier l'ensemble de l'implémentation et que nous pouvons créer un dossier personnalisé pour les applications.
Hugo Gresse
2
L'envoi d'une diffusion peut être un gaspillage de ressources lorsque vous ne pouvez analyser qu'un fichier: stackoverflow.com/a/5814533/43051 .
Jérémy Reynaud
2
Où passez-vous réellement le bitmap?
Daniel Reyhanian
22

J'ai essayé beaucoup de choses pour que cela fonctionne sur Marshmallow et Lollipop. Enfin, j'ai fini par déplacer l'image enregistrée dans le dossier DCIM (la nouvelle application Google Photo scanne les images uniquement si elles se trouvent apparemment dans ce dossier)

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;
}

Et puis le code standard pour la numérisation des fichiers que vous pouvez également trouver sur le site Google Developers .

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);
}

N'oubliez pas que ce dossier ne peut pas être présent dans tous les appareils du monde et qu'à partir de Marshmallow (API 23), vous devez demander l'autorisation de WRITE_EXTERNAL_STORAGE à l'utilisateur.

MatPag
la source
1
Merci pour les informations concernant Google Photos.
Jérémy Reynaud le
1
C'est la seule et unique solution qui explique bien. Personne d'autre n'a mentionné que le fichier doit être dans le dossier DCIM. Je vous remercie!!!
Predrag Manojlovic
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)a fait l'affaire pour moi. Merci!
saltandpepper
2
getExternalStoragePublicDirectory()est maintenant obsolète sur l'API 29. Besoin d'utiliser MediaStore
riggaroo
@riggaroo Oui vous avez raison Rebecca, je
mettrai à
13

Selon ce cours , la bonne façon de procéder est:

Environment.getExternalStoragePublicDirectory(
        Environment.DIRECTORY_PICTURES
    )

Cela vous donnera le chemin racine du répertoire de la galerie.

Cédric Julien
la source
J'ai essayé ce nouveau code mais il a planté java.lang.NoSuchFieldError: android.os.Environment.DIRECTORY_PICTURES
Christian Giupponi
ok merci, il n'y a donc aucun moyen de mettre une image sur la galerie avec android <2.2?
Christian Giupponi
Parfait - un lien directement vers le site Web des développeurs Android. Cela a fonctionné et était une solution simple.
Phil
1
Bonne réponse, mais ce serait mieux avec l'ajout de la méthode "galleryAddPic" à partir des autres réponses ici, car vous voudrez généralement que l'application Galerie remarque de nouvelles images.
Andrew Koster
11
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);
}
nitine Sol
la source
6

Vous pouvez créer un répertoire dans le dossier de l'appareil photo et enregistrer l'image. Après cela, vous pouvez simplement effectuer votre analyse. Il montrera instantanément votre image dans la galerie.

String root = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).toString()+ "/Camera/Your_Directory_Name";
File myDir = new File(root);
myDir.mkdirs();
String fname = "Image-" + image_name + ".png";
File file = new File(myDir, fname);
System.out.println(file.getAbsolutePath());
if (file.exists()) file.delete();
    Log.i("LOAD", root + fname);
    try {
        FileOutputStream out = new FileOutputStream(file);
        finalBitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
        out.flush();
        out.close();
    } catch (Exception e) {
       e.printStackTrace();
    }

MediaScannerConnection.scanFile(context, new String[]{file.getPath()}, new String[]{"image/jpeg"}, null);
javatar
la source
dans ce critère c'est la meilleure réponse
Noor Hossain
1

Je viens ici avec le même doute mais pour Xamarin pour Android, j'ai utilisé la réponse Sigrist pour faire cette méthode après avoir enregistré mon fichier:

private void UpdateGallery()
{
    Intent mediaScanIntent = new Intent(Intent.ActionMediaScannerScanFile);
    Java.IO.File file = new Java.IO.File(_path);
    Android.Net.Uri contentUri = Android.Net.Uri.FromFile(file);
    mediaScanIntent.SetData(contentUri);
    Application.Context.SendBroadcast(mediaScanIntent);
} 

et cela a résolu mon problème, Thx Sigrist. Je l'ai mis ici car je n'ai pas trouvé de réponse à ce sujet pour Xamarin et j'espère que cela pourra aider d'autres personnes.

Lattes
la source
1

Dans mon cas, les solutions ci-dessus n'ont pas fonctionné, j'ai dû faire ce qui suit:

sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(f)));
dc10
la source
c'est vraiment bon de savoir sur cette option, mais malheureusement ne fonctionne pas sur certains appareils avec Android 6, donc une ContentProvidersolution préférable
Siarhei
0
 String filePath="/storage/emulated/0/DCIM"+app_name;
    File dir=new File(filePath);
    if(!dir.exists()){
        dir.mkdir();
    }

Ce code est dans la méthode onCreate. Ce code est pour créer un répertoire de nom_app. Maintenant, ce répertoire est accessible à l'aide de l'application de gestionnaire de fichiers par défaut dans Android. Utilisez cette chaîne filePath partout où cela est nécessaire pour définir votre dossier de destination. Je suis sûr que cette méthode fonctionne également sur Android 7 parce que j'ai testé dessus.Par conséquent, elle peut également fonctionner sur d'autres versions d'Android.

Bhavik Mehta
la source