Получение растрового изображения из векторного рисунка
В моем приложении я должен установить большой значок для уведомления.
LargeIcon должен быть растровым, а мои чертежи - векторные изображения (новая функция в Android, см. эту ссылку)
Проблема в том, что когда я пытаюсь декодировать ресурс, являющийся векторным изображением, я возвращаю null.
Вот пример кода:
if (BitmapFactory.decodeResource(arg0.getResources(), R.drawable.vector_menu_objectifs) == null)
Log.d("ISNULL", "NULL");
else
Log.d("ISNULL", "NOT NULL");
В этом примере, когда я заменяю R.drawable.vector_menu_objectifs на "нормальное" изображение, например png, результат не равен null (я получаю правильное растровое изображение)
Что-то мне не хватает?
Ответы
Ответ 1
Проверено на 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;
}
UPDATE:
Проект gradle:
dependencies {
classpath 'com.android.tools.build:gradle:2.2.0-alpha5'
}
Модуль gradle:
android {
compileSdkVersion 23
buildToolsVersion '23.0.3'
defaultConfig {
minSdkVersion 16
targetSdkVersion 23
vectorDrawables.useSupportLibrary = true
}
...
}
...
Ответ 2
Вы можете использовать следующий метод:
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private static Bitmap getBitmap(VectorDrawable vectorDrawable) {
Bitmap bitmap = Bitmap.createBitmap(vectorDrawable.getIntrinsicWidth(),
vectorDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
vectorDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
vectorDrawable.draw(canvas);
return bitmap;
}
который я иногда совмещаю с:
private static Bitmap getBitmap(Context context, int drawableId) {
Drawable drawable = ContextCompat.getDrawable(context, drawableId);
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
} else if (drawable instanceof VectorDrawable) {
return getBitmap((VectorDrawable) drawable);
} else {
throw new IllegalArgumentException("unsupported drawable type");
}
}
Ответ 3
Основываясь на предыдущих ответах, его можно упростить таким образом, чтобы он соответствовал как 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
}
}
В пре-Lollipop он будет использовать VectorDrawableCompat, а в Lollipop - VectorDrawable.
РЕДАКТИРОВАТЬ
Я отредактировал условие после комментария @user3109468
Ответ 4
Если вы хотите использовать Android KTX для Kotlin, вы можете использовать метод расширения Drawable#toBitmap()
для достижения того же эффекта, что и в других ответах:
val bitmap = AppCompatResources.getDrawable(requireContext(), drawableId).toBitmap()
или
val bitmap = AppCompatResources.getDrawable(context, drawableId).toBitmap()
Чтобы добавить этот и другие полезные методы расширения, вам нужно добавить следующее на уровень вашего модуля build.gradle
repositories {
google()
}
dependencies {
implementation 'androidx.core:core-ktx:1.0.0-alpha1'
}
Обратите внимание, что это будет работать для любого подкласса Drawable
, и если Drawable
является BitmapDrawable
, он будет использовать ярлык для использования базового Bitmap
.
Ответ 5
Слава @Alexey
Вот версия Kotlin
использующая расширения к Context
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
}
Пример использования в Activity
:
val bitmap = this.getBitmapFromVectorDrawable(R.drawable.ic_done_white_24dp)
Ответ 6
Drawable layerDrawable = (Drawable) imageBase.getDrawable();
Bitmap bitmap = Bitmap.createBitmap(layerDrawable.getIntrinsicWidth(),
layerDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
layerDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
layerDrawable.draw(canvas);
imageTeste.setImageBitmap(addGradient(bitmap));
Ответ 7
Если ваше vector
изображение intrinsicWidth
и intrinsicHeight
невелико и вы пытаетесь отобразить растровое изображение в большом виде, то вы увидите, что в результате получается размытое изображение.
В этом случае вы можете предоставить новую ширину/высоту для вашего растрового изображения, чтобы получить более качественное изображение (или вы можете увеличить размер вектора в xml, но предоставить desireWidth
и desireHeight
могут быть более гибкими).
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
}
Надеюсь, это поможет
Ответ 8
Если вы хотите иметь возможность масштабировать вывод до желаемого размера вывода, попробуйте следующий фрагмент:
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)
Ответ 9
Проверено на API 16 - JellyBean с векторной графикой
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;
Спасибо всем!