Как преобразовать Drawable в растровое изображение?


950

Я хотел бы установить определенные Drawableв качестве обоев устройства, но все функции обоев принимают Bitmapтолько s. Я не могу использовать, WallpaperManagerпотому что я предварительно 2.1.

Кроме того, мои рисунки загружаются из Интернета и не находятся в R.drawable.



1
Пожалуйста, выберите правильный ответ, это: stackoverflow.com/a/3035869/4548520
user25

Ответы:


1290

Этот кусок кода помогает.

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. тогда мой отредактированный ответ должен помочь.
Правин

откуда берется str_url? Я не смог найти функцию Drawable, связанную со строками ... спасибо за вашу помощь.
Роб

12
Я думаю, что нашел что-то: если «draw» - это нарисованный объект, который я хочу преобразовать в растровое изображение, то: Bitmap bitmap = ((BitmapDrawable) draw) .getBitmap (); делает трюк!
Роб

1
@Rob: если ваш Drawable только BitmapDrawable. (что означает, что ваш Drawable - это всего лишь обертка вокруг растрового изображения)
njzk2

2
примечание: это вызывает массивный java.lang.OutOfMemoryError с JPG
Кто-то где-то

745
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
Мэтт Вулф

1
только одна поправка: docs говорит о BitmapDrawable.getBitmap (), что он может вернуться к нулю. Я говорю, что это может также вернуться уже переработано.
kellogs

16
Осторожно: getIntrinsicWidth()и getIntrinsicHieght()вернет -1, если рисуемый сплошной цвет.
SD

5
Итак ... еще одна проверка для ColorDrawable, и у нас есть победитель. Серьезно, кто-то делает это принятым ответом.
Кай

2
Вопреки помеченному ответу, это отвечает на вопрос.
njzk2

214

Это преобразует BitmapDrawable в Bitmap.

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

9
это действительно лучший способ? Конечно, drawable может быть другого типа, и это вызовет исключение runtimeException? Например, это может быть ninePatchDrawble ...?
Дори

4
@ Дори, вы можете обернуть код в условный оператор, чтобы проверить, действительно ли он BitmapDrawableперед тем, как его разыграть : if (d instanceof BitmapDrawable) { Bitmap bitmap = ((BitmapDrawable)d).getBitmap(); }
Тони Чан,

367
Не можете поверить, 64 голосов? Этот код , очевидно , работает , только если dуже естьBitmapDrawable , в этом случае это тривиально , чтобы получить его как растровое изображение ... Будет ли столкновение с ClassCastExceptionво всех остальных случаях.
Матиас

3
@Matthias, не говоря уже о том, что ... сам вопрос, тот же автор, имеет 100 голосов: /
quinestor

2
Это так специализируется на тривиальном случае.
njzk2

141

Drawable может быть нарисован на a Canvas, а a 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;
}

Что произойдет, если drawable param будет нулевым?
hrules6872

1
Этот метод не поддерживает VectorDrawable
Махмуд


Предполагая, что вы получаете непустой Drawable, почему нужно проверить, что ширина и высота не равны 0? Кроме того, зачем вам нужно использовать setBounds (), если они одного размера?
Йоав

Хорошее решение! Android 8.0 / sdk 26 ApplicationInfo.loadIcon (PackageManager pm) возвращает AdaptiveIconDrawable。 Использование вашего кода может помочь мне привести AdaptiveIconDrawable к растровому изображению。
burulangtu

45

МЕТОД 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 работает только в том случае, если объект рисования является BitmapDrawable, если вы используете VectorDrawable, то у вас будет CCE.
Брилл Паппин

Ни один из них не работает с ресурсом VectorDrawable . Возникает следующая ошибкаandroid.graphics.drawable.VectorDrawable cannot be cast to android.graphics.drawable.BitmapDrawable
Адам Гурвиц

Это решение хорошо работает с Kotlin.
Адам Гурвиц


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 не разрушит предыдущие границы отрисовки? Не лучше ли хранить его и восстанавливать потом?
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);

Как и в случае с ответом Роба, вам требуется определенный тип Drawable, в данном случае a PictureDrawable.
Кабуко

4
«Может быть, это кому-то поможет ...»
Мауро

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

Вот хорошая версия ответа от 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


8

Android обеспечивает не прямое решение Foward: BitmapDrawable. Чтобы получить растровое изображение, мы должны предоставить идентификатор ресурса R.drawable.flower_picдля a, BitmapDrawableа затем привести его к a Bitmap.

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

5

Используйте этот code.it поможет вам в достижении вашей цели.

 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

1

Библиотека ImageWorker может конвертировать растровое изображение в drawable или base64 и наоборот.

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

Реализация

На уровне проекта Gradle

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

На уровне приложения Gradle

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

Вы также можете хранить и извлекать растровые изображения / рисованные изображения / изображения base64 из внешних источников.

Проверьте здесь. https://github.com/1AboveAll/ImageWorker/edit/master/README.md

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.