Jak zdobyć bitmapę z Uri?

209

Jak uzyskać obiekt Bitmap z Uri (jeśli uda mi się go zapisać w /data/data/MYFOLDER/myimage.pnglub file///data/data/MYFOLDER/myimage.png), aby użyć go w mojej aplikacji?

Czy ktoś ma pomysł, jak to osiągnąć?

ilredelweb
źródło
30
Powinieneś zaktualizować swoją zaakceptowaną odpowiedź w tym poście, ponieważ są lepsze odpowiedzi niż moje.
Vidar Vestnes
1
Druga odpowiedź jest właściwa z nich, trzeci odpowiedź jest bardziej kompletny.
IgniteCoders
@VidarVestnes Dlaczego go nie usuniesz?
Carlos López Marí,

Odpowiedzi:

-35

. . WAŻNE: Zobacz odpowiedź od @Mark Ingram poniżej i @pjv, aby uzyskać lepsze rozwiązanie. . .

Możesz spróbować:

public Bitmap loadBitmap(String url)
{
    Bitmap bm = null;
    InputStream is = null;
    BufferedInputStream bis = null;
    try 
    {
        URLConnection conn = new URL(url).openConnection();
        conn.connect();
        is = conn.getInputStream();
        bis = new BufferedInputStream(is, 8192);
        bm = BitmapFactory.decodeStream(bis);
    }
    catch (Exception e) 
    {
        e.printStackTrace();
    }
    finally {
        if (bis != null) 
        {
            try 
            {
                bis.close();
            }
            catch (IOException e) 
            {
                e.printStackTrace();
            }
        }
        if (is != null) 
        {
            try 
            {
                is.close();
            }
            catch (IOException e) 
            {
                e.printStackTrace();
            }
        }
    }
    return bm;
}

Pamiętaj jednak, że ta metoda powinna być wywoływana tylko z wątku (nie z GUI). I AsyncTask.

Vidar Vestnes
źródło
2
Co z konwersją URI na adres URL, np. Za pomocą yourUri.toURL ()?
Vidar Vestnes,
7
@VidarVestnes kolego, jak można przekonwertować ścieżkę pliku na adres URL?
dharam
7
Nie rozumiem, jak to jest wybrana odpowiedź
Nick Cardoso
11
Zgadzam się, ta odpowiedź nie powinna być uznana za najlepszą. Może został wybrany, ponieważ była to pierwsza odpowiedź. To stary post. W każdym razie, poniżej znajdziesz odpowiedzi na lepsze rozwiązania.
Vidar Vestnes
8
@VidarVestnes po prostu usuń swoją odpowiedź
winklerrr
564

Oto poprawny sposób:

protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == RESULT_OK)
    {
        Uri imageUri = data.getData();
        Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imageUri);
    }
}

Jeśli musisz załadować bardzo duże obrazy, poniższy kod załaduje je w kafelkach (unikając przydziałów dużej pamięci):

BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(myStream, false);  
Bitmap region = decoder.decodeRegion(new Rect(10, 10, 50, 50), null);

Zobacz odpowiedź tutaj

Mark Ingram
źródło
3
Ten kod nie obsługuje jednak większych zdjęć (w zasadzie dowolnego rozmiaru tapety). getBitmap () wywołuje decodeStream (), który nie działa z błędem OOM ze stackoverflow.com/questions/2220949/handling-large-bitmaps . Wszelkie inne porady? MediaStore.Images.Thumbnails.getThumbnail () najwyraźniej nie przyjmuje contentURI.
pjv
1
Zobacz odpowiedź tutaj: stackoverflow.com/questions/4753013/…
Mark Ingram
@MarkIngram Czy to działa z dowolnym obrazem lokalnym lub tylko obrazem z kamery?
Narendra Singh,
@ MarkIngram co jeśli nie mamy dostępu do data.getData (), mam na myśli to, że jeśli po prostu otworzę jakiś obraz z galerii i wszyscy wiem, że chodzi o jego ścieżkę, jak mogę uzyskać URI i bitmapę?
Umair,
@Umair powinieneś zadać nowe pytanie zamiast zadawać w komentarzach odpowiedzi. Przy okazji: spójrz tutaj developer.android.com/reference/android/net/Uri.html
winklerrr
111

Oto poprawny sposób na zrobienie tego, z zachowaniem kontroli użycia pamięci:

protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
  super.onActivityResult(requestCode, resultCode, data);
  if (resultCode == RESULT_OK)
  {
    Uri imageUri = data.getData();
    Bitmap bitmap = getThumbnail(imageUri);
  }
}

