Android 从矢量绘制中获取位图

Android 从矢量绘制中获取位图,android,bitmap,android-drawable,android-vectordrawable,Android,Bitmap,Android Drawable,Android Vectordrawable,在我的应用程序中,我必须为通知设置一个大图标。 LargeIcon必须是位图,而我的绘图是矢量图像(Android的新功能,请参阅) 问题是,当我试图解码一个矢量图像资源时,返回的是空值 以下是代码示例: if (BitmapFactory.decodeResource(arg0.getResources(), R.drawable.vector_menu_objectifs) == null) Log.d("ISNULL", "NULL"); else

在我的应用程序中,我必须为通知设置一个大图标。 LargeIcon必须是位图,而我的绘图是矢量图像(Android的新功能,请参阅) 问题是,当我试图解码一个矢量图像资源时,返回的是空值

以下是代码示例:

if (BitmapFactory.decodeResource(arg0.getResources(), R.drawable.vector_menu_objectifs) == null)
        Log.d("ISNULL", "NULL");
    else
        Log.d("ISNULL", "NOT NULL");
在本示例中,当我用“正常”图像(例如png)替换R.drawable.vector_menu_objectif时,结果不是空的(我得到了正确的位图)
我有什么遗漏吗?

您可以使用以下方法:

@TargetApi(Build.VERSION\u CODES.LOLLIPOP)
私有静态位图getBitmap(矢量可绘制矢量可绘制){
位图位图=位图.createBitmap(vectorDrawable.getIntrinsicWidth(),
vectorDrawable.getIntrinsicHeight(),Bitmap.Config.ARGB_8888);
画布=新画布(位图);
vectorDrawable.setBounds(0,0,canvas.getWidth(),canvas.getHeight());
矢量可绘制。绘制(画布);
返回位图;
}
我有时会结合:

私有静态位图getBitmap(上下文上下文,int-drawableId){
Drawable Drawable=ContextCompat.getDrawable(上下文,drawableId);
if(BitmapDrawable的可绘制实例){
返回((BitmapDrawable)drawable.getBitmap();

}else if(矢量可绘制的可绘制实例){ 返回getBitmap((VectorDrawable)drawable); }否则{ 抛出新的IllegalArgumentException(“不支持的可绘制类型”); } }
检查API:17、21、23

public static Bitmap getBitmapFromVectorDrawable(Context context, int drawableId) {
    Drawable drawable = ContextCompat.getDrawable(context, drawableId);
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
        drawable = (DrawableCompat.wrap(drawable)).mutate();
    }

    Bitmap 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;
}
模块梯度:

android {
    compileSdkVersion 23
    buildToolsVersion '23.0.3'
    defaultConfig {
        minSdkVersion 16
        targetSdkVersion 23
        vectorDrawables.useSupportLibrary = true
    }
    ...
}
...

基于前面的答案,它可以简化为与VectorDrawable和BitmapDrawable匹配,并且至少与API 15兼容

public static Bitmap getBitmapFromDrawable(Context context, @DrawableRes int drawableId) {
    Drawable drawable = AppCompatResources.getDrawable(context, drawableId);

    if (drawable instanceof BitmapDrawable) {
        return ((BitmapDrawable) drawable).getBitmap();
    } else if (drawable instanceof VectorDrawableCompat || drawable instanceof VectorDrawable) {
        Bitmap 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;
    } else {
        throw new IllegalArgumentException("unsupported drawable type");
    }
}
然后,您必须在gradle文件中添加:

android {
    defaultConfig {
        vectorDrawables.useSupportLibrary = true
    }
}
在pre-Lollipop上使用VectorDrawable Compat,在Lollipop上使用VectorDrawable

编辑 我已经编辑了@user3109468注释之后的条件

编辑2(10/2020) 至少在API 21中,您现在可以使用此代码而不是上面的代码(我没有在以前的API版本上尝试过):

尊敬@Alexey

下面是使用
上下文扩展的
Kotlin
版本

