android - resmi galeriye kaydet


94

Resim galerisi olan bir uygulamam var ve kullanıcının bunu kendi galerisine kaydetmesini istiyorum. Buna izin vermek için tek bir sesle "kaydetme" seçeneği olan bir seçenek menüsü oluşturdum, ancak sorun şu ki ... resmi galeriye nasıl kaydedebilirim?

bu benim kodum:

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

kodun bu kısmından emin değilim:

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

galeriye kaydetmek doğru mu? maalesef kod çalışmıyor :(


bu sorunu çözdün mü? lütfen benimle paylaşabilir misin
user3233280

Ben de aynı problemi yaşıyorum stackoverflow.com/questions/21951558/…
user3233280

Dosyayı kaydetmede hala sorun yaşayanlarınız için, bunun nedeni url'nizin "?", ":" Ve "-" gibi geçersiz karakterler içermesi olabilir ve bunları kaldırın. Bu, yabancı cihazlarda ve android emülatörlerinde yaygın bir hatadır. Bununla ilgili daha fazla bilgiyi burada bulabilirsiniz: stackoverflow.com/questions/11394616/…
Meydan Okuma

Kabul edilen cevap 2019'da biraz modası geçmiş. Burada güncellenmiş bir cevap yazdım: stackoverflow.com/questions/36624756/…
Bao Lei

Yanıtlar:


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

Eski kod, resmi galerinin sonuna ekleyecektir. Tarihi, başlangıçta veya başka herhangi bir meta veride görünecek şekilde değiştirmek istiyorsanız, aşağıdaki koda bakın (SK Cortesy , 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;
        }
    }
}

24
Bu görüntüyü kaydeder, ancak galerinin sonuna kadar kamera ile bir fotoğraf çektiğinizde üstte kaydeder. Resmi galerinin üstüne nasıl kaydedebilirim?
eric.itzhak

19
Ayrıca manifext.xml dosyanıza <uses-allow android: name = "android.permission.WRITE_EXTERNAL_STORAGE" /> eklemeniz gerektiğini unutmayın.
Kyle Clegg

3
Dahili olarak insertImage herhangi bir tarih meta verisi eklemediğinden, resimler galerinin üst kısmına kaydedilmez. Lütfen bu GIST'e bakın: gist.github.com/0242ba81d7ca00b475b9.git bu insertImage yönteminin tam bir kopyasıdır, ancak resmin galerinin önüne eklendiğinden emin olmak için tarih meta tarihini ekler.
S-K '

6
İşte yukarıda belirtilen doğru GIST bağlantısı ( .gitsonunda kaldırmak için gerekli )
minipif

2
Dosya klasörü adı nasıl değiştirilir?
Kopi Bryant

49

Aslında, resminizi herhangi bir yerde kaydedebilirsiniz. Başka herhangi bir uygulamanın erişebilmesi için kamusal bir alana kaydetmek istiyorsanız, şu kodu kullanın:

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

Resim albüme gitmiyor. Bunu yapmak için bir tarama yapmanız gerekir:

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

Daha fazla bilgiyi https://developer.android.com/training/camera/photobasics.html#TaskGallery adresinde bulabilirsiniz.


1
Bu, tüm uygulamayı değiştirmemize gerek olmadığı ve uygulamalar için özel bir klasör oluşturabileceğimiz için güzel ve basit bir çözümdür.
Hugo Gresse

2
Yalnızca bir dosyayı tarayabildiğiniz zaman yayın göndermek kaynak israfı olabilir: stackoverflow.com/a/5814533/43051 .
Jérémy Reynaud

2
Bit eşlemi gerçekte nereden geçiriyorsunuz?
Daniel Reyhanian

1
Environment.getExternalStoragePublicDirectoryve Intent.ACTION_MEDIA_SCANNER_SCAN_FILEartık kullanımdan kaldırıldı ...
Michael Abyzov

22

