Bagaimana cara memilih gambar dari galeri (Kartu SD) untuk aplikasi saya?

343

Pertanyaan ini awalnya ditanyakan untuk Android 1.6.

Saya sedang mengerjakan opsi foto di aplikasi saya.

Saya memiliki tombol dan ImageView di Aktivitas saya. Ketika saya mengklik tombol itu akan mengarahkan ulang ke galeri dan saya akan dapat memilih gambar. Gambar yang dipilih akan muncul di ImageView saya.

Praveen
sumber
1
lihat jawaban ini, saya memposting kode yang ditingkatkan di sana untuk menangani pilihan dari manajer file juga stackoverflow.com/questions/2169649/…
mad

Jawaban:

418

Jawaban yang diperbarui, hampir 5 tahun kemudian:

Kode dalam jawaban asli tidak lagi dapat diandalkan, karena gambar dari berbagai sumber terkadang kembali dengan URI konten yang berbeda, yaitu content://alih-alih file://. Solusi yang lebih baik adalah dengan hanya menggunakan context.getContentResolver().openInputStream(intent.getData()), karena itu akan mengembalikan InputStream yang dapat Anda tangani sesuai pilihan Anda.

Misalnya, BitmapFactory.decodeStream()berfungsi dengan baik dalam situasi ini, karena Anda juga dapat menggunakan bidang Options dan inSampleSize untuk memperkecil gambar besar dan menghindari masalah memori.

Namun, hal-hal seperti Google Drive mengembalikan URI ke gambar yang sebenarnya belum diunduh. Karenanya Anda perlu menjalankan kode getContentResolver () pada utas latar belakang.


Jawaban asli:

Jawaban lain menjelaskan cara mengirim maksud, tetapi mereka tidak menjelaskan dengan baik bagaimana menangani respons. Berikut ini beberapa contoh kode tentang cara melakukannya:

protected void onActivityResult(int requestCode, int resultCode, 
       Intent imageReturnedIntent) {
    super.onActivityResult(requestCode, resultCode, imageReturnedIntent); 

    switch(requestCode) { 
    case REQ_CODE_PICK_IMAGE:
        if(resultCode == RESULT_OK){  
            Uri selectedImage = imageReturnedIntent.getData();
            String[] filePathColumn = {MediaStore.Images.Media.DATA};

            Cursor cursor = getContentResolver().query(
                               selectedImage, filePathColumn, null, null, null);
            cursor.moveToFirst();

            int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
            String filePath = cursor.getString(columnIndex);
            cursor.close();


            Bitmap yourSelectedImage = BitmapFactory.decodeFile(filePath);
        }
    }
}

Setelah ini, Anda memiliki gambar yang dipilih disimpan di "yourSelectedImage" untuk melakukan apa pun yang Anda inginkan. Kode ini berfungsi dengan mendapatkan lokasi gambar di basis data ContentResolver, tetapi itu saja tidak cukup. Setiap gambar memiliki sekitar 18 kolom informasi, mulai dari filepath hingga 'tanggal terakhir dimodifikasi' hingga koordinat GPS tempat foto diambil, meskipun banyak bidang yang sebenarnya tidak digunakan.

Untuk menghemat waktu karena Anda sebenarnya tidak membutuhkan bidang lain, pencarian kursor dilakukan dengan filter. Filter bekerja dengan menentukan nama kolom yang Anda inginkan, MediaStore.Images.Media.DATA, yang merupakan path, dan kemudian memberikan string [] ke kueri kursor. Kueri kursor kembali dengan jalur, tetapi Anda tidak tahu di kolom mana itu sampai Anda menggunakan columnIndexkode. Itu hanya mendapatkan nomor kolom berdasarkan namanya, yang sama digunakan dalam proses penyaringan. Setelah Anda mendapatkannya, Anda akhirnya dapat mendekode gambar menjadi bitmap dengan baris kode terakhir yang saya berikan.

