วิธีรับ Bitmap จาก Uri


209

วิธีรับวัตถุบิตแมปจาก Uri (หากฉันประสบความสำเร็จในการเก็บไว้ใน /data/data/MYFOLDER/myimage.pngหรือfile///data/data/MYFOLDER/myimage.png) เพื่อใช้ในแอปพลิเคชันของฉัน

ใครบ้างมีความคิดในการทำสิ่งนี้ให้สำเร็จ


30
คุณควรอัปเดตคำตอบที่ยอมรับในโพสต์นี้เนื่องจากมีคำตอบที่ดีกว่าของฉัน
Vidar Vestnes

1
ตอบที่สองเป็นสิทธิหนึ่งคำตอบที่สามคือความสมบูรณ์มากขึ้น
IgniteCoders

@VidarVestnes ทำไมคุณไม่ลบมัน?
Carlos

คำตอบ:


-35

. . สำคัญ: ดูคำตอบจาก @Mark Ingram ด้านล่างและ @pjv เพื่อการแก้ปัญหาที่ดีกว่า . .

คุณสามารถลองสิ่งนี้:

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

แต่จำไว้ว่าวิธีนี้ควรถูกเรียกจากภายในเธรดเท่านั้น (ไม่ใช่ GUI -thread) ฉันเป็น AsyncTask


2
สิ่งที่เกี่ยวกับการแปลง URI เป็น URL เช่นโดยใช้ yourUri.toURL ()
Vidar Vestnes

7
@VidarVestnes เพื่อนวิธีแปลงไฟล์เส้นทางบน Url?
dharam

7
ฉันไม่เข้าใจว่านี่เป็นคำตอบที่เลือกไหม
Nick Cardoso

11
ฉันเห็นด้วยคำตอบนี้ไม่ควรได้รับการยอมรับว่าดีที่สุด บางทีมันอาจจะเป็นทางเลือกเพราะมันเป็นคำตอบแรก มันเป็นโพสต์เก่า อย่างไรก็ตามคำตอบด้านล่างสำหรับวิธีแก้ปัญหาที่ดีกว่า
Vidar Vestnes

8
@VidarVestnes เพียงแค่ลบคำตอบของคุณ
winklerrr

564

นี่คือวิธีที่ถูกต้องในการทำ:

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

หากคุณต้องการโหลดภาพที่มีขนาดใหญ่มากรหัสต่อไปนี้จะโหลดในรูปแบบไทล์ (หลีกเลี่ยงการจัดสรรหน่วยความจำขนาดใหญ่):

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

ดูคำตอบได้ที่นี่


3
รหัสนี้ไม่ได้จัดการกับภาพที่ใหญ่ขึ้น getBitmap () เรียก decodeStream () ซึ่งล้มเหลวด้วยข้อผิดพลาด OOM จากstackoverflow.com/questions/2220949/handling-large-bitmaps มีคำแนะนำอื่น ๆ อีกไหม? MediaStore.Images.Thumbnails.getThumbnail () เห็นได้ชัดว่าไม่ได้ใช้ contentURI
pjv


@MarkIngram มันใช้ได้กับภาพในตัวเครื่องหรือภาพจากกล้องหรือไม่?
Narendra Singh

@ MarkIngram จะเป็นอย่างไรถ้าเราไม่มีสิทธิ์เข้าถึง data.getData () ฉันหมายความว่าถ้าฉันเปิดภาพจากแกลเลอรี่และฉันรู้ว่าเส้นทางของมันฉันจะได้รับ uri และบิตแมปได้อย่างไร?
Umair

@Umair คุณควรถามคำถามใหม่แทนที่จะถามในความคิดเห็นของคำตอบ โดยวิธีการ: ดูที่นี่developer.android.com/reference/android/net/Uri.html
winklerrr

111

นี่เป็นวิธีที่ถูกต้องในการทำเช่นนั้นโดยรักษาแท็บในการใช้หน่วยความจำเช่นกัน:

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

การเรียกใช้ getBitmap () จากการโพสต์ของ Mark Ingram เรียกว่า decodeStream () ดังนั้นคุณจะไม่สูญเสียฟังก์ชันการทำงานใด ๆ

อ้างอิง:


1
สิ่งนี้ช่วยฉันได้จริงๆแม้ว่าฉันคิดว่ามันคุ้มค่าที่จะกล่าวถึงว่าคำหลักนี้ไม่สามารถใช้จากภายในบริบทที่คงที่ได้ ฉันส่งมันไปยังเมธอด getThumbnail เพื่อเป็นข้อโต้แย้งและมันทำงานได้อย่างมีเสน่ห์
MacKinley Smith

8
ใครสามารถบอกฉันได้ว่าฉันควรให้คุณค่ากับ THUMBNAILSIZE เท่าไหร่
Abid

2
การปิดและเปิด InputStream เป็นสิ่งที่จำเป็นจริง ๆ เพราะการเรียก BitmapFactory.decodeStream (... ) ครั้งแรกเป็นการตั้งค่าตำแหน่งการอ่านของกระแสข้อมูลไปยังจุดสิ้นสุดดังนั้นการเรียกครั้งที่สองของวิธีการจะไม่ทำงานอีกต่อไปโดยไม่ต้องเปิดกระแสอีกครั้ง!
DominicM

3
โปรดบอกคุณค่าของ THUMBNAILSIZE
Mightian

3
มันไม่จำเป็นที่จะคำนวณอัตราส่วนด้วยพลังของสองตัวเองเพราะตัวถอดรหัสจะปัดเศษขนาดตัวอย่างลงไปจนถึงกำลังสองที่ใกล้เคียงที่สุด ดังนั้นการเรียกเมธอดgetPowerOfTwoForSampleRatio()สามารถข้ามได้ ดู: 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
}

