Android Bitmap——基本使用及压缩、颜色质量、bitmap内存空间复用

  • 实例化对象
  • Bitmap对象大小和像素大小
  • BitmapFactory.Options

如何实例化对象

  1. Bitmap文档
    Bitmap提供了一系列的createXX方法,可以通过:Bitmap、DisplayMetrics、Picture、RGB的颜色数组等得到一个Bitmap对象。
  2. BitmapFactory提供了一系列的decodeXX方法。流行、文件、资源等得到一个Bitmap对象。

示例:

bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.car);
...
bitmap = Bitmap.createBitmap(BitmapFactory.decodeResource(getResources(),R.drawable.car));

一般通过Bitmap创建的话需要先事先有一个Bitmap对象,或者通过自己指定一些像素属性。
BitmapFactory基本用语将一个图片资源变为解码成Bitmap对象。

Bitmap对象大小和像素大小。

/**
     * 返回Bitmap对象像素所占内存大小
     *
     * <p>As of {@link android.os.Build.VERSION_CODES#KITKAT}, the result of this method can
     * no longer be used to determine memory usage of a bitmap. See {@link
     * #getAllocationByteCount()}.</p>
     */
    public final int getByteCount() {
        if (mRecycled) {
            Log.w(TAG, "Called getByteCount() on a recycle()'d bitmap! "
                    + "This is undefined behavior!");
            return 0;
        }
        // int result permits bitmaps up to 46,340 x 46,340
        return getRowBytes() * getHeight();
    }

此方法在19之后就不能在用于定位Bitmap对象内存使用的情况,需要用getAllocationByteCount

 /**
     * Returns the size of the allocated memory used to store this bitmap's pixels.
     *
     * <p>This can be larger than the result of {@link #getByteCount()} if a bitmap is reused to
     * decode other bitmaps of smaller size, or by manual reconfiguration. See {@link
     * #reconfigure(int, int, Config)}, {@link #setWidth(int)}, {@link #setHeight(int)}, {@link
     * #setConfig(Bitmap.Config)}, and {@link BitmapFactory.Options#inBitmap
     * BitmapFactory.Options.inBitmap}. If a bitmap is not modified in this way, this value will be
     * the same as that returned by {@link #getByteCount()}.</p>
     *
     * <p>This value will not change over the lifetime of a Bitmap.</p>
     *
     * @see #reconfigure(int, int, Config)
     */
    public final int getAllocationByteCount() {
        if (mRecycled) {
            Log.w(TAG, "Called getAllocationByteCount() on a recycle()'d bitmap! "
                    + "This is undefined behavior!");
            return 0;
        }
        return nativeGetAllocationByteCount(mNativePtr);
    }

如果位图没有重新以BitmapFactory.Options.inBitmap方式设置Bitmap对象,改方法返回的值和getByteCount一样。

所以就需要封装一个针对不同版本的方法