Steve Haley
sumber
4
cursor.moveToFirst () harus diperiksa keberadaannya: if (cursor.moveToFirst ()) {lakukan sesuatu dengan data kursor}
mishkin
14
Alih-alih kursor Anda harus mendapatkan gambar dengan cara ini: Bitmap b = MediaStore.Images.Media.getBitmap (this.getContentResolver (), selectedImage);
Luigi Agosti
4
Luigi, jika Bitmap adalah MediaStore.Images.Media.getBitmap () yang besar dapat menyebabkan pengecualian OutOfMemory. Metode Steve memungkinkan untuk memperkecil gambar sebelum memuatnya ke dalam memori.
Frank Harper
9
ini tidak berfungsi untuk saya, saya mendapatkan nol dari cursor.getString (columnIndex);
Alexis Pautrot
9
Hati-hati dengan metode ini: nama file akan 'nol' ketika pengguna memilih foto dari album picasa atau dari aplikasi Foto Google+.
Ciske Boekelo
315
private static final int SELECT_PHOTO = 100;

Mulai niat

Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
photoPickerIntent.setType("image/*");
startActivityForResult(photoPickerIntent, SELECT_PHOTO);    

Hasil proses

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent imageReturnedIntent) { 
    super.onActivityResult(requestCode, resultCode, imageReturnedIntent); 

    switch(requestCode) { 
    case SELECT_PHOTO:
        if(resultCode == RESULT_OK){  
            Uri selectedImage = imageReturnedIntent.getData();
            InputStream imageStream = getContentResolver().openInputStream(selectedImage);
            Bitmap yourSelectedImage = BitmapFactory.decodeStream(imageStream);
        }
    }
}

Atau, Anda juga dapat melakukan downsample gambar Anda untuk menghindari kesalahan OutOfMemory.

private Bitmap decodeUri(Uri selectedImage) throws FileNotFoundException {

        // Decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(getContentResolver().openInputStream(selectedImage), null, o);

        // The new size we want to scale to
        final int REQUIRED_SIZE = 140;

        // Find the correct scale value. It should be the power of 2.
        int width_tmp = o.outWidth, height_tmp = o.outHeight;
        int scale = 1;
        while (true) {
            if (width_tmp / 2 < REQUIRED_SIZE
               || height_tmp / 2 < REQUIRED_SIZE) {
                break;
            }
            width_tmp /= 2;
            height_tmp /= 2;
            scale *= 2;
        }

        // Decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
        return BitmapFactory.decodeStream(getContentResolver().openInputStream(selectedImage), null, o2);

    }
siamii
sumber
8
menempatkan jpeg 1,5MB ke 100px kecil saya dengan 100px imageview mengakibatkan VM keluar dari kesalahan memori. Downsampling memperbaiki masalah itu :-)
Seseorang di suatu tempat
1
Hai. Bukankah kedua aliran harus ditutup?
Denis Kniazhev
Hello @ siamii..I mengikuti kode Anda..tapi sebagian berfungsi untuk saya .. :( ketika gambar dipilih dari galeri di bawah bagian gambar yang diambil, maka itu memberikan kesalahan json, tetapi ketika gambar dipilih dari galeri di bawah bagian bluetooth gambar diakses dan dikirim ke server..bisakah Anda memeriksa tautan ini dan menyarankan saya solusi apa pun tolong ... stackoverflow.com/questions/29234409/image-is-not-uploaded
Prabs
Bagian tentang menemukan skala dapat ditulis sebagai:int scale = 1; for ( ; bfOptions.outWidth / scale > TARGET_SIZE && bfOptions.outWidth > TARGET_SIZE; scale*=2);
The_Rafi
@siamii Di mana dan bagaimana memanggil metode ini -------- decodeUri
Akshay Kumar
87

Anda harus memulai maksud galeri untuk hasilnya.

Intent i = new Intent(Intent.ACTION_PICK,
               android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(i, ACTIVITY_SELECT_IMAGE); 

Kemudian masuk onActivityForResult, panggil intent.getData()untuk mendapatkan Uri Gambar. Maka Anda perlu mendapatkan Gambar dari ContentProvider.

Robby Pond
sumber
Apa perbedaan antara ACTION_PICK dan ACTION_GET_CONTENT dalam dua jawaban lain?
penguin359
4
Dengan ACTION_PICK Anda menentukan URI tertentu dan dengan ACTION_GET_CONTENT Anda menentukan mime_type. Saya menggunakan ACTION_PICK karena pertanyaannya adalah gambar khusus dari SDCARD dan tidak semua gambar.
Robby Pond
2
Keren. Ini adalah persis apa yang saya butuhkan dan bekerja seperti pesona :) Bertanya-tanya dari mana kalian menemukan barang-barang ini :)
Jayshil Dave
@WilliamKinaan ACTIVITY_SELECT_IMAGE adalah nilai int apa pun yang Anda tentukan untuk mengidentifikasi hasil mana yang ingin Anda terima. Itu kemudian dikirim kembali di onActivityResult (int requestCode, int resultCode, Intent data) sebagai 'requestCode'.
Fydo
@ Fydo Saya menyadari itu nanti, Terima kasih
William Kinaan
22

