วิธีแปลง Drawable เป็น Bitmap


947

ฉันต้องการตั้งค่าบางอย่างDrawableเป็นวอลล์เปเปอร์ของอุปกรณ์ แต่ฟังก์ชั่นวอลล์เปเปอร์ทั้งหมดยอมรับBitmapเฉพาะ ฉันไม่สามารถใช้WallpaperManagerเพราะฉันก่อน 2.1

R.drawableนอกจากนี้ยังมีภาพวาดของฉันจะถูกดาวน์โหลดจากเว็บและไม่ได้อาศัยอยู่ใน



1
โปรดเลือกคำตอบที่ถูกต้องนี้: stackoverflow.com/a/3035869/4548520
25

คำตอบ:


1289

รหัสนี้ช่วย

Bitmap icon = BitmapFactory.decodeResource(context.getResources(),
                                           R.drawable.icon_resource);

นี่คือรุ่นที่มีการดาวน์โหลดรูปภาพ

String name = c.getString(str_url);
URL url_value = new URL(name);
ImageView profile = (ImageView)v.findViewById(R.id.vdo_icon);
if (profile != null) {
    Bitmap mIcon1 =
        BitmapFactory.decodeStream(url_value.openConnection().getInputStream());
    profile.setImageBitmap(mIcon1);
}

1
ฉันคิดว่าคุณมีค่า URL คำตอบที่แก้ไขแล้วของฉันจะช่วยได้
Praveen

str_url มาจากไหน ฉันไม่พบฟังก์ชัน Drawable ใด ๆ ที่เกี่ยวข้องกับสตริง ... ขอบคุณสำหรับความช่วยเหลือของคุณ
Rob

12
ฉันคิดว่าฉันพบบางสิ่ง: ถ้า "draw" เป็น drawable ฉันต้องการแปลงเป็นบิตแมปแล้ว: Bitmap bitmap = ((BitmapDrawable) draw) .getBitmap (); หลอกลวง!
Rob

1
@Rob: หาก Drawable ของคุณเป็น BitmapDrawable เท่านั้น (ซึ่งหมายความว่า Drawable ของคุณเป็นเพียง wrapper รอบ ๆ บิตแมปจริง ๆ )
njzk2

2
หมายเหตุ: สิ่งนี้ทำให้เกิด java.lang.OutOfMemoryError ขนาดใหญ่ของ JPG
บางคนที่อื่น

743
public static Bitmap drawableToBitmap (Drawable drawable) {
    Bitmap bitmap = null;

    if (drawable instanceof BitmapDrawable) {
        BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
        if(bitmapDrawable.getBitmap() != null) {
            return bitmapDrawable.getBitmap();
        }
    }

    if(drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
        bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); // Single color bitmap will be created of 1x1 pixel
    } else {
        bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
    }

    Canvas canvas = new Canvas(bitmap);
    drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
    drawable.draw(canvas);
    return bitmap;
}

41
ดูเหมือนว่าคำตอบเดียวที่ใช้ได้กับ drawable ทุกชนิดและยังมีวิธีแก้ปัญหาอย่างรวดเร็วสำหรับ drawable ที่เป็น BitmapDrawable อยู่แล้ว +1
Matt Wolfe

1
เพียงหนึ่งการแก้ไข: docs พูดเกี่ยวกับ BitmapDrawable.getBitmap () ว่ามันอาจกลับมาเป็นโมฆะ ฉันบอกว่ามันอาจกลับมารีไซเคิลได้แล้ว
kellogs

16
ระวัง: getIntrinsicWidth()และgetIntrinsicHieght()จะคืนค่า -1 ถ้า drawable เป็นสีทึบ
SD

5
ดังนั้น ... ตรวจสอบ ColorDrawable อีกครั้งและเรามีผู้ชนะ อย่างจริงจังมีคนทำคำตอบนี้ได้รับการยอมรับ
kayay

2
ตรงกันข้ามกับคำตอบที่ถูกตั้งค่าสถานะนี้ตอบคำถาม
njzk2

214

สิ่งนี้จะแปลง BitmapDrawable เป็น Bitmap

Drawable d = ImagesArrayList.get(0);  
Bitmap bitmap = ((BitmapDrawable)d).getBitmap();

