Jak wybrać zdjęcie z galerii (karta SD) dla mojej aplikacji?


343

To pytanie zostało pierwotnie zadane dla Androida 1.6.

Pracuję nad opcjami zdjęć w mojej aplikacji.

W mojej aktywności mam przycisk i ImageView. Po kliknięciu przycisku nastąpi przekierowanie do galerii i będę mógł wybrać obraz. Wybrany obraz pojawi się w moim ImageView.


1
spójrz na tę odpowiedź, opublikowałem tam ulepszony kod do obsługi wyborów z menedżerów plików także stackoverflow.com/questions/2169649/…
szalony

Odpowiedzi:


418

Zaktualizowana odpowiedź, prawie 5 lat później:

Kod w oryginalnej odpowiedzi nie działa niezawodnie, jak obrazy z różnych źródeł, czasami powrócić z różną zawartością URI, czyli content://zamiast file://. Lepszym rozwiązaniem jest po prostu użycie context.getContentResolver().openInputStream(intent.getData()), ponieważ zwróci InputStream, który możesz obsłużyć według własnego wyboru.

Na przykład BitmapFactory.decodeStream()działa idealnie w tej sytuacji, ponieważ można również użyć pola Opcje i inSampleSize, aby zmniejszyć próbkę dużych obrazów i uniknąć problemów z pamięcią.

Jednak rzeczy takie jak Dysk Google zwracają identyfikatory URI do obrazów, które nie zostały jeszcze pobrane. Dlatego musisz wykonać kod getContentResolver () w wątku w tle.


Oryginalna odpowiedź:

Pozostałe odpowiedzi wyjaśniły, jak wysłać zamiar, ale nie wyjaśniły dobrze, jak sobie z tym poradzić. Oto przykładowy kod, jak to zrobić:

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

Następnie masz wybrany obraz zapisany w „yourSelectedImage”, aby robić, co chcesz. Ten kod działa, pobierając lokalizację obrazu w bazie danych ContentResolver, ale sam w sobie nie wystarczy. Każde zdjęcie zawiera około 18 kolumn informacji, od ścieżki pliku do „ostatniej modyfikacji daty” do współrzędnych GPS miejsca, w którym zdjęcie zostało zrobione, chociaż wiele pól nie jest faktycznie używanych.

Aby zaoszczędzić czas, ponieważ tak naprawdę nie potrzebujesz innych pól, wyszukiwanie kursorem odbywa się za pomocą filtra. Filtr działa poprzez określenie nazwy żądanej kolumny, MediaStore.Images.Media.DATA, która jest ścieżką, a następnie podanie tego ciągu [] do zapytania kursora. Zapytanie kursora powraca ze ścieżką, ale nie wiesz, w której kolumnie się znajduje, dopóki nie użyjesz columnIndexkodu. To po prostu pobiera numer kolumny na podstawie jej nazwy, tej samej, której użyto w procesie filtrowania. Gdy to osiągniesz, w końcu możesz dekodować obraz do bitmapy za pomocą ostatniego wiersza kodu, który podałem.


4
kursor.moveToFirst () powinien zostać sprawdzony pod kątem istnienia: if (kursor.moveToFirst ()) {zrób coś z danymi kursora}
mishkin

14
Zamiast kursora powinieneś pobrać obraz w ten sposób: Bitmap b = MediaStore.Images.Media.getBitmap (this.getContentResolver (), selectedImage);
Luigi Agosti

4
Luigi, jeśli bitmapa jest duża MediaStore.Images.Media.getBitmap () może powodować wyjątki OutOfMemory. Metoda Steve'a pozwala skalować obraz w dół przed załadowaniem go do pamięci.
Frank Harper,

9
to nie działa dla mnie, dostaję null z kursor.getString (columnIndex);
Alexis Pautrot,

9
Ostrożnie z tą metodą: nazwa pliku będzie „null”, gdy użytkownik wybierze zdjęcie z albumu Picasa lub z aplikacji Zdjęcia Google+.
Ciske Boekelo

315
private static final int SELECT_PHOTO = 100;

Zacznij zamiar

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

Wynik procesu

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

Alternatywnie możesz również zmniejszyć próbkę obrazu, aby uniknąć błędów 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);

    }

