如何将Drawable转换为位图?


947

我想将某个设置Drawable为设备的墙纸,但所有墙纸功能Bitmap仅接受。我无法使用,WallpaperManager因为我是2.1之前的版本。

另外,我的可绘制对象是从网络下载的,并不位于中R.drawable



1
请选择正确的答案,这是:stackoverflow.com/a/3035869/4548520
user25 2013年

Answers:


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函数...感谢您的帮助。
罗布2010年

12
我想我发现了一些东西:如果“ draw”是我想转换为位图的可绘制对象,则:Bitmap bitmap =((BitmapDrawable)draw).getBitmap(); 绝招!
罗布2010年

1
@Rob:如果您的Drawable仅是BitmapDrawable。(实际上,这意味着您的Drawable只是一个位图的包装)
njzk2

2
注意:这会导致带有JPG的大量java.lang.OutOfMemoryError
某处某人

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
这看起来像是对任何可绘制对象都适用的唯一答案,并且对于已为BitmapDrawable的可绘制对象提供了快速解决方案。+1
Matt Wolfe

1
只是一项修正:文档说到BitmapDrawable.getBitmap()可能会返回null。我说它也可能回来了,已经回收了。
kellogs's

16
注意:如果drawable是纯色getIntrinsicWidth()getIntrinsicHieght()它将返回-1。
SD

5
所以... ColorDrawable的另一张支票,我们有一个赢家。认真地说,有人将其作为可接受的答案。
kaay 2013年

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

367
不敢相信这64个投票?该代码显然仅在d已经 a的BitmapDrawable情况下才有效,在这种情况下,将其作为位图进行检索很简单…… ClassCastException在所有其他情况下都会崩溃。
Matthias

3
@Matthias更不用说..问题本身,同一位作者,拥有100票:/
quinestor 2012年

2
这对于琐碎的案件是如此专门。
njzk2

141

一个Drawable可以拉伸到Canvas,并且Canvas可以支持通过Bitmap

(已更新,以处理的快速转换BitmapDrawable并确保所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;
}

如果可绘制参数为null,会发生什么?
hrules6872 '02

1
此方法不支持VectorDrawable
Mahmoud,


假设您获得一个非空的Drawable,为什么需要检查宽度和高度不是0?另外,如果它们的大小相同,为什么还要使用setBounds()?
Yoav Feuerstein

好的解决方案!Android 8.0 / sdk 26 ApplicationInfo.loadIcon(PackageManager pm)返回AdaptiveIconDrawable。使用您的代码可以帮助我将AdaptiveIconDrawable
强制转换

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

只有可绘制对象是BitmapDrawable时,ResourcesCompat才有效;如果使用VectorDrawable,则将具有CCE。
Brill Pappin

这些都不使用VectorDrawable资源。发生以下错误android.graphics.drawable.VectorDrawable cannot be cast to android.graphics.drawable.BitmapDrawable
Adam Hurwitz

解决方案在Kotlin上很好用。
亚当·赫维兹


15

所以其他的答案中寻找(并使用)之后,他们似乎都处理ColorDrawablePaintDrawable严重。(特别是在棒棒糖上)似乎已对Shaders进行了调整,因此未正确处理纯色块。

我现在正在使用以下代码:

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

不像其他人,如果你拨打setBoundsDrawable要求把它变成一个位图前,将以此为位图以正确的尺寸!


setBounds是否会破坏可绘制对象的先前边界?将其存储并随后还原是否更好?
Android开发人员

@androiddeveloper,如果设置了边界,无论如何我们都在使用边界。在某些情况下,这需要在没有设置边界且没有固有大小的情况下进行(例如在某些情况下为ColorDrawables)。因此,宽度和高度将为0,我们为可绘制对象1x1提供实际绘制对象的方式。我可能会争辩说在这种情况下我们可以对ColorDrawable进行类型检查,但这在99%的情况下都有效。(您可以根据需要对其进行修改)。
克里斯·詹金斯(Chris.Jenkins)

@ Chris.Jenkins如果没有界限怎么办,现在它将得到新的界限?我还想问另一个问题:设置返回的位图大小(甚至对于BitmapDrawable)的最佳方法是什么?
android开发人员

我建议您仔细阅读代码。如果Drawable没有设置边界,则使用IntrinsicWidth/Height。如果它们均<= 0,则将画布设置为1px。您是正确的,如果Drawable没有界限,它将通过一些(大多数情况下为1x1),但这对于诸如ColorDrawable没有固有尺寸的事情是必需的。如果我们不这样做,它将抛出一个Exception,您将无法在画布上绘制0x0。
克里斯·詹金斯(Chris.Jenkins)

1
mutate()会制作一个副本,而将原始可绘制对象保留下来,这将消除在原始范围内传回的问题。我很少根据这些观点来更改代码。如果您的用例需要它,请添加另一个答案。我建议您为位图缩放创建另一个问题。
克里斯·詹金斯(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);

与Rob的答案一样,您需要特定类型的Drawable,在这种情况下为PictureDrawable
kabuko

4
“也许这会帮助某人……”
毛罗(Mauro)2012年

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

从代码如何阅读绘制位为InputStream的


11

1)可绘制到位图:

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

2)位图到Drawable:

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

10

这是@ Chris.Jenkins在这里提供的答案的不错的Kotlin版本: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

8

Android提供了一种非直截了当的解决方案:BitmapDrawable。要获取位图,我们必须将资源ID提供R.drawable.flower_pic给a BitmapDrawable,然后将其转换为a Bitmap

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

8

android-ktx具有Drawable.toBitmap方法:https : //android.github.io/android-ktx/core-ktx/androidx.graphics.drawable/android.graphics.drawable.-drawable/to-bitmap.html

从科特林

val bitmap = myDrawable.toBitmap()

这是VectorDrawableKotlin中最简单的解决方案!在本文的SO帖子中也有详细分享。
亚当·赫维兹

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

我认为您看错了这个问题。问题问:如何从可绘制资源而不是系统库中获取位图
kc ochibili 2014年

1

ImageWorker库可以将位图转换为drawable或base64,反之亦然。

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

实作

在项目级别Gradle中

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

在应用程序级别中

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

您还可以从外部存储和检索位图/可绘制对象/ base64图像。

在这里检查。https://github.com/1AboveAll/ImageWorker/edit/master/README.md

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.