และเส้นทางที่ใช่จะต้องอยู่ในรูปแบบเช่นนี้

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


1
ขอบคุณ Itay นี้ง่ายถ้าคุณมีเส้นทางคุณเพียงแค่ต้องผ่านเส้นทางนั้นและได้รับบิตแมป .. มันใช้งานได้สำหรับฉันหวังว่าคุณจะลองทำเช่นนี้ ..
DjP

2
@Dhananjay ขอขอบคุณคำแนะนำของคุณบันทึกวันของฉันและมันทำงานเพื่อโหลดบิตแมปรูปขนาดย่อจากผู้ให้บริการเนื้อหา
Nezneika

2
นอกจากนี้Uri.parse ()จะต้องมีรูปแบบ URI เช่นเดียวกับ: Uri.parse ("file: ///mnt/sdcard/filename.jpg")หากไม่มีเราจะได้รับjava.io.FileNotFoundException: ไม่มีเนื้อหา ผู้จัดหา
Nezneika

การปรับแก้บางอย่างจะดี แต่นี่เป็นคำตอบที่ดีสำหรับคำถาม OPs ที่ใช้งานได้ในกรณีส่วนใหญ่ นี่เป็นคำตอบที่ดีที่มีอยู่ในหน้าเพื่อกลั่นกรองชิ้นส่วนของคำตอบอื่น ๆ เหล่านี้ที่ตอบคำถาม OPs โดยตรง
umassthrower

1
@AndroidNewBee c เป็นวัตถุบริบท
DjP


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
มันทำงานได้ใน sdk ทั้งหมด .. ขอบคุณ มันเป็นทางเลือกของBitmap bitmap = MediaStore.Images.Media.getBitmap(context.getContentResolver(), uri);
Jigar Patel

คำตอบที่แท้จริงที่สุดของ SDK ทั้งหมดพึงพอใจ
Noaman Akram

13

มันดูเหมือนว่าจะได้รับการยกเลิกในMediaStore.Images.Media.getBitmap API 29วิธีที่แนะนำคือการใช้ImageDecoder.createSourceซึ่งเพิ่มเข้าAPI 28มา

นี่คือวิธีการรับบิตแมปที่จะทำ:

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

คุณสามารถดึงบิตแมปจาก uri เช่นนี้ได้

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
คุณช่วยอธิบายรายละเอียดเกี่ยวกับวิธีการทำงานของรหัสนี้และวิธีตอบคำถามได้อย่างไร
Michael Dodd

2

ใช้ startActivityForResult metod เหมือนด้านล่าง

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

และคุณจะได้ผลลัพธ์เช่นนี้:

@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

ฉันได้ลองหลายวิธีแล้ว งานนี้สำหรับฉันอย่างสมบูรณ์แบบ

หากคุณเลือก pictrue จากคลังภาพ คุณต้องเป็นเครื่องที่ได้รับUriจากintent.clipdataหรือintent.dataเพราะหนึ่งในนั้นอาจเป็นโมฆะในเวอร์ชันที่แตกต่างกัน

  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

คุณสามารถทำโครงสร้างนี้:

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

โดยสิ่งนี้คุณสามารถแปลง uri เป็น bitmap ได้อย่างง่ายดาย หวังว่าจะช่วยคุณ


1
มันไม่ทำงานใน android nougat 7.1.1 เวอร์ชั่น extras.getParcelable นี้ ("ข้อมูล"); กำลังคืนค่า null
Developer_vaibhav

1

สิ่งที่ใส่เข้าไปgetBitmapซึ่งถูก depricated ตอนนี้ฉันใช้วิธีการต่อไปนี้ใน 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) ดังนั้นเมื่อวันที่ 7 เมษายน 2020 ไม่มีตัวเลือกที่กล่าวถึงข้างต้นทำงานได้ แต่นี่คือสิ่งที่ใช้ได้กับฉัน:

  1. หากคุณต้องการเก็บบิตแมปใน val และตั้งค่า imageView ด้วยให้ใช้สิ่งนี้:

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

  2. หากคุณต้องการตั้งค่าบิตแมปเป็นและ imageView ใช้สิ่งนี้:

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


0

วิธีการรับภาพ uri อย่างสมบูรณ์จากแกลเลอรีมือถือ

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


   }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.