fun Context.getBitmapFromVectorDrawable(drawableId: Int): Bitmap? {
    var drawable = ContextCompat.getDrawable(this, drawableId) ?: return null

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
        drawable = DrawableCompat.wrap(drawable).mutate()
    }

    val bitmap = Bitmap.createBitmap(
            drawable.intrinsicWidth,
            drawable.intrinsicHeight,
            Bitmap.Config.ARGB_8888) ?: return null
    val canvas = Canvas(bitmap)
    drawable.setBounds(0, 0, canvas.width, canvas.height)
    drawable.draw(canvas)

    return bitmap
}
如果您愿意使用Kotlin,您可以使用扩展方法
Drawable#toBitmap()
实现与其他答案相同的效果:

val bitmap = AppCompatResources.getDrawable(requireContext(), drawableId).toBitmap() 

要添加此扩展方法和其他有用的扩展方法,您需要将以下内容添加到模块级
build.gradle

repositories {
    google()
}

dependencies {
    implementation "androidx.core:core-ktx:1.2.0"
}
有关将依赖项添加到项目的最新说明,请参见


请注意,这将适用于
Drawable
的任何子类,如果
Drawable
BitmapDrawable
的子类,并且如果
向量
图像
内部宽度
内部八度
较小,并且您尝试将位图显示为较大的值,则将使用底层
位图的快捷方式视图,然后您将看到结果是模糊的

在这种情况下,您可以为位图提供新的宽度/高度以获得更好的图像(或者您可以增加xml中的向量大小,但提供
desireWidth
desireHeight
可能更灵活)


希望对您有所帮助

如果您希望能够将输出缩放到所需的输出大小,请尝试以下代码片段:

fun getBitmapFromVectorDrawable(context: Context, drawableId: Int, outputSize: OutputSize? = null): Bitmap? {
    var drawable = ContextCompat.getDrawable(context, drawableId) ?: return null
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
        drawable = DrawableCompat.wrap(drawable).mutate()
    }

    var targetBitmap: Bitmap
    if (outputSize != null) {
        targetBitmap = Bitmap.createBitmap(outputSize.width,
                outputSize.height, Bitmap.Config.ARGB_8888)
    } else {
        targetBitmap = Bitmap.createBitmap(drawable.intrinsicWidth,
            drawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
    }

    val canvas = Canvas(targetBitmap)
    val scaleX =  targetBitmap.width.toFloat()/drawable.intrinsicWidth.toFloat()
    val scaleY =  targetBitmap.height.toFloat()/drawable.intrinsicHeight.toFloat()
    canvas.scale(scaleX, scaleY)
    drawable.draw(canvas)

    return targetBitmap
}

