android - Bild in Galerie speichern


90

Ich habe eine App mit einer Bildergalerie und möchte, dass der Benutzer sie in seiner eigenen Galerie speichern kann. Ich habe ein Optionsmenü mit einer einzigen Stimme "Speichern" erstellt, um dies zu ermöglichen, aber das Problem ist ... wie kann ich das Bild in der Galerie speichern?

Das ist mein 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);
            }
        }

Ich bin mir dieses Teils des Codes nicht sicher:

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

Ist es richtig, in der Galerie zu speichern? Leider funktioniert der Code nicht :(


Haben Sie dieses Problem behoben?
Kannst

Ich habe auch das gleiche Problem stackoverflow.com/questions/21951558/…
user3233280

Für diejenigen unter Ihnen, die immer noch Probleme beim Speichern der Datei haben, kann dies daran liegen, dass Ihre URL unzulässige Zeichen wie "?", ":" Und "-" enthält. Entfernen Sie diese und es sollte funktionieren. Dies ist ein häufiger Fehler bei fremden Geräten und den Android-Emulatoren. Weitere Informationen finden
ChallengeAccepted

Die akzeptierte Antwort ist im Jahr 2019 etwas veraltet. Ich habe hier eine aktualisierte Antwort geschrieben: stackoverflow.com/questions/36624756/…
Bao Lei

Antworten:


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

Der vorherige Code fügt das Bild am Ende der Galerie hinzu. Wenn Sie das Datum so ändern möchten, dass es am Anfang oder in anderen Metadaten angezeigt wird, lesen Sie den folgenden Code (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;
        }
    }
}

22
Dadurch wird das Bild gespeichert, aber bis zum Ende der Galerie wird es oben gespeichert, wenn Sie ein Bild mit der Kamera aufnehmen. Wie kann ich das Bild oben in der Galerie speichern?
Eric.itzhak

19
Beachten Sie, dass Sie Ihrer manifext.xml auch <using-allow android: name = "android.permission.WRITE_EXTERNAL_STORAGE" /> hinzufügen müssen.
Kyle Clegg

3
Bilder werden nicht oben in der Galerie gespeichert, da intern insertImage keine Datums-Metadaten hinzufügt. Bitte beachten Sie diese GIST: gist.github.com/0242ba81d7ca00b475b9.git Es handelt sich um eine exakte Kopie der insertImage-Methode, es wird jedoch das Datums-Metadatum hinzugefügt, um sicherzustellen, dass das Bild vorne in der Galerie hinzugefügt wird.
S-K

1
@ S-K'Ich kann nicht auf diese URL zugreifen. Bitte aktualisieren Sie es und ich werde meine Antwort aktualisieren, damit es beide Optionen gibt. Prost
sfratini

6
Hier ist der korrekte GIST-Link, der oben erwähnt wurde (erforderlich, um den .gitam Ende zu entfernen )
Minipif

47

Eigentlich können Sie Ihr Bild an jedem Ort speichern. Wenn Sie in einem öffentlichen Raum speichern möchten, damit jede andere Anwendung darauf zugreifen kann, verwenden Sie diesen Code:

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

Das Bild geht nicht zum Album. Dazu müssen Sie einen Scan aufrufen:

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

Weitere Informationen finden Sie unter https://developer.android.com/training/camera/photobasics.html#TaskGallery


1
Dies ist eine nette, einfache Lösung, da wir nicht die gesamte Implementierung ändern müssen und einen benutzerdefinierten Ordner für die Apps erstellen können.
Hugo Gresse

2
Das Senden einer Sendung kann eine Ressourcenverschwendung sein, wenn Sie nur eine Datei scannen können: stackoverflow.com/a/5814533/43051 .
Jérémy Reynaud

Wo geben Sie die Bitmap tatsächlich weiter?
Daniel Reyhanian

20