Ini adalah kode yang diuji untuk gambar dan video.Ini akan bekerja untuk semua API kurang dari 19 dan lebih besar dari 19 juga.

Gambar:

if (Build.VERSION.SDK_INT <= 19) {
                        Intent i = new Intent();
                        i.setType("image/*");
                        i.setAction(Intent.ACTION_GET_CONTENT);
                        i.addCategory(Intent.CATEGORY_OPENABLE);
                        startActivityForResult(i, 10);
                    } else if (Build.VERSION.SDK_INT > 19) {
                        Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
                        startActivityForResult(intent, 10);
                    }

Video:

if (Build.VERSION.SDK_INT <= 19) {
                        Intent i = new Intent();
                        i.setType("video/*");
                        i.setAction(Intent.ACTION_GET_CONTENT);
                        i.addCategory(Intent.CATEGORY_OPENABLE);
                        startActivityForResult(i, 20);
                    } else if (Build.VERSION.SDK_INT > 19) {
                        Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Video.Media.EXTERNAL_CONTENT_URI);
                        startActivityForResult(intent, 20);
                    }    

.

     @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == Activity.RESULT_OK) {               
            if (requestCode == 10) {
                Uri selectedImageUri = data.getData();
                String selectedImagePath = getRealPathFromURI(selectedImageUri);
            } else if (requestCode == 20) {
                Uri selectedVideoUri = data.getData();
                String selectedVideoPath = getRealPathFromURI(selectedVideoUri);
            }
        }
     }

     public String getRealPathFromURI(Uri uri) {
            if (uri == null) {
                return null;
            }
            String[] projection = {MediaStore.Images.Media.DATA};
            Cursor cursor = getActivity().getContentResolver().query(uri, projection, null, null, null);
            if (cursor != null) {
                int column_index = cursor
                        .getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
                cursor.moveToFirst();
                return cursor.getString(column_index);
            }
            return uri.getPath();
        }
Muhammad Umair Shafique
sumber
14

Lakukan ini untuk meluncurkan galeri dan memungkinkan pengguna untuk memilih gambar:

Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent, IMAGE_PICK);

Kemudian dalam onActivityResult()penggunaan Anda URI dari gambar yang dikembalikan untuk mengatur gambar di ImageView Anda.

Mark B
sumber
3
Ini tidak akan bekerja untuk perangkat Android 4.4. Ini akan meluncurkan layar dokumen terbaru.
Noundla Sandeep
2
Ini adalah perbaikan untuk KitKat: stackoverflow.com/a/26690628/860488
Morten Holmgaard
11
public class EMView extends Activity {
ImageView img,img1;
int column_index;
  Intent intent=null;
// Declare our Views, so we can access them later
String logo,imagePath,Logo;
Cursor cursor;
//YOU CAN EDIT THIS TO WHATEVER YOU WANT
private static final int SELECT_PICTURE = 1;

