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 :(

Christian Giupponi
quelle
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;
        }
    }
}
sfratini
quelle
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

Sigrist
quelle
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.

MatPag
quelle
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.

Cédric Julien
quelle
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);
}
Nitin Sol
quelle
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);
Javatar
quelle
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.

Slaters
quelle
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)));
dc10
quelle
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.

Bhavik Mehta
quelle