Bunun Marshmallow ve Lollipop'ta çalışmasına izin vermek için pek çok şey denedim. Sonunda, kaydedilen resmi DCIM klasörüne taşımayı sonlandırdım (yeni Google Fotoğraf uygulaması, görüntüleri yalnızca bu klasörün içindeyse tarar)

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

Ve sonra, Google Developers sitesinde de bulabileceğiniz dosyaları taramak için standart kod .

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

Lütfen bu klasörün dünyadaki her cihazda bulunamayacağını ve Marshmallow'dan (API 23) başlayarak, kullanıcıya WRITE_EXTERNAL_STORAGE için izin istemeniz gerektiğini unutmayın.


1
Google Foto ile ilgili bilgiler için teşekkür ederiz.
Jérémy Reynaud

1
Bu, iyi açıklayan tek çözümdür. Dosyanın DCIM klasöründe olması gerektiğinden başka kimse bahsetmedi. Teşekkür ederim!!!
Predrag Manojlovic

Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)benim için hile yaptı. Teşekkürler!
saltandpepper

2
getExternalStoragePublicDirectory()artık API 29'da kullanımdan kaldırıldı. MediaStore'u kullanmanız gerekiyor
riggaroo

@riggaroo Evet haklısın Rebecca, cevabı en kısa sürede güncelleyeceğim
MatPag

13

Bu kursa göre, bunu yapmanın doğru yolu:

Environment.getExternalStoragePublicDirectory(
        Environment.DIRECTORY_PICTURES
    )

Bu size galeri dizininin kök yolunu verecektir.


bu yeni kodu denedim ama java.lang.NoSuchFieldError: android.os.Environment.DIRECTORY_PICTURES
Christian Giupponi

tamam teşekkürler, bu yüzden galeriye android <2.2 ile resim koymanın bir yolu yok mu?
Christian Giupponi

Mükemmel - doğrudan Android Geliştirici web sitesine bağlantı. Bu işe yaradı ve basit bir çözümdü.
Phil

1
Güzel yanıt, ancak buradaki diğer yanıtlardan "galleryAddPic" yönteminin eklenmesi daha iyi olur, çünkü genellikle Galeri uygulamasının yeni resimleri fark etmesini isteyeceksiniz.
Andrew Koster

Environment.getExternalStoragePublicDirectoryzaten kullanımdan kaldırıldı ...
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);
}

6

Kamera klasörünün içinde bir dizin oluşturabilir ve görüntüyü kaydedebilirsiniz. Bundan sonra, taramanızı kolayca gerçekleştirebilirsiniz. Resminizi anında galeride gösterecektir.

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

bu kriterde en iyi cevap bu
Noor Hossain

1

Buraya aynı şüpheyle geliyorum ancak Android için Xamarin için, dosyamı kaydettikten sonra bu yöntemi yapmak için Sigrist yanıtını kullandım:

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

ve sorunumu çözdü, Thx Sigrist. Xamarin için bununla ilgili bir answare bulamadığım için buraya koydum ve umarım diğer insanlara yardımcı olabilir.


1

Benim durumumda yukarıdaki çözümler işe yaramadı, aşağıdakileri yapmak zorunda kaldım:

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

Bu seçenek hakkında bilgi sahibi olmak gerçekten çok iyi, ancak maalesef android 6 ile bazı cihazlarda ContentProviderçalışmıyor , bu yüzden tercih edilen çözüm
Siarhei

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

Bu kod onCreate metodundadır.Bu kod app_name dizini oluşturmak içindir. Şimdi, bu dizine android'deki varsayılan dosya yöneticisi uygulaması kullanılarak erişilebilir. Hedef klasörünüzü ayarlamak için gereken her yerde bu filePath dizesini kullanın. Bu yöntemin Android 7'de de çalıştığına eminim çünkü üzerinde test ettim, bu nedenle android'in diğer sürümlerinde de çalışabilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.