 String selectedImagePath;
//ADDED
 String filemanagerstring;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    img= (ImageView)findViewById(R.id.gimg1);



    ((Button) findViewById(R.id.Button01))
    .setOnClickListener(new OnClickListener() {

        public void onClick(View arg0) {

            // in onCreate or any event where your want the user to
            // select a file
            Intent intent = new Intent();
            intent.setType("image/*");
            intent.setAction(Intent.ACTION_GET_CONTENT);
            startActivityForResult(Intent.createChooser(intent,
                    "Select Picture"), SELECT_PICTURE);


        }
    });
}

//UPDATED
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode == Activity.RESULT_OK) {
        if (requestCode == SELECT_PICTURE) {
            Uri selectedImageUri = data.getData();

            //OI FILE Manager
            filemanagerstring = selectedImageUri.getPath();

            //MEDIA GALLERY
            selectedImagePath = getPath(selectedImageUri);


            img.setImageURI(selectedImageUri);

           imagePath.getBytes();
           TextView txt = (TextView)findViewById(R.id.title);
           txt.setText(imagePath.toString());


           Bitmap bm = BitmapFactory.decodeFile(imagePath);

          // img1.setImageBitmap(bm);



        }

    }

}

//UPDATED!
public String getPath(Uri uri) {
String[] projection = { MediaColumns.DATA };
Cursor cursor = managedQuery(uri, projection, null, null, null);
column_index = cursor
        .getColumnIndexOrThrow(MediaColumns.DATA);
cursor.moveToFirst();
 imagePath = cursor.getString(column_index);

return cursor.getString(column_index);
}

}
Sheetal Lebih Banyak
sumber
8
public class BrowsePictureActivity extends Activity {
private static final int SELECT_PICTURE = 1;

private String selectedImagePath;

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    ((Button) findViewById(R.id.Button01))
            .setOnClickListener(new OnClickListener() {

                public void onClick(View arg0) {

                    Intent intent = new Intent();
                    intent.setType("image/*");
                    intent.setAction(Intent.ACTION_GET_CONTENT);
                    startActivityForResult(Intent.createChooser(intent,
                            "Select Picture"), SELECT_PICTURE);
                }
            });
}

public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode == RESULT_OK) {
        if (requestCode == SELECT_PICTURE) {
            Uri selectedImageUri = data.getData();
            selectedImagePath = getPath(selectedImageUri);
        }
    }
}

public String getPath(Uri uri) {

        if( uri == null ) {
            return null;
        }

        // this will only work for images selected from gallery
        String[] projection = { MediaStore.Images.Media.DATA };
        Cursor cursor = managedQuery(uri, projection, null, null, null);
        if( cursor != null ){
            int column_index = cursor
            .getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
            cursor.moveToFirst();
            return cursor.getString(column_index);
        }

        return uri.getPath();
}

}
Muhammad Usman Ghani
sumber
Ini adalah perbaikan untuk KitKat: stackoverflow.com/a/26690628/860488
Morten Holmgaard
4

Untuk beberapa alasan, semua jawaban di utas ini, di onActivityResult()coba untuk memposting proses yang diterima Uri, seperti mendapatkan jalur nyata gambar dan kemudian gunakan BitmapFactory.decodeFile(path)untuk mendapatkanBitmap .

Langkah ini tidak perlu. The ImageViewkelas memiliki metode yang disebut setImageURI(uri). Berikan uri Anda padanya dan Anda harus selesai.

Uri imageUri = data.getData();
imageView.setImageURI(imageUri);

