android - simpan gambar ke galeri

94

Saya memiliki aplikasi dengan galeri gambar dan saya ingin pengguna dapat menyimpannya ke galerinya sendiri. Saya telah membuat menu opsi dengan satu suara "simpan" untuk mengizinkannya, tetapi masalahnya adalah ... bagaimana cara menyimpan gambar ke galeri?

ini kode saya:

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

saya tidak yakin dengan bagian kode ini:

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

apakah benar menyimpan ke galeri? sayangnya kodenya tidak berfungsi :(

Christian Giupponi
sumber
sudahkah anda menyelesaikan masalah ini? bisakah kamu berbagi dengan saya
pengguna3233280
saya juga mengalami masalah yang sama stackoverflow.com/questions/21951558/…
user3233280
Bagi Anda yang masih mengalami masalah dalam menyimpan file, mungkin karena url Anda berisi karakter ilegal seperti "?", ":", Dan "-" Hapus itu dan seharusnya berfungsi. Ini adalah kesalahan umum di perangkat asing dan emulator android. Lihat lebih lanjut di sini: stackoverflow.com/questions/11394616/…
ChallengeAccepted
Jawaban yang diterima agak ketinggalan jaman pada tahun 2019. Saya telah menulis jawaban yang diperbarui di sini: stackoverflow.com/questions/36624756/…
Bao Lei

Jawaban:

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

Kode sebelumnya akan menambahkan gambar di akhir galeri. Jika Anda ingin mengubah tanggal agar muncul di awal atau metadata lainnya, lihat kode di bawah ini (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.dll
sumber
23
Ini menyimpan gambar, tetapi ke akhir galeri meskipun ketika Anda mengambil gambar dengan kamera, itu disimpan di atas. Bagaimana cara menyimpan gambar ke atas galeri?
eric.itzhak
19
Perhatikan bahwa Anda juga harus menambahkan <using-permission android: name = "android.permission.WRITE_EXTERNAL_STORAGE" /> ke manifext.xml Anda.
Kyle Clegg
3
Gambar tidak disimpan di bagian atas galeri karena secara internal insertImage tidak menambahkan data meta tanggal apa pun. Silakan lihat GIST ini: gist.github.com/0242ba81d7ca00b475b9.git ini adalah salinan persis dari metode insertImage tetapi menambahkan tanggal meta tanggal untuk memastikan gambar ditambahkan di depan galeri.
S-K '
6
Berikut adalah tautan GIST yang benar yang disebutkan di atas (diperlukan untuk menghapus .gitdi bagian akhir)
minipif
2
Bagaimana cara mengubah nama folder file?
Kopi Bryant
48

Sebenarnya, Anda dapat menyimpan gambar Anda di sembarang tempat. Jika Anda ingin menyimpan di ruang publik, agar aplikasi lain dapat mengakses, gunakan kode ini:

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

Gambar tidak masuk ke album. Untuk melakukan ini, Anda perlu memanggil 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);
}

Anda dapat menemukan info lebih lanjut di https://developer.android.com/training/camera/photobasics.html#TaskGallery

Sigrist
sumber
1
Ini adalah solusi sederhana yang bagus karena kami tidak perlu mengubah seluruh implementasi dan kami dapat membuat folder khusus untuk aplikasi.
Hugo Gresse
2
Mengirim siaran mungkin membuang-buang sumber daya jika Anda hanya dapat memindai file: stackoverflow.com/a/5814533/43051 .
Jérémy Reynaud
2
Di mana sebenarnya Anda meneruskan bitmap?
Daniel Reyhanian
Environment.getExternalStoragePublicDirectorydan Intent.ACTION_MEDIA_SCANNER_SCAN_FILEtidak digunakan lagi sekarang ...
Michael Abyzov
22

Saya sudah mencoba banyak hal agar ini berfungsi di Marshmallow dan Lollipop. Akhirnya saya akhirnya memindahkan gambar yang disimpan ke folder DCIM (aplikasi Google Photo baru memindai gambar hanya jika ada di dalam folder ini)

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

