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ąć?


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.


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


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


@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:


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


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

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

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

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

10
Uri imgUri = data.getData();
Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imgUri);

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

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

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ę


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

1
  InputStream imageStream = null;
    try {
        imageStream = getContext().getContentResolver().openInputStream(uri);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    final Bitmap selectedImage = BitmapFactory.decodeStream(imageStream);

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


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


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