Làm cách nào để có được Bitmap từ một Uri?


209

Làm cách nào để có được một đối tượng Bitmap từ một Uri (nếu tôi thành công để lưu trữ nó trong /data/data/MYFOLDER/myimage.pnghoặc file///data/data/MYFOLDER/myimage.png) để sử dụng nó trong ứng dụng của mình?

Có ai có một ý tưởng về cách thực hiện điều này?


30
Bạn nên cập nhật câu trả lời được chấp nhận của bạn trên bài đăng này, vì có câu trả lời tốt hơn của tôi.
Vidar Vestnes

1
Các câu trả lời thứ hai là một trong những quyền, các câu trả lời thứ ba là hoàn chỉnh hơn.
IgniteCoders

@VidarVestnes Tại sao bạn không xóa nó?
Carlos López Marí

Câu trả lời:


-35

. . QUAN TRỌNG: Xem câu trả lời từ @Mark Ingram bên dưới và @pjv để biết giải pháp tốt hơn. . .

Bạn có thể thử điều này:

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

Nhưng hãy nhớ rằng, phương thức này chỉ nên được gọi từ bên trong một luồng (không phải GUI -thread). Tôi là một AsyncTask.


2
Điều gì về việc chuyển đổi URI thành một url, ví dụ: bằng cách sử dụng yourUri.toURL ()?
Vidar Vestnes

7
@VidarVestnes bạn thân, làm thế nào có thể chuyển đổi đường dẫn tệp trên Url?
dharam

7
Tôi không hiểu câu trả lời được chọn như thế nào
Nick Cardoso

11
Tôi đồng ý, câu trả lời này không nên được chấp nhận là tốt nhất. Có lẽ nó được chọn vì đó là câu trả lời đầu tiên. Đó là một bài viết cũ. Dù sao, se câu trả lời dưới đây cho giải pháp tốt hơn.
Vidar Vestnes

8
@VidarVestnes chỉ cần xóa câu trả lời của bạn
winklerrr

564

Đây là cách làm đúng:

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

Nếu bạn cần tải hình ảnh rất lớn, đoạn mã sau sẽ tải nó trong các ô (tránh phân bổ bộ nhớ lớn):

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

Xem câu trả lời tại đây


3
Mã này không xử lý hình ảnh lớn hơn (về cơ bản bất kỳ kích thước hình nền). getBitmap () gọi decodeStream () không thành công với lỗi OOM từ stackoverflow.com/questions/2220949/handling-large-bitmaps . Còn lời khuyên nào nữa không? MediaStore.Images.Thumbnails.getThumbnail () dường như không mất nội dungURI.
pjv

1
Xem câu trả lời tại đây: stackoverflow.com/questions/4753013/ từ
Mark Ingram

@MarkIngram Điều này có hoạt động với bất kỳ hình ảnh địa phương hoặc chỉ hình ảnh máy ảnh?
Narendra Singh

@MarkIngram nếu chúng ta không có quyền truy cập vào data.getData (), ý tôi là nếu tôi chỉ đơn giản mở một số hình ảnh từ thư viện và tôi đều biết là về đường dẫn của nó, làm cách nào tôi có thể lấy uri và bitmap?
Umair

@Umair bạn nên hỏi một câu hỏi mới thay vì hỏi trong các bình luận của một câu trả lời. Nhân tiện: hãy xem tại đây developer.android.com/reference/android/net/Uri.html
winklerrr

111

Đây là cách làm đúng, cũng giữ các tab sử dụng bộ nhớ:

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

Cuộc gọi getBitmap () từ bài đăng của Mark Ingram cũng gọi decodeStream (), vì vậy bạn không mất bất kỳ chức năng nào.

Người giới thiệu:


1
Điều này thực sự giúp ích cho tôi, mặc dù tôi nghĩ rằng đáng để đề cập rằng từ khóa này không thể được sử dụng từ trong một bối cảnh tĩnh. Tôi đã chuyển nó vào phương thức getThumbnail như một đối số và nó hoạt động như một nét duyên dáng.
MacKinley Smith

8
Có ai có thể cho tôi biết giá trị nào tôi nên cung cấp cho THUMBNAILSIZE
Abid

2
Việc đóng và mở lại InputStream thực sự cần thiết vì lệnh gọi BitmapFactory.decodeStream (...) đầu tiên đặt vị trí đọc của luồng đến hết, vì vậy lệnh gọi thứ hai của phương thức sẽ không hoạt động nữa mà không mở lại luồng!
Đaminh

3
vui lòng cho biết giá trị của THUMBNAILSIZE
Mightian

3
Không cần thiết phải tự tính tỷ lệ là lũy thừa của hai vì bộ giải mã tự làm tròn thành cỡ mẫu xuống tới công suất gần nhất của hai. Do đó, cuộc gọi phương thức getPowerOfTwoForSampleRatio()có thể được bỏ qua. Xem: developer.android.com/reference/android/graphics/ từ
winklerrr

42
try
{
    Bitmap bitmap = MediaStore.Images.Media.getBitmap(c.getContentResolver() , Uri.parse(paths));
}
catch (Exception e) 
{
    //handle exception
}

và có đường dẫn phải có định dạng như thế này

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


1
cảm ơn Itay, điều này thật đơn giản, nếu bạn có con đường bạn chỉ cần vượt qua con đường đó và lấy Bitmap .. nó đang hoạt động với tôi, hy vọng bạn cũng sẽ thử điều này ..
DjP

2
@Dhananjay Cảm ơn bạn, gợi ý của bạn giúp tiết kiệm ngày của tôi và nó hoạt động để tải bitmap hình thu nhỏ từ Nhà cung cấp nội dung.
Nezneika

2
Ngoài ra, Uri.parse () phải chứa định dạng URI, giống như: Uri.parse ("file: ///mnt/sdcard/filename.jpg") , nếu không chúng tôi sẽ nhận được java.io.FileNotFoundException: Không có nội dung nhà cung cấp .
Nezneika

Một số bài xã luận sẽ rất hay, nhưng đây là một câu trả lời ngắn gọn cho câu hỏi OP hoạt động trong hầu hết các trường hợp. Đây là một câu trả lời hay có trên trang với mục đích chắt lọc những phần của những câu trả lời khác trực tiếp trả lời các câu hỏi của OP.
umassthrower

1
@AndroidNewBee c là đối tượng bối cảnh.
DjP

17

Đây là giải pháp dễ nhất:

Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);