public static Bitmap getThumbnail(Uri uri) throws FileNotFoundException, IOException{
  InputStream input = this.getContentResolver().openInputStream(uri);

  BitmapFactory.Options onlyBoundsOptions = new BitmapFactory.Options();
  onlyBoundsOptions.inJustDecodeBounds = true;
  onlyBoundsOptions.inDither=true;//optional
  onlyBoundsOptions.inPreferredConfig=Bitmap.Config.ARGB_8888;//optional
  BitmapFactory.decodeStream(input, null, onlyBoundsOptions);
  input.close();

  if ((onlyBoundsOptions.outWidth == -1) || (onlyBoundsOptions.outHeight == -1)) {
    return null;
  }

  int originalSize = (onlyBoundsOptions.outHeight > onlyBoundsOptions.outWidth) ? onlyBoundsOptions.outHeight : onlyBoundsOptions.outWidth;

  double ratio = (originalSize > THUMBNAIL_SIZE) ? (originalSize / THUMBNAIL_SIZE) : 1.0;

  BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
  bitmapOptions.inSampleSize = getPowerOfTwoForSampleRatio(ratio);
  bitmapOptions.inDither = true; //optional
  bitmapOptions.inPreferredConfig=Bitmap.Config.ARGB_8888;//
  input = this.getContentResolver().openInputStream(uri);
  Bitmap bitmap = BitmapFactory.decodeStream(input, null, bitmapOptions);
  input.close();
  return bitmap;
}

private static int getPowerOfTwoForSampleRatio(double ratio){
  int k = Integer.highestOneBit((int)Math.floor(ratio));
  if(k==0) return 1;
  else return k;
}

Wywołanie getBitmap () z postu Marka Ingrama wywołuje również decodeStream (), więc nie tracisz żadnej funkcjonalności.

Bibliografia:

pjv
źródło
1
To naprawdę mi pomogło, chociaż myślę, że warto wspomnieć, że tego słowa kluczowego nie można użyć w kontekście statycznym. Podałem go jako metodę getThumbnail jako argument i działa jak urok.
MacKinley Smith
8
Czy ktoś może mi powiedzieć, jaką wartość powinienem dać THUMBNAILSIZE
Abid
2
Zamykanie i ponowne otwieranie InputStream jest faktycznie konieczne, ponieważ pierwsze wywołanie BitmapFactory.decodeStream (...) ustawia pozycję odczytu strumienia do końca, więc drugie wywołanie metody nie zadziałałoby bez ponownego otwarcia strumienia!
DominicM
3
proszę podać wartość THUMBNAILSIZE
Mightian
3
Nie ma potrzeby samodzielnego obliczania współczynnika jako potęgi dwóch, ponieważ sam dekoder zaokrągla wielkość próbki do najbliższej potęgi dwóch. Dlatego wywołanie metody getPowerOfTwoForSampleRatio()można pominąć. Zobacz: developer.android.com/reference/android/graphics/…
winklerrr
42
try
{
    Bitmap bitmap = MediaStore.Images.Media.getBitmap(c.getContentResolver() , Uri.parse(paths));
}
catch (Exception e) 
{
    //handle exception
}

i tak ścieżka musi mieć format podobny do tego

file:///mnt/sdcard/filename.jpg

DjP
źródło
1
dzięki Itay, to jest proste, jeśli masz ścieżkę, musisz po prostu przejść tę ścieżkę i zdobyć Bitmapę ... to działa dla mnie, mam nadzieję, że również spróbujesz tego ...
DjP
2
@Dhananjay Dziękuję, twoja wskazówka oszczędza mój dzień i działa, aby załadować miniaturową mapę bitową z dostawcy treści.
Nezneika
2
Ponadto funkcja Uri.parse () musi zawierać format URI, podobnie jak: Uri.parse („file: ///mnt/sdcard/filename.jpg”) , jeśli nie, otrzymamy java.io.FileNotFoundException: Brak treści dostawca .
Nezneika
Przydałaby się pewna redakcja, ale jest to dobra zwięzła odpowiedź na pytanie PO, która działa w większości przypadków. Jest to miła odpowiedź na stronie w celu wyjaśnienia fragmentu tych innych odpowiedzi, które bezpośrednio odpowiadają na pytania PO.
umassthrower
1
@AndroidNewBee c jest obiektem kontekstowym.
DjP
17

To jest najłatwiejsze rozwiązanie:

Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);
Hasib Akter
źródło
16
private void uriToBitmap(Uri selectedFileUri) {
    try {
        ParcelFileDescriptor parcelFileDescriptor =
                getContentResolver().openFileDescriptor(selectedFileUri, "r");
        FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
        Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);

        parcelFileDescriptor.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
DeltaCap019
źródło
3
działa na wszystkich SDK .. Dzięki. to alternatywny sposóbBitmap bitmap = MediaStore.Images.Media.getBitmap(context.getContentResolver(), uri);
Jigar Patel
najbardziej autentyczna odpowiedź, którą spełnił wszystkie SDK
Noaman Akram
13

Wygląda na to, że MediaStore.Images.Media.getBitmapbył przestarzały API 29. Zalecanym sposobem jest użycie, ImageDecoder.createSourcektóre zostało dodane API 28.

Oto jak można uzyskać bitmapę:

val bitmap = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
    ImageDecoder.decodeBitmap(ImageDecoder.createSource(requireContext().contentResolver, imageUri))
} else {
    MediaStore.Images.Media.getBitmap(requireContext().contentResolver, imageUri)
}
Ika
źródło
11