Untuk contoh kerja yang lengkap, Anda dapat melihatnya di sini: http://androidbitmaps.blogspot.com/2015/04/loading-images-in-android-part-iii-pick.html

PS:
Mendapatkan Bitmapdalam variabel yang terpisah akan masuk akal dalam kasus-kasus di mana gambar yang akan dimuat terlalu besar untuk muat dalam memori, dan operasi penurunan skala diperlukan untuk mencegah OurOfMemoryError, seperti yang ditunjukkan dalam jawaban @siamii.

Andy Res
sumber
3

sebut metode selectImage seperti-

public void chooseImage(ImageView v)
{
    Intent intent = new Intent(Intent.ACTION_PICK);
    intent.setType("image/*");
    startActivityForResult(intent, SELECT_PHOTO);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent imageReturnedIntent) {
    // TODO Auto-generated method stub
    super.onActivityResult(requestCode, resultCode, imageReturnedIntent);

    if(imageReturnedIntent != null)
    {
        Uri selectedImage = imageReturnedIntent.getData();
    switch(requestCode) { 
    case SELECT_PHOTO:
        if(resultCode == RESULT_OK)
        {
            Bitmap datifoto = null;
            temp.setImageBitmap(null);
            Uri picUri = null;
            picUri = imageReturnedIntent.getData();//<- get Uri here from data intent
             if(picUri !=null){
               try {
                   datifoto = android.provider.MediaStore.Images.Media.getBitmap(this.getContentResolver(),                                 picUri);
                   temp.setImageBitmap(datifoto);
               } catch (FileNotFoundException e) {
                  throw new RuntimeException(e);
               } catch (IOException e) {
                  throw new RuntimeException(e);
               } catch (OutOfMemoryError e) {
                Toast.makeText(getBaseContext(), "Image is too large. choose other", Toast.LENGTH_LONG).show();
            }

        }
        }
        break;

}
    }
    else
    {
        //Toast.makeText(getBaseContext(), "data null", Toast.LENGTH_SHORT).show();
    }
}
Akshay Paliwal
sumber
1
#initialize in main activity 
    path = Environment.getExternalStorageDirectory()
            + "/images/make_machine_example.jpg"; #
     ImageView image=(ImageView)findViewById(R.id.image);
 //--------------------------------------------------||

 public void FromCamera(View) {

    Log.i("camera", "startCameraActivity()");
    File file = new File(path);
    Uri outputFileUri = Uri.fromFile(file);
    Intent intent = new Intent(
            android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
    startActivityForResult(intent, 1);

}

public void FromCard() {
    Intent i = new Intent(Intent.ACTION_PICK,
            android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    startActivityForResult(i, 2);
}

 protected void onActivityResult(int requestCode, int resultCode, Intent data) {

    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == 2 && resultCode == RESULT_OK
            && null != data) {

        Uri selectedImage = data.getData();
        String[] filePathColumn = { MediaStore.Images.Media.DATA };

        Cursor cursor = getContentResolver().query(selectedImage,
                filePathColumn, null, null, null);
        cursor.moveToFirst();

        int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
        String picturePath = cursor.getString(columnIndex);
        cursor.close();

        bitmap = BitmapFactory.decodeFile(picturePath);
        image.setImageBitmap(bitmap);

        if (bitmap != null) {
            ImageView rotate = (ImageView) findViewById(R.id.rotate);

        }

    } else {

        Log.i("SonaSys", "resultCode: " + resultCode);
        switch (resultCode) {
        case 0:
            Log.i("SonaSys", "User cancelled");
            break;
        case -1:
            onPhotoTaken();
            break;

        }

    }

}

protected void onPhotoTaken() {
    // Log message
    Log.i("SonaSys", "onPhotoTaken");
    taken = true;
    imgCapFlag = true;
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inSampleSize = 4;
    bitmap = BitmapFactory.decodeFile(path, options);
    image.setImageBitmap(bitmap);


}
ASHISH KUMAR Tiwary
sumber