15
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
nó hoạt động trên tất cả các sdk .. Cảm ơn. đó là cách khác củaBitmap bitmap = MediaStore.Images.Media.getBitmap(context.getContentResolver(), uri);
Jigar Patel

câu trả lời chân thực nhất mà tất cả SDK hài lòng
Noaman Akram

13

Có vẻ như MediaStore.Images.Media.getBitmapđã bị phản đối API 29. Cách được đề xuất là sử dụng ImageDecoder.createSourceđã được thêm vào API 28.

Đây là cách nhận bitmap sẽ được thực hiện:

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

Bạn có thể lấy bitmap từ uri như thế này

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
Bạn có thể vui lòng giải thích về cách mã này hoạt động và cách nó trả lời câu hỏi?
Michael Dodd

2

Sử dụng metod startActivityForResult như bên dưới

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

Và bạn có thể nhận được kết quả như thế này:

@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

Tôi đã thử rất nhiều cách. công việc này đối với tôi hoàn hảo

Nếu bạn chọn hình ảnh từ Thư viện. Bạn cần phải sẵn sàng nhận Uritừ intent.clipdatahoặc intent.data, bởi vì một trong số chúng có thể là null trong phiên bản khác nhau.

  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

bạn có thể làm cấu trúc này:

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

bằng cách này, bạn có thể dễ dàng chuyển đổi một uri thành bitmap. mong giúp bạn


1
Điều này không hoạt động trong phiên bản Android nougat 7.1.1. Điều này ngoại vi.getParcelable ("dữ liệu"); đang trả về null
Nhà phát

1

Inset của getBitmapđược depricated bây giờ tôi sử dụng các phương pháp sau đây trong 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);

0

Phương pháp đầy đủ để có được hình ảnh uri từ bộ sưu tập di động.

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


   }
}

0

(KOTLINE) Vì vậy, kể từ ngày 7 tháng 4 năm 2020, không có lựa chọn nào được đề cập ở trên có hiệu quả, nhưng đây là những gì hiệu quả với tôi:

  1. Nếu bạn muốn lưu trữ bitmap trong val và đặt imageView với nó, hãy sử dụng:

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

  2. Nếu bạn chỉ muốn đặt bitmap thành và imageView, hãy sử dụng điều này:

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.