【问题标题】:How to convert a Drawable to a Bitmap?如何将 Drawable 转换为位图?
【发布时间】:2011-03-03 10:00:37
【问题描述】:

我想设置某个Drawable作为设备的壁纸,但所有壁纸功能只接受Bitmaps。我不能使用WallpaperManager,因为我是 2.1 之前的版本。

另外,我的drawables是从网上下载的,不驻留在R.drawable

【问题讨论】:

标签: android bitmap wallpaper android-drawable


【解决方案1】:

我在这个线程上使用了一些答案,但其中一些没有按预期工作(也许他们在旧版本中工作过)但我想在几次尝试和错误后分享我的答案,使用扩展功能:

val markerOption = MarkerOptions().apply {
    position(LatLng(driver.lat, driver.lng))
    icon(R.drawabel.your_drawable.toBitmapDescriptor(context))
    snippet(driver.driverId.toString())
}
mMap.addMarker(markerOption)

这是扩展功能:

fun Int.toBitmapDescriptor(context: Context): BitmapDescriptor {
    val vectorDrawable = ResourcesCompat.getDrawable(context.resources, this, context.theme)
    val bitmap = vectorDrawable?.toBitmap(
        vectorDrawable.intrinsicWidth,
        vectorDrawable.intrinsicHeight,
        Bitmap.Config.ARGB_8888
    )
    return BitmapDescriptorFactory.fromBitmap(bitmap!!)
}