9
นี่เป็นวิธีที่ดีที่สุดจริง ๆ หรือ แน่นอน drawable อาจเป็นประเภทอื่นและสิ่งนี้จะโยน runtimeException หรือไม่ ตัวอย่างเช่นอาจเป็น NinePatchDrawble ... ?
Dori

4
@Dori คุณสามารถห่อรหัสในคำสั่งตามเงื่อนไขเพื่อตรวจสอบว่าเป็นจริงBitmapDrawableก่อนที่จะหล่อมัน if (d instanceof BitmapDrawable) { Bitmap bitmap = ((BitmapDrawable)d).getBitmap(); }
โทนี่จันทร์

367
ไม่อยากเชื่อ 64 upvotes ใช่ไหม รหัสที่เห็นได้ชัดว่าการทำงานเฉพาะในกรณีที่dมีอยู่แล้วเป็นBitmapDrawableซึ่งในกรณีนี้มันเป็นเรื่องเล็ก ๆ น้อย ๆ ที่จะดึงมันเป็นบิตแมป ... จะผิดพลาดกับClassCastExceptionในกรณีอื่น ๆ
Matthias

3
@ Matias ไม่ต้องพูดถึงว่า .. คำถามตัวเองผู้เขียนคนเดียวกันมี 100 คะแนนโหวต: /
quinestor

2
นี่เป็นกรณีเฉพาะสำหรับเรื่องเล็กน้อย
njzk2

141

DrawableสามารถวาดลงบนCanvasและCanvasสามารถรับการสนับสนุนโดยBitmap:

(อัปเดตเพื่อจัดการกับการแปลงอย่างรวดเร็วสำหรับBitmapDrawables และเพื่อให้แน่ใจว่าการBitmapสร้างมีขนาดที่ถูกต้อง)

public static Bitmap drawableToBitmap (Drawable drawable) {
    if (drawable instanceof BitmapDrawable) {
        return ((BitmapDrawable)drawable).getBitmap();
    }

    int width = drawable.getIntrinsicWidth();
    width = width > 0 ? width : 1;
    int height = drawable.getIntrinsicHeight();
    height = height > 0 ? height : 1;

    Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap); 
    drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
    drawable.draw(canvas);

    return bitmap;
}

จะเกิดอะไรขึ้นถ้า param ที่ดึงออกได้เป็นโมฆะ?
hrules6872

1
วิธีนี้ไม่รองรับ VectorDrawable
Mahmoud


สมมติว่าคุณได้รับ Drawable ที่ไม่ว่างเปล่าเหตุใดจึงต้องตรวจสอบความกว้างและความสูงนั้นไม่ได้เป็น 0 ทำไมคุณต้องใช้ setBounds () ถ้ามันมีขนาดเท่ากัน?
Yoav Feuerstein

ทางออกที่ดี! Android 8.0 / sdk 26 ApplicationInfo.loadIcon (แพคเกจผู้จัดการ pm) ส่งคืน AdaptiveIconDrawable 。ใช้รหัสของคุณสามารถช่วยฉันส่ง AdaptiveIconDrawable ไปเป็นบิตแมป。
burulangtu

43

วิธีที่ 1 : คุณสามารถแปลงเป็นบิตแมปแบบนี้ได้โดยตรง

Bitmap myLogo = BitmapFactory.decodeResource(context.getResources(), R.drawable.my_drawable);

วิธีที่ 2 : คุณสามารถแปลงทรัพยากรเป็นแบบวาดได้และจากนั้นคุณจะได้รับบิตแมปแบบนี้

Bitmap myLogo = ((BitmapDrawable)getResources().getDrawable(R.drawable.logo)).getBitmap();

สำหรับAPI> 22 getDrawableวิธีถูกย้ายไปที่ResourcesCompatคลาสเพื่อให้คุณทำสิ่งนี้

Bitmap myLogo = ((BitmapDrawable) ResourcesCompat.getDrawable(context.getResources(), R.drawable.logo, null)).getBitmap();

ResourcesCompat ใช้งานได้เฉพาะถ้า drawable เป็น BitmapDrawable ถ้าคุณใช้ VectorDrawable ดังนั้นคุณจะมี CCE
Brill Pappin