Dan kemudian kode standar untuk memindai file yang dapat Anda temukan di situs Google Developers juga .

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

Harap diingat bahwa folder ini tidak dapat hadir di setiap perangkat di dunia dan mulai dari Marshmallow (API 23), Anda perlu meminta izin ke WRITE_EXTERNAL_STORAGE kepada pengguna.

MatPag
sumber
1
Terima kasih atas informasi tentang Foto Google.
Jérémy Reynaud
1
Ini adalah satu-satunya solusi yang menjelaskan dengan baik. Tidak ada orang lain yang menyebutkan bahwa file tersebut harus ada di folder DCIM. Terima kasih!!!
Predrag Manojlovic
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)melakukan trik untuk saya. Terima kasih!
saltandpepper
2
getExternalStoragePublicDirectory()sekarang tidak digunakan lagi di API 29. Perlu menggunakan MediaStore
riggaroo
@riggaroo Ya, Anda benar Rebecca, saya akan memperbarui jawabannya ASAP
MatPag
13

Menurut kursus ini , cara yang benar untuk melakukannya adalah:

Environment.getExternalStoragePublicDirectory(
        Environment.DIRECTORY_PICTURES
    )

Ini akan memberi Anda jalur root untuk direktori galeri.

Cédric Julien
sumber
saya mencoba kode baru ini tetapi gagal java.lang.NoSuchFieldError: android.os.Environment.DIRECTORY_PICTURES
Christian Giupponi
ok terima kasih, jadi tidak ada cara untuk meletakkan gambar di galeri dengan android <2.2?
Christian Giupponi
Sempurna - tautan langsung ke situs web Pengembang Android. Ini berhasil dan merupakan solusi sederhana.
Phil
1
Jawaban bagus, tapi akan lebih baik dengan penambahan metode "galleryAddPic" dari jawaban lain di sini, karena Anda biasanya ingin aplikasi Galeri melihat gambar baru.
Andrew Koster
Environment.getExternalStoragePublicDirectorysudah tidak digunakan lagi ...
Michael Abyzov
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
sumber
6

Anda dapat membuat direktori di dalam folder kamera dan menyimpan gambarnya. Setelah itu, Anda cukup melakukan pemindaian. Ini akan langsung menampilkan gambar Anda di galeri.

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
sumber
dalam kriteria ini ini adalah jawaban terbaik
Noor Hossain
1

Saya datang ke sini dengan keraguan yang sama tetapi untuk Xamarin untuk Android, saya telah menggunakan jawaban Sigrist untuk melakukan metode ini setelah menyimpan file saya:

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

dan itu memecahkan masalah saya, Thx Sigrist. Saya taruh di sini karena saya tidak menemukan jawaban tentang ini untuk Xamarin dan saya berharap ini dapat membantu orang lain.

Slater
sumber
1

Dalam kasus saya, solusi di atas tidak berhasil, saya harus melakukan hal berikut:

sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(f)));
dc10
sumber
sangat baik untuk mengetahui tentang opsi ini, tetapi sayangnya tidak berfungsi pada beberapa perangkat dengan Android 6, ContentProvidersolusi yang lebih disukai
Siarhei
0
 String filePath="/storage/emulated/0/DCIM"+app_name;
    File dir=new File(filePath);
    if(!dir.exists()){
        dir.mkdir();
    }

Kode ini ada dalam metode onCreate. Kode ini untuk membuat direktori app_name. Sekarang, direktori ini dapat diakses menggunakan aplikasi file manager default di android. Gunakan filePath string ini jika diperlukan untuk menyetel folder tujuan Anda. Saya yakin metode ini juga berfungsi di Android 7 karena saya telah mengujinya, sehingga dapat berfungsi di versi Android lain juga.

Bhavik Mehta
sumber