Ich habe viele Dinge versucht, damit dies auf Marshmallow und Lollipop funktioniert. Schließlich habe ich das gespeicherte Bild in den DCIM-Ordner verschoben (neue Google Photo App scannt Bilder nur, wenn sie sich anscheinend in diesem Ordner befinden).

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

Und dann der Standardcode zum Scannen von Dateien, den Sie auch auf der Google Developers-Website finden .

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

Bitte denken Sie daran, dass dieser Ordner nicht auf jedem Gerät der Welt vorhanden sein kann und dass Sie ab Marshmallow (API 23) die Berechtigung für WRITE_EXTERNAL_STORAGE beim Benutzer anfordern müssen.


1
Vielen Dank für die Informationen zu Google Fotos.
Jérémy Reynaud

1
Dies ist die einzige Lösung, die sich gut erklären lässt. Niemand sonst erwähnte, dass sich die Datei im DCIM-Ordner befinden muss. Danke dir!!!
Predrag Manojlovic

Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)hat den Trick für mich gemacht. Vielen Dank!
Saltandpepper

2
getExternalStoragePublicDirectory()ist jetzt auf API 29 veraltet. Müssen MediaStore
riggaroo

@riggaroo Ja, Sie haben Recht Rebecca, ich werde die Antwort so schnell wie
möglich

12

Nach diesem Kurs ist der richtige Weg, dies zu tun:

Environment.getExternalStoragePublicDirectory(
        Environment.DIRECTORY_PICTURES
    )

Dadurch erhalten Sie den Stammpfad für das Galerieverzeichnis.


Ich habe diesen neuen Code ausprobiert, aber er ist abgestürzt. java.lang.NoSuchFieldError: android.os.Environment.DIRECTORY_PICTURES
Christian Giupponi

ok danke, also gibt es keine möglichkeit ein bild mit android <2.2 in die galerie zu setzen?
Christian Giupponi

Perfekt - ein Link direkt zur Android Developer-Website. Dies funktionierte und war eine einfache Lösung.
Phil

1
Gute Antwort, aber es wäre besser, wenn Sie die "galleryAddPic" -Methode aus den anderen Antworten hier hinzufügen, da Sie normalerweise möchten, dass die Galerie-App neue Bilder bemerkt.
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);
}

6

Sie können ein Verzeichnis im Kameraordner erstellen und das Bild speichern. Danach können Sie einfach Ihren Scan durchführen. Ihr Bild wird sofort in der Galerie angezeigt.

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

In diesem Kriterium ist dies die beste Antwort
Noor Hossain

1

Ich komme mit dem gleichen Zweifel hierher, aber für Xamarin für Android habe ich die Sigrist-Antwort verwendet, um diese Methode nach dem Speichern meiner Datei auszuführen:

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

und es hat mein Problem gelöst, Thx Sigrist. Ich habe es hierher gebracht, weil ich keine Antwort für Xamarin gefunden habe und ich hoffe, dass es anderen Menschen helfen kann.


1

In meinem Fall haben die oben genannten Lösungen nicht funktioniert. Ich musste Folgendes tun:

sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(f)));

Es ist wirklich gut, über diese Option Bescheid zu wissen, funktioniert aber leider nicht auf einigen Geräten mit Android 6, daher ContentProvidervorzuziehende Lösung
Siarhei

0
 String filePath="/storage/emulated/0/DCIM"+app_name;
    File dir=new File(filePath);
    if(!dir.exists()){
        dir.mkdir();
    }

Dieser Code befindet sich in der onCreate-Methode. Dieser Code dient zum Erstellen eines Verzeichnisses mit dem Namen app_name. Jetzt kann auf dieses Verzeichnis mit der Standard-Dateimanager-App in Android zugegriffen werden. Verwenden Sie diese Zeichenfolge filePath, wo immer dies erforderlich ist, um Ihren Zielordner festzulegen. Ich bin sicher, dass diese Methode auch auf Android 7 funktioniert, da ich sie getestet habe. Daher kann sie auch auf anderen Android-Versionen funktionieren.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.