ไม่ทำงานกับทรัพยากรVectorDrawable ข้อผิดพลาดต่อไปนี้เกิดขึ้น -android.graphics.drawable.VectorDrawable cannot be cast to android.graphics.drawable.BitmapDrawable
Adam Hurwitz

วิธีนี้ใช้ได้ดีกับ Kotlin
Adam Hurwitz


15

ดังนั้นหลังจากดู (และใช้) คำตอบอื่น ๆ ดูเหมือนว่าพวกเขาจัดการColorDrawableและPaintDrawableไม่ดี (โดยเฉพาะอย่างยิ่งบนอมยิ้ม) ดูเหมือนว่าShaderมีการปรับแต่งเพื่อให้บล็อกสีทึบไม่ได้จัดการอย่างถูกต้อง

ฉันกำลังใช้รหัสต่อไปนี้ตอนนี้:

public static Bitmap drawableToBitmap(Drawable drawable) {
    if (drawable instanceof BitmapDrawable) {
        return ((BitmapDrawable) drawable).getBitmap();
    }

    // We ask for the bounds if they have been set as they would be most
    // correct, then we check we are  > 0
    final int width = !drawable.getBounds().isEmpty() ?
            drawable.getBounds().width() : drawable.getIntrinsicWidth();

    final int height = !drawable.getBounds().isEmpty() ?
            drawable.getBounds().height() : drawable.getIntrinsicHeight();

    // Now we check we are > 0
    final Bitmap bitmap = Bitmap.createBitmap(width <= 0 ? 1 : width, height <= 0 ? 1 : height,
            Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap);
    drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
    drawable.draw(canvas);

    return bitmap;
}

ซึ่งแตกต่างจากคนอื่น ๆ ถ้าคุณโทรsetBoundsในDrawableก่อนที่จะขอที่จะเปิดเป็นบิตแมปก็จะวาดบิตแมปที่ขนาดที่ถูกต้อง!


จะไม่ setBounds ทำลายขอบเขตก่อนหน้าของ drawable หรือไม่ จะดีกว่าหรือไม่ในการจัดเก็บและกู้คืนในภายหลัง?
นักพัฒนา android

@androiddeveloper หากมีการกำหนดขอบเขตเราก็แค่ใช้มันอยู่ดี ในบางกรณีจำเป็นต้องมีเมื่อไม่มีการตั้งค่าขอบเขตและไม่มีขนาดที่แท้จริง (เช่น ColorDrawables ในบางกรณี) ดังนั้นความกว้างและความสูงจะเป็น 0 เราให้ 1x1 ที่ดึงได้ด้วยวิธีที่มันวาดอะไรบางอย่าง ฉันอาจแย้งว่าเราสามารถตรวจสอบประเภทสำหรับ ColorDrawable ในกรณีเหล่านั้น แต่ใช้งานได้ 99% ของกรณี (คุณสามารถแก้ไขได้ตามความต้องการของคุณ)
Chris.Jenkins

@ Chris.Jenkins เกิดอะไรขึ้นถ้ามันไม่มีขอบเขตและตอนนี้มันจะได้รับใหม่ ฉันอยากถามคำถามอื่น: วิธีที่ดีที่สุดในการตั้งค่าขนาดบิตแมป (แม้สำหรับ BitmapDrawable) ที่ได้รับคืนคืออะไร
นักพัฒนา android

ฉันขอแนะนำให้คุณอ่านรหัสอย่างละเอียด ถ้าไม่ได้มีขอบเขตกำหนดจะใช้Drawable IntrinsicWidth/Heightหากทั้งคู่ <= 0 เราตั้งค่า canvas เป็น 1px คุณถูกต้องหากDrawableไม่มีขอบเขตมันจะถูกส่งผ่านบางส่วน (1x1 เป็นกรณีส่วนใหญ่) แต่สิ่งนี้จำเป็นสำหรับสิ่งColorDrawableที่ไม่ได้มีขนาดที่แท้จริง ถ้าเราไม่ทำเช่นนี้มันจะขว้างExceptionคุณไม่สามารถวาด 0x0 ลงบนผืนผ้าใบได้
Chris.Jenkins