public static int getBitmapSize(Bitmap bitmap){
        if (bitmap == null) {
            return 0;
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { //api 19
            return bitmap.getAllocationByteCount();
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1){ //api 12
            return bitmap.getByteCount();
        }
        return bitmap.getRowBytes() * bitmap.getHeight(); //other version
    }

BitmapFactory.Options

  • Options
public class BitmapFactory {
    private static final int DECODE_BUFFER_SIZE = 16 * 1024;

    public static class Options {
	.....
	}

}

Options 是BitmapFactory 中的一个静态内部类。内置一些Bitmap对象的属性。
Options 的API文档
博客介绍,很详细

  1. 简单压缩图片
    有一些场景,对图片的显示质量要求不高,这样我们就没有必要去加载高清原图了。直接显示压缩后的图片,需要解决两个问题:
    1. 如何不用创建Bitmap对象就获得原图的宽高大小呢?
 		/**
         * If set to true, the decoder will return null (no bitmap), but
         * the <code>out...</code> fields will still be set, allowing the caller to
         * query the bitmap without having to allocate the memory for its pixels.
         */
        public boolean inJustDecodeBounds;

Options 有个属性inJustDecodeBounds,改属性为true的时候不会返回一个Bitmap对象,但是属性仍然会被设置到Options 对象中。

  1. 如何计算缩放比例?
 		/**
         * If set to a value > 1, requests the decoder to subsample the original
         * image, returning a smaller image to save memory. The sample size is
         * the number of pixels in either dimension that correspond to a single
         * pixel in the decoded bitmap. For example, inSampleSize == 4 returns
         * an image that is 1/4 the width/height of the original, and 1/16 the
         * number of pixels. Any value <= 1 is treated the same as 1. Note: the
         * decoder uses a final value based on powers of 2, any other value will
         * be rounded down to the nearest power of 2.
         */
        public int inSampleSize;

inSampleSize属性如果大于1,则会四舍五入到2的次方,然后缩小该倍数。如果值小于1,则等同于1 。
如:=4的话表示缩小4倍。=5的话也是4倍。效果是一样的。

private Bitmap scaleBitmap(Bitmap bitmap, int newWidth, int newHeight) {
        BitmapFactory.Options opts = new BitmapFactory.Options();
        //设置true
        opts.inJustDecodeBounds = true;
        //不返回Bitmap对象,但是opts属性照样设置
        BitmapFactory.decodeResource(getResources(), R.drawable.car, opts);
        
        //根据目标宽高和原始宽高计算比例
        int scaleWidth = opts.outWidth / newWidth;
        int scaleHeight = opts.outHeight / newHeight;
        //取出缩放比例小的一方
        //opts.inSampleSize = Math.min(scaleWidth,scaleHeight);
        opts.inSampleSize = 4;
        //比例设置好后,inJustDecodeBounds设置为false
        opts.inJustDecodeBounds = false;
        //得到缩放后的bitmap对象
        Bitmap bitmap1 = BitmapFactory.decodeResource(getResources(), R.drawable.car, opts);
		....
}

示例中写了固定的比例。如果把得到缩放后的Bitmap对象,重新设置到ImageView中就会发现,变模糊了。

像素占内存压缩

Android中图片有四种属性,分别是:
ALPHA_8:每个像素占用1byte内存
ARGB_4444:每个像素占用2byte内存
ARGB_8888:每个像素占用4byte内存 (默认)
RGB_565:每个像素占用2byte内存

Android默认的颜色模式为ARGB_8888,这个颜色模式色彩最细腻,显示质量最高。但同样的,占用的内存也最大。 所以在对图片效果不是特别高的情况下使用RGB_565(565没有透明度属性)

BitmapFactory.Options opts = new BitmapFactory.Options();
        //设置true
        opts.inJustDecodeBounds = true;
        //不返回Bitmap对象,但是opts属性照样设置
        BitmapFactory.decodeResource(getResources(), R.drawable.car, opts);
        //像素占内存改小
        opts.inPreferredConfig = Bitmap.Config.RGB_565;

        //根据目标宽高和原始宽高计算比例
        int scaleWidth = opts.outWidth / newWidth;
        int scaleHeight = opts.outHeight / newHeight;
        //取出缩放比例小的一方
        //opts.inSampleSize = Math.min(scaleWidth,scaleHeight);
//        opts.inSampleSize = 4;
        //比例设置好后,inJustDecodeBounds设置为false
        opts.inJustDecodeBounds = false;
        //得到缩放后的bitmap对象
        Bitmap bitmap1 = BitmapFactory.decodeResource(getResources(), R.drawable.car, opts);

log之后发现宽高不变,像素变小了。
改变前后,宽高、像素大小

内存空间复用

利用的就是inBitmap指定将要重复利用的Bitmap对象的内存。同时需要指定inMutable=true表示对象是可变的。如果inPreferredConfig = android.graphics.Bitmap.Config.HARDWARE,inMutable属性永远为false。
可以看看下面博客中的图片加一理解
别人的博客,保存下

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值