8
włożenie 1,5 MB JPEG do mojego małego podglądu obrazu 100 na 100 pikseli spowodowało błąd pamięci VM. Próbkowanie w dół naprawiło ten problem :-)
Ktoś gdzieś

1
Cześć. Czy oba strumienie nie powinny być zamknięte?
Denis Kniazhev

Cześć @ siamii .. Podążyłem za twoim kodem ... ale to częściowo działa dla mnie .. :( kiedy obraz jest wybrany z galerii w sekcji przechwyconych zdjęć, wtedy daje błąd JSON, ale kiedy obraz jest wybrany z galerii w sekcji Bluetooth obraz jest dostępny i wysyłany na serwer .. czy możesz sprawdzić ten link i zasugerować mi jakieś rozwiązanie ... stackoverflow.com/questions/29234409/image-is-not-uploaded
Prabs

Sekcja o znajdowaniu skali może być napisana jako:int scale = 1; for ( ; bfOptions.outWidth / scale > TARGET_SIZE && bfOptions.outWidth > TARGET_SIZE; scale*=2);
The_Rafi

@siamii Gdzie i jak wywołać tę metodę -------- decodeUri
Akshay Kumar

87

Musisz rozpocząć zamiar galerii, aby uzyskać wynik.

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

Następnie onActivityForResultzadzwoń, intent.getData()aby uzyskać Uri obrazu. Następnie musisz pobrać obraz z ContentProvider.


Czym ACTION_PICK różni się od ACTION_GET_CONTENT zastosowanego w dwóch innych odpowiedziach?
penguin359

4
Za pomocą ACTION_PICK określasz konkretny identyfikator URI, a za pomocą ACTION_GET_CONTENT określasz typ mime. Użyłem ACTION_PICK, ponieważ pytanie dotyczyło konkretnie obrazów z karty SDCARD, a nie wszystkich obrazów.
Robby Pond

2
Fajne. Właśnie tego potrzebowałem i
działałem

@WilliamKinaan ACTIVITY_SELECT_IMAGE to dowolna wartość int, którą określisz w celu ustalenia, jaki wynik spodziewasz się otrzymać. Następnie jest on wysyłany z powrotem w onActivityResult (int requestCode, int resultCode, Intent data) jako „requestCode”.
Fydo

@Fydo zdałem sobie sprawę, że później, dzięki
William Kinaan

22

Oto przetestowany kod obrazu i wideo, który będzie działał dla wszystkich interfejsów API mniejszych niż 19 i większych niż 19.

Wizerunek:

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

Wideo:

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

14

Zrób to, aby uruchomić galerię i pozwolić użytkownikowi wybrać obraz:

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

Następnie przy onActivityResult()użyciu URI obrazu, który jest zwracany, aby ustawić obraz w ImageView.


3
To nie będzie działać na urządzeniach z Androidem 4.4. Uruchomi się ekran ostatnich dokumentów.
Noundla Sandeep

2
Oto poprawka dla 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);
}

}

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

}

Oto poprawka dla KitKat: stackoverflow.com/a/26690628/860488
Morten Holmgaard

4

Z niektórych powodów wszystkie odpowiedzi w tym wątku onActivityResult()próbują przetworzyć otrzymane dane Uri, na przykład uzyskać prawdziwą ścieżkę obrazu, a następnie użyć, BitmapFactory.decodeFile(path)aby uzyskaćBitmap .

Ten krok jest niepotrzebny. ImageViewKlasa ma metodę nazwie setImageURI(uri). Podaj do niego swoje URI i powinieneś skończyć.

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

Aby uzyskać pełny działający przykład, możesz zajrzeć tutaj: http://androidbitmaps.blogspot.com/2015/04/loading-images-in-android-part-iii-pick.html

PS:
Wprowadzenie Bitmapoddzielnej zmiennej miałoby sens w przypadkach, gdy obraz do załadowania jest zbyt duży, aby zmieścił się w pamięci, a konieczne jest wykonanie operacji zmniejszania skali OurOfMemoryError, jak pokazano w odpowiedzi @siamii.


3

wywołaj metodę selectImage jak-

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

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


}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.