1
mutate()จะทำสำเนาออกจาก drawable ต้นฉบับเพียงอย่างเดียวซึ่งจะลบล้างปัญหาของการส่งกลับในขอบเขตเดิม ฉันไม่ค่อยจะเปลี่ยนรหัสตามประเด็นเหล่านั้น หากกรณีการใช้งานของคุณต้องการมันจะเพิ่มคำตอบอื่น ฉันขอแนะนำให้คุณสร้างคำถามอื่นสำหรับมาตราส่วนบิตแมป
Chris.Jenkins

13

บางทีนี่อาจช่วยคน ...

จาก PictureDrawable เป็น Bitmap ให้ใช้:

private Bitmap pictureDrawableToBitmap(PictureDrawable pictureDrawable){ 
    Bitmap bmp = Bitmap.createBitmap(pictureDrawable.getIntrinsicWidth(), pictureDrawable.getIntrinsicHeight(), Config.ARGB_8888); 
    Canvas canvas = new Canvas(bmp); 
    canvas.drawPicture(pictureDrawable.getPicture()); 
    return bmp; 
}

... ดำเนินการเช่นนี้:

Bitmap bmp = pictureDrawableToBitmap((PictureDrawable) drawable);

เช่นเดียวกับคำตอบของร็อบคุณกำหนดประเภทเฉพาะของในกรณีนี้Drawable PictureDrawable
kabuko

4
"นี่อาจจะช่วยใครซักคน ... "
Mauro

11

นี่คือความละเอียดที่ดีกว่า

public static Bitmap drawableToBitmap (Drawable drawable) {
    if (drawable instanceof BitmapDrawable) {
        return ((BitmapDrawable)drawable).getBitmap();
    }

    Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap); 
    drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
    drawable.draw(canvas);

    return bitmap;
}

public static InputStream bitmapToInputStream(Bitmap bitmap) {
    int size = bitmap.getHeight() * bitmap.getRowBytes();
    ByteBuffer buffer = ByteBuffer.allocate(size);
    bitmap.copyPixelsToBuffer(buffer);
    return new ByteArrayInputStream(buffer.array());
}

รหัสจากวิธีการอ่านบิต drawable เป็น InputStream


11

1) drawable to Bitmap:

Bitmap mIcon = BitmapFactory.decodeResource(context.getResources(),R.drawable.icon);
// mImageView.setImageBitmap(mIcon);

2) บิตแมปถึง Drawable:

Drawable mDrawable = new BitmapDrawable(getResources(), bitmap);
// mImageView.setDrawable(mDrawable);

10

นี่คือรุ่น Kotlin ที่ดีของคำตอบที่ได้รับจาก @ Chris.Jenkins ที่นี่: https://stackoverflow.com/a/27543712/1016462

fun Drawable.toBitmap(): Bitmap {
  if (this is BitmapDrawable) {
    return bitmap
  }

  val width = if (bounds.isEmpty) intrinsicWidth else bounds.width()
  val height = if (bounds.isEmpty) intrinsicHeight else bounds.height()

  return Bitmap.createBitmap(width.nonZero(), height.nonZero(), Bitmap.Config.ARGB_8888).also {
    val canvas = Canvas(it)
    setBounds(0, 0, canvas.width, canvas.height)
    draw(canvas)
  }
}

private fun Int.nonZero() = if (this <= 0) 1 else this

9

android-ktx มีDrawable.toBitmapวิธีการ: https://android.github.io/android-ktx/core-ktx/androidx.graphics.drawable/android.graphics.drawable.-drawable/to-bitmap.html

จาก Kotlin

val bitmap = myDrawable.toBitmap()

นี่คือทางออกที่ง่ายที่สุดสำหรับVectorDrawableใน Kotlin! แชร์ในโพสต์ SO นี้ที่นี่ด้วยรายละเอียดเพิ่มเติม
Adam Hurwitz

8

Android BitmapDrawableให้การแก้ปัญหานอนที่ไม่ตรง ที่จะได้รับบิตแมปที่เราจะต้องให้ ID ทรัพยากรR.drawable.flower_picเพื่อที่แล้วโยนมันทิ้งไปBitmapDrawableBitmap

