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.