【讨论】:

    【解决方案2】:

    1) 可绘制到位图:

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

    2) 位图到 Drawable :

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

    【讨论】:

      【解决方案3】:

      位图位图 = BitmapFactory.decodeResource(context.getResources(), R.drawable.icon);

      这不会每次都起作用,例如,如果您的可绘制对象是图层列表可绘制对象,那么它会给出空响应,因此您需要将可绘制对象绘制到画布中然后保存为位图,请参考下面的一段代码。

      public void drawableToBitMap(Context context, int drawable, int widthPixels, int heightPixels) {
          try {
              File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/", "drawable.png");
              FileOutputStream fOut = new FileOutputStream(file);
              Drawable drw = ResourcesCompat.getDrawable(context.getResources(), drawable, null);
              if (drw != null) {
                  convertToBitmap(drw, widthPixels, heightPixels).compress(Bitmap.CompressFormat.PNG, 100, fOut);
              }
              fOut.flush();
              fOut.close();
          } catch (Exception e) {
              e.printStackTrace();
          }
      }
      
      private Bitmap convertToBitmap(Drawable drawable, int widthPixels, int heightPixels) {
          Bitmap bitmap = Bitmap.createBitmap(widthPixels, heightPixels, Bitmap.Config.ARGB_8888);
          Canvas canvas = new Canvas(bitmap);
          drawable.setBounds(0, 0, widthPixels, heightPixels);
          drawable.draw(canvas);
          return bitmap;
      }
      

      以上代码将你的可绘制文件保存为下载目录中的drawable.png

      【讨论】:

        【解决方案4】:

        最新的 androidx 核心库 (androidx.core:core-ktx:1.2.0) 现在有一个 extension function: Drawable.toBitmap(...) 用于将 Drawable 转换为 Bitmap。

        【讨论】:

        • 我不太明白如何导入该函数。我认为它也可以在 Kotlin 之外运行?
        • 从java中,需要导入包含扩展方法的Kt文件。此外,签名稍微复杂一些,因为接收者和默认参数在 java 中不可用。会是这样的:DrawableKt.toBitmap(...);
        【解决方案5】:

        如果您使用的是 kotlin,请使用以下代码。它会工作的

        // 使用图片路径

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

        【讨论】:

          【解决方案6】:

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

          【讨论】:

            【解决方案7】:

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

            【讨论】:

            • 这是 Kotlin 中 VectorDrawable 最简单的解决方案!还更详细地分享了@98​​7654322@。
            • 我从这个方法得到一个空白位图。
            【解决方案8】:

            方法一:或者你可以像这样直接转换成位图

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

            方法2:你甚至可以将资源转换为drawable,然后你可以得到像这样的位图

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

            对于 API > 22getDrawable 方法移至 ResourcesCompat 类,以便您执行类似的操作

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

            【讨论】:

            • ResourcesCompat 仅在 drawable 是 BitmapDrawable 时有效,如果您使用 VectorDrawable,那么您将拥有一个 CCE。
            • 这些都不适用于 VectorDrawable 资源。出现以下错误 - android.graphics.drawable.VectorDrawable cannot be cast to android.graphics.drawable.BitmapDrawable
            • 这个solution 与 Kotlin 配合得很好。
            【解决方案9】:

            ImageWorker 库可以将位图转换为可绘制或 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'
                }
            

            您还可以从外部存储和检索位图/drawables/base64 图像。

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

            【讨论】:

              【解决方案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
              

              【讨论】:

                【解决方案11】:

                这段代码有帮助。

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

                【讨论】:

                • 我认为你有 url 值。那么我编辑的答案应该会有所帮助。
                • 我想我找到了一些东西:如果“draw”是我想要转换为位图的drawable,那么:Bitmap bitmap = ((BitmapDrawable)draw).getBitmap();成功了!
                • @Rob : 如果你的 Drawable 只是 BitmapDrawable。 (这意味着您的 Drawable 实际上只是位图的一个包装器)
                • 注意:这会导致 JPG 的大量 java.lang.OutOfMemoryError
                • 这不适用于 svg。 BitmapFactory.decodeResource()返回null
                【解决方案12】:
                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;
                }
                

                【讨论】:

                • 这看起来是唯一适用于任何类型的drawable的答案,并且对于已经是BitmapDrawable的drawable也有一个快速的解决方案。 +1
                • 只是一个修正:文档说 BitmapDrawable.getBitmap() 它可能会返回 null。我说它也可能已经回收了。
                • 注意:如果 drawable 是纯色,getIntrinsicWidth()getIntrinsicHieght() 将返回 -1。
                • 所以...再次检查 ColorDrawable,我们有一个赢家。说真的,有人将此作为公认的答案。
                • 与标记的答案相反,这回答了问题。
                【解决方案13】:
                 // 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);
                        }
                    }
                }
                

                【讨论】:

                • 我认为你读错了这个问题。问题问:如何从可绘制资源而不是系统图库中获取位图
                【解决方案14】:

                因此,在查看(和使用)其他答案之后,似乎他们都处理不好 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;
                }
                

                与其他人不同,如果您在要求将其转换为位图之前在Drawable 上调用setBounds,它将以正确的大小绘制位图!

                【讨论】:

                • setBounds 不会破坏之前的可绘制边界吗?储存起来再恢复不是更好吗?
                • @androiddeveloper,如果已经设置了边界,那么无论如何我们都在使用它们。在某些情况下,如果没有设置边界并且没有固有大小(例如某些情况下的 ColorDrawables),则需要这样做。所以宽度和高度将是 0,我们给可绘制 1x1 以它实际绘制某些东西的方式。我可以说我们可以在这些情况下对 ColorDrawable 进行类型检查,但这适用于 99% 的情况。 (您可以根据需要对其进行修改)。
                • @Chris.Jenkins 如果它没有边界怎么办,现在它会得到新的?我还想问另一个问题:设置返回的位图大小(即使是 BitmapDrawable)的最佳方法是什么?
                • 建议您仔细阅读代码。如果Drawable 没有设置边界,则使用IntrinsicWidth/Height。如果它们都 Drawable 没有界限,那么您是正确的,它将被传递一些(大多数情况下是1x1),但是对于没有内在大小的ColorDrawable 之类的东西,这是必需的。如果我们不这样做,它会抛出一个Exception,你不能在画布上绘制 0x0。
                • mutate() 会制作一个副本,只保留原始可绘制对象,这将消除在原始边界内传回的问题。我很少根据这些点更改代码。如果您的用例需要,请添加另一个答案。我建议您为位图缩放创建另一个问题。
                【解决方案15】:

                使用此代码。它将帮助您实现目标。

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

                【讨论】:

                  【解决方案16】:

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

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

                  【讨论】:

                    【解决方案17】:

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

                    【讨论】:

                    • 如果可绘制参数为空会怎样?
                    • 此方法不支持 VectorDrawable
                    • 假设你得到一个非空的Drawable,为什么需要检查宽度和高度不是0?另外,如果它们的大小相同,为什么还需要使用 setBounds()?
                    • 很好的解决方案!Android 8.0 /sdk 26 ApplicationInfo.loadIcon(PackageManager pm) return a AdaptiveIconDrawable 。使用你的代码可以帮助我将 AdaptiveIconDrawable 转换为位图。
                    【解决方案18】:

                    这里有更好的分辨率

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

                    来自How to read drawable bits as InputStream的代码

                    【讨论】:

                      【解决方案19】:

                      很简单

                      Bitmap tempBMP = BitmapFactory.decodeResource(getResources(),R.drawable.image);
                      

                      【讨论】:

                      【解决方案20】:

                      这会将 BitmapDrawable 转换为 Bitmap。

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

                      【讨论】:

                      • 这真的是最好的方法吗?当然drawable可能是另一种类型,这会抛出runtimeException吗?例如它可能是一个 NinePatchDrawble...?
                      • @Dori 您可以将代码包装在条件语句中,以在转换之前检查它是否确实是 BitmapDrawableif (d instanceof BitmapDrawable) { Bitmap bitmap = ((BitmapDrawable)d).getBitmap(); }
                      • 不敢相信这 64 票?该代码显然只有在d 已经 BitmapDrawable 时才有效,在这种情况下,将其作为位图检索很简单......在所有其他情况下都会与ClassCastException 一起崩溃。跨度>
                      • @Matthias 更不用说......问题本身,同一作者,有 100 票:/
                      • 这对于一个琐碎的案例来说是如此专业。
                      【解决方案21】:

                      也许这会对某人有所帮助...

                      从 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
                      • “也许这会对某人有所帮助……”
                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 2019-12-17
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多