Bitmap bm = ((BitmapDrawable) getResources().getDrawable(R.drawable.flower_pic)).getBitmap();

5

ใช้รหัสนี้จะช่วยให้คุณบรรลุเป้าหมาย

 Bitmap bmp=BitmapFactory.decodeResource(getResources(), R.drawable.profileimage);
    if (bmp!=null) {
        Bitmap bitmap_round=getRoundedShape(bmp);
        if (bitmap_round!=null) {
            profileimage.setImageBitmap(bitmap_round);
        }
    }

  public Bitmap getRoundedShape(Bitmap scaleBitmapImage) {
    int targetWidth = 100;
    int targetHeight = 100;
    Bitmap targetBitmap = Bitmap.createBitmap(targetWidth, 
            targetHeight,Bitmap.Config.ARGB_8888);

    Canvas canvas = new Canvas(targetBitmap);
    Path path = new Path();
    path.addCircle(((float) targetWidth - 1) / 2,
            ((float) targetHeight - 1) / 2,
            (Math.min(((float) targetWidth), 
                    ((float) targetHeight)) / 2),
                    Path.Direction.CCW);

    canvas.clipPath(path);
    Bitmap sourceBitmap = scaleBitmapImage;
    canvas.drawBitmap(sourceBitmap, 
            new Rect(0, 0, sourceBitmap.getWidth(),
                    sourceBitmap.getHeight()), 
                    new Rect(0, 0, targetWidth, targetHeight), new Paint(Paint.FILTER_BITMAP_FLAG));
    return targetBitmap;
}

3

BitmapFactory.decodeResource()สเกลบิตแมปโดยอัตโนมัติดังนั้นบิตแมปของคุณอาจกลายเป็นคลุมเครือ เพื่อป้องกันการปรับขนาดให้ทำสิ่งนี้:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
Bitmap source = BitmapFactory.decodeResource(context.getResources(),
                                             R.drawable.resource_name, options);

หรือ

InputStream is = context.getResources().openRawResource(R.drawable.resource_name)
bitmap = BitmapFactory.decodeStream(is);

2

ถ้าคุณใช้ kotlin ให้ใช้โค้ดด้านล่าง มันจะทำงาน

// สำหรับการใช้เส้นทางภาพ

val image = Drawable.createFromPath(path)
val bitmap = (image as BitmapDrawable).bitmap


1
 // get image path from gallery
protected void onActivityResult(int requestCode, int resultcode, Intent intent) {
    super.onActivityResult(requestCode, resultcode, intent);

    if (requestCode == 1) {
        if (intent != null && resultcode == RESULT_OK) {             
            Uri selectedImage = intent.getData();

            String[] filePathColumn = {MediaStore.Images.Media.DATA};
            Cursor cursor = getContentResolver().query(selectedImage, filePathColumn, null, null, null);
            cursor.moveToFirst();
            int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
            filePath = cursor.getString(columnIndex);

            //display image using BitmapFactory

            cursor.close(); bmp = BitmapFactory.decodeFile(filepath); 
            iv.setBackgroundResource(0);
            iv.setImageBitmap(bmp);
        }
    }
}

ฉันคิดว่าคุณอ่านคำถามผิด คำถามที่ถาม: วิธีการรับบิตแมปจากทรัพยากร drawable ไม่ใช่แกลเลอรีของระบบ
kc ochibili

1

ImageWorker Library สามารถแปลงบิตแมปเป็น drawable หรือ base64 และในทางกลับกัน

val bitmap: Bitmap? = ImageWorker.convert().drawableToBitmap(sourceDrawable)

การดำเนินงาน

ในระดับโครงการ

allprojects {
        repositories {
            ...
            maven { url 'https://jitpack.io' }
        }
    }

ในระดับการสมัคร Gradle

dependencies {
            implementation 'com.github.1AboveAll:ImageWorker:0.51'
    }

คุณยังสามารถจัดเก็บและดึงภาพบิตแมป / drawables / base64 จากภายนอก

ตรวจสอบที่นี่ https://github.com/1AboveAll/ImageWorker/edit/master/README.md

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