class OutputSize(val width: Int, val height: Int)
fun getBitmapFromVectorDrawable(上下文:context,drawableId:Int,outputSize:outputSize?=null):位图?{
var drawable=ContextCompat.getDrawable(context,drawableId)?:返回null
if(Build.VERSION.SDK\u INT
在API 16上测试-带矢量绘图功能的果冻豆

public static Bitmap getBitmapFromVectorDrawable(Context context, int drawableId) {
    Drawable drawable = AppCompatResources.getDrawable(context, drawableId);
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
        drawable = (DrawableCompat.wrap(drawable)).mutate();
    }

    Bitmap 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;
}   
公共静态位图getBitmapFromVectorDrawable(上下文,int-drawableId){
Drawable Drawable=AppCompatResources.getDrawable(上下文,drawableId);
if(Build.VERSION.SDK\u INT
使用以下代码转换具有正确纵横比的图像(例如,用于通知图标):

公共静态位图getBitmapFromVector(上下文,int-drawableId){
Drawable Drawable=ContextCompat.getDrawable(上下文,drawableId);
int width=drawable.getIntrinsicWidth();
int height=drawable.getIntrinsicHeight();
位图;
如果(宽度<高度){//做一个正方形
bitmap=bitmap.createBitmap(高度、高度、bitmap.Config.ARGB_8888);
}否则{
bitmap=bitmap.createBitmap(宽度、宽度、bitmap.Config.ARGB_8888);
}
画布=新画布(位图);
可拉深。缩位(0,0,0,
drawable.getIntrinsicWidth(),//使用drawable的维度
drawable.getIntrinsicHeight()
);
可绘制。绘制(画布);
返回位图;
}

这将为您提供所需大小的位图。此外,它还允许您根据每个图像保持或不保持透明度,以提高图像的性能
val bitmap = AppCompatResources.getDrawable(requireContext(), drawableId).toBitmap() 
val bitmap = AppCompatResources.getDrawable(context, drawableId).toBitmap() 
repositories {
    google()
}

dependencies {
    implementation "androidx.core:core-ktx:1.2.0"
}
private fun getBitmap(drawableId: Int, desireWidth: Int? = null, desireHeight: Int? = null): Bitmap? {
    val drawable = AppCompatResources.getDrawable(context, drawableId) ?: return null
    val bitmap = Bitmap.createBitmap(
        desireWidth ?: drawable.intrinsicWidth,
        desireHeight ?: drawable.intrinsicHeight,
        Bitmap.Config.ARGB_8888
    )
    val canvas = Canvas(bitmap)
    drawable.setBounds(0, 0, canvas.width, canvas.height)
    drawable.draw(canvas)
    return bitmap
}
fun getBitmapFromVectorDrawable(context: Context, drawableId: Int, outputSize: OutputSize? = null): Bitmap? {
    var drawable = ContextCompat.getDrawable(context, drawableId) ?: return null
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
        drawable = DrawableCompat.wrap(drawable).mutate()
    }

    var targetBitmap: Bitmap
    if (outputSize != null) {
        targetBitmap = Bitmap.createBitmap(outputSize.width,
                outputSize.height, Bitmap.Config.ARGB_8888)
    } else {
        targetBitmap = Bitmap.createBitmap(drawable.intrinsicWidth,
            drawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
    }

    val canvas = Canvas(targetBitmap)
    val scaleX =  targetBitmap.width.toFloat()/drawable.intrinsicWidth.toFloat()
    val scaleY =  targetBitmap.height.toFloat()/drawable.intrinsicHeight.toFloat()
    canvas.scale(scaleX, scaleY)
    drawable.draw(canvas)

    return targetBitmap
}

class OutputSize(val width: Int, val height: Int)
public static Bitmap getBitmapFromVectorDrawable(Context context, int drawableId) {
    Drawable drawable = AppCompatResources.getDrawable(context, drawableId);
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
        drawable = (DrawableCompat.wrap(drawable)).mutate();
    }

    Bitmap 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;
}   
public static Bitmap getBitmapFromVector(Context context, int drawableId) {
    Drawable drawable = ContextCompat.getDrawable(context, drawableId);
    int width = drawable.getIntrinsicWidth();
    int height = drawable.getIntrinsicHeight();
    Bitmap bitmap;
    if (width < height) {    //make a square
        bitmap = Bitmap.createBitmap(height, height, Bitmap.Config.ARGB_8888);
    } else {
        bitmap = Bitmap.createBitmap(width, width, Bitmap.Config.ARGB_8888);
    }
    Canvas canvas = new Canvas(bitmap);
    drawable.setBounds(0, 0,
            drawable.getIntrinsicWidth(),    //use dimensions of Drawable
            drawable.getIntrinsicHeight()
    );
    drawable.draw(canvas);
    return bitmap;
}
public static Bitmap drawableToBitmap(Resources res, int drawableId,
        int width, int height, boolean keepAlpha) {
    Drawable drawable = res.getDrawable(drawableId);
    Bitmap bmp = createBitmap(width, height, keepAlpha ?
            Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565);
    Canvas cvs = new Canvas(bmp);
    drawable.setBounds(0, 0, width, height);
    drawable.draw(cvs);
    return bmp;
}
@Nullable
public static Bitmap drawableToBitmap(Context context, int drawableId) {
    Drawable drawable = ContextCompat.getDrawable(context, drawableId);
    if (drawable != null) {
        int width = drawable.getIntrinsicWidth();
        int height = drawable.getIntrinsicHeight();
        Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bmp);
        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
        drawable.draw(canvas);
        return bmp;
    }
    return null;
}