Możesz pobrać bitmapę z URI w ten sposób

Bitmap bitmap = null;
try {
    bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imageUri);
} catch (IOException e) {
    e.printStackTrace();
}
Emre AYDIN
źródło
10
Uri imgUri = data.getData();
Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imgUri);
Ahmed Sayed
źródło
2
Czy możesz wyjaśnić, jak działa ten kod i jak odpowiada na pytanie?
Michael Dodd
2

Użyj metody startActivityForResult jak poniżej

        startActivityForResult(new Intent(Intent.ACTION_PICK).setType("image/*"), PICK_IMAGE);

I możesz uzyskać taki wynik:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode != RESULT_OK) {
        return;
    }
    switch (requestCode) {
        case PICK_IMAGE:
            Uri imageUri = data.getData();
            try {
                Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imageUri);
            } catch (IOException e) {
                e.printStackTrace();
            }
         break;
    }
}
Faxriddin Abdullayev
źródło
2

Próbowałem na wiele sposobów. ta praca dla mnie idealnie.

Jeśli wybierzesz pictrue z galerii. Musisz być ostrożny w pobieraniu Uriz intent.clipdatalub intent.data, ponieważ jeden z nich może być pusty w innej wersji.

  private fun onChoosePicture(data: Intent?):Bitmap {
        data?.let {
            var fileUri:Uri? = null

              data.clipData?.let {clip->
                  if(clip.itemCount>0){
                      fileUri = clip.getItemAt(0).uri
                  }
              }
            it.data?.let {uri->
                fileUri = uri
            }


               return MediaStore.Images.Media.getBitmap(this.contentResolver, fileUri )
}
Cyrus
źródło
1

możesz zrobić tę strukturę:

protected void onActivityResult(int requestCode, int resultCode, Intent imageReturnedIntent) {
    super.onActivityResult(requestCode, resultCode, imageReturnedIntent);
    switch(requestCode) {
        case 0:
            if(resultCode == RESULT_OK){
                    Uri selectedImage = imageReturnedIntent.getData();
                    Bundle extras = imageReturnedIntent.getExtras();
                    bitmap = extras.getParcelable("data");
            }
            break;
   }

dzięki temu możesz łatwo przekonwertować URI na bitmapę. mam nadzieję, że ci pomogę

Sayed Mohammad Amin Emrani
źródło
1
To nie działa w wersji Android nougat 7.1.1. To extras.getParcelable („dane”); zwraca wartość null
Developer_vaibhav
1

Wstawka z getBitmapktórą depricated teraz używam następujące podejście w Kotlin

PICK_IMAGE_REQUEST ->
    data?.data?.let {
        val bitmap = BitmapFactory.decodeStream(contentResolver.openInputStream(it))
        imageView.setImageBitmap(bitmap)
    }
Yaugenka
źródło
1
  InputStream imageStream = null;
    try {
        imageStream = getContext().getContentResolver().openInputStream(uri);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    final Bitmap selectedImage = BitmapFactory.decodeStream(imageStream);
Fawzi Nofal
źródło
1

(KOTLIN) Tak więc od 7 kwietnia 2020 r. Żadna z wyżej wymienionych opcji nie działała, ale oto, co zadziałało dla mnie:

  1. Jeśli chcesz zapisać bitmapę w wartości i ustawić przy niej imageView, użyj tego:

    val bitmap = BitmapFactory.decodeFile(currentPhotoPath).also { bitmap -> imageView.setImageBitmap(bitmap) }

  2. Jeśli chcesz ustawić bitmapę na i imageView, użyj tego:

    BitmapFactory.decodeFile(currentPhotoPath).also { bitmap -> imageView.setImageBitmap(bitmap) }

Advait Bansode
źródło
0

Pełna metoda pobierania obrazu z galerii mobilnej.

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

  if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null && data.getData() != null) {
                Uri filePath = data.getData();

     try { //Getting the Bitmap from Gallery
           Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), filePath);
           rbitmap = getResizedBitmap(bitmap, 250);//Setting the Bitmap to ImageView
           serImage = getStringImage(rbitmap);
           imageViewUserImage.setImageBitmap(rbitmap);
      } catch (IOException e) {
           e.printStackTrace();
      }


   }
}
Zzmilanzz Zzmadubashazz
źródło