IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android Bitmap相关知识点——类型、创建、压缩、转换等 -> 正文阅读

[移动开发]Android Bitmap相关知识点——类型、创建、压缩、转换等

一、Bitmap的存储格式以及内存计算

当需要做性能优化或者防止OOM时,我们通常会使用RGB_565这种类型。
因为ALPHA_8类型的bitmap只有透明度,用处不多。ARGB_4444显示图片不清晰。ARGB_8888占用内存空间最多。

BItmap类型一个像素所占内存
ALPHA_81字节 【8位( A:8)】
RGB_5652字节 【16位(R:5;G:6;B:5)】
ARGB_44442字节【16位( A:4;R:4;G:4;B:4)】
ARGB_88884字节【32位( A:8;R:8;G:8;B:8)】

Bitmap所占内存大小 = 宽度像素 × 高度像素 × 一个像素所占的内存大小。

在Bitmap里有两个获取内存占用大小的方法:

  • getByteCount():API12加入,代表存储Bitmap的像素需要的最少内存。
  • getAllocationByteCount():API19加入,代表在内存中为BItmap分配的内存大小,代替了getByteCount()方法。

二、Bitmap的加载

如何加载一张图片呢?BitmapFactory 类提供了四种方法:decodeFile()decodeResource()decodeStream()decodeByteArray(),分别用于从文件系统、资源、输入流以及字节数组中加载一个Bitmap对象,其中decodeFile和decodeResource又间接调用了decodeStream方法,这四种方法对应着底层实现中相应的native方法。

decodeFile():

BitmapFactory.decodeFile(pathName: String!, opts: BitmapFactory.Options!)

decodeResource():

BitmapFactory.decodeResource(res: Resources!, resId: Int, opts: BitmapFactory.Options!)

decodeStream():

BitmapFactory.decodeStream(is: InputStream?, outPadding: Rect?, opts: BitmapFactory.Options?)

decodeByteArray():

BitmapFactory.decodeByteArray(data: ByteArray!, offset: Int,  length: Int, opts: BitmapFactory.Options!)

BitmapFactory.Options类

上面的四个方法都有一个相同的参数BitmapFactory.Options,这个参数作用很大。
通过这个参数可以对bitmap进行一些配置,例如,设置采样率来减少bitmap的像素,防止OOM。

BitmapFactory.Options类中一些重要的成员变量和方法:
inSampleSize:设置采样率,对图片进行缩放,例如:inSampleSize = 2时,加载出来的图片的宽高分别原来的二分之一,内存大小是原来的四分之一,inSampleSize的值需为2的指数。当设置的值不为2的指数时,系统会自动向下选取一个最接近的2的指数来代替。

outWidth:获取图片的宽度。

outHeight:获取图片的高度。

inJustDecodeBounds:布尔类型,当设置为true时,不获取图片,不分配内存,但可以获得图片的高度(options.outHeight)、宽度(options.outWidth)、MIME类型(options.outMineType)等。

inScreenDensity:获取当前屏幕的像素密度。

三、Bitmap的压缩方法

1、压缩格式

当对图片进行压缩时,有以下三种压缩格式:

CompressFormat描述
Bitmap.CompressFormat.JPEG表示以JPEG压缩算法进行图片压缩,压缩后的格式可以是 .jpg 或者 .jpeg,是一种有损压缩
Bitmap.CompressFormat.PNG表示以PNG压缩算法进行压缩,是一种支持透明度的无损压缩格式
Bitmap.CompressFormat.WEBP是一种支持有损压缩和无损压缩的图片文件格式,无损的webp格式图片体积比无损的png图片小

2、采样率压缩

如何压缩一张图片,使其所占内存变小?首先,最简单的方式就是通过设置采样率来缩小图片的尺寸,减小图片内存占用。
例如,ImageView的大小为100×100像素,而图片的原始大小为200×200,那么只需要将采样率inSampleSize设置为2即可。
如何确定采样率的值,可以通过下面这两个方法来计算得到一个适合的采样率。

fun decodeSampledBitmapFromResource(res: Resources, resId: Int, reqWidth: Int, reqHeight: Int): Bitmap{
        val options = BitmapFactory.Options()
        options.inJustDecodeBounds = true
        BitmapFactory.decodeResource(res, resId, options)
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight)
        options.inJustDecodeBounds = false
        return BitmapFactory.decodeResource(res, resId, options)
    }

    private fun calculateInSampleSize(options: BitmapFactory.Options, reqWidth: Int, reqHeight: Int): Int {
        val width = options.outWidth
        val height = options.outHeight
        println("width: $width ,height: $height")
        var inSampleSize = 1
        if (width > reqWidth || height > reqHeight) {
            val halfHeight = height / 2
            val halfWidth = width / 2
            while ((halfWidth / inSampleSize) >= reqWidth && (halfHeight / inSampleSize) >= reqHeight){
                inSampleSize *= 2
            }
        }
        println("inSampleSize: $inSampleSize")
        return inSampleSize
    }

这里用的是decodeResource()方法来加载图片,其它三个decode方法也支持采样率加载,并且处理方式也是类似的。
所以,想要通过采样率来高效的加载图片,主要的步骤流程是这样的:

  1. BitampFactory.OptionsinJustDecodeBounds参数设为true;
  2. BitampFactory.Options中取出图片的原始宽高信息,它们对应于outWidthoutHeight参数;
  3. 根据采样率的规则并结合目标View的所需大小计算出采样率inSampleSize;
  4. BitampFactory.OptionsinJustDecodeBounds参数设置为false,然后重新加载图片。

3、质量压缩

采样率压缩会改变图片的原始尺寸,如果你想压缩图片大小的同时保持原来的图片尺寸,那可以采用下面这种方式来处理。
通过Bitmap对象的compress(format:Bitmap.CompressFormat, quality: Int, stream: OutputStream)方法,不仅可以进行图片质量的压缩,可以设置压缩后图片的格式。方法的第一个参数为压缩后的格式,第二个参数为压缩质量(0~100),100为不压缩图片质量,第三个参数就是要写入的输出流。
注意,如果设置格式为Bitmap.CompressFormat.PNG,那设置压缩质量quality是没有效果的,因为png为无损压缩。

具体使用方法,请看代码:

/**
     * 压缩Bitmap
     * quality为压缩质量(0~100)
     */
    fun compressBitmap(bitmap: Bitmap, quality: Int): Bitmap?{
        if (bitmap == null) {
            return null
        }
        var baos: ByteArrayOutputStream? = null
        try {
            baos = ByteArrayOutputStream()
            bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos)
            val bytes = baos.toByteArray()
            val isBm = ByteArrayInputStream(bytes)
            return BitmapFactory.decodeStream(isBm)
        } catch (e: OutOfMemoryError){
            e.printStackTrace()
        } finally {
            try {
                baos?.close()
            } catch (e: IOException){
                e.printStackTrace()
            }
        }
        return null
    }

四、Bitmap与Drawable相互转换

 /**
     * Drawable转Bitmap
     */
    fun drawableToBitmap(drawable: Drawable): Bitmap{
        // 获取drawable的宽高
        val width = drawable.intrinsicWidth
        val height = drawable.intrinsicHeight
        // 获取drawable的颜色类型
        val config = if(drawable.opacity != PixelFormat.OPAQUE) Bitmap.Config.ARGB_8888 else Bitmap.Config.RGB_565
        // 建立bitmap对象
        val bitmap = createBitmap(width, height, config)
        // 创建对应的画布
        val canvas = Canvas(bitmap)
        drawable.setBounds(0, 0, width, height)
        // 将drawable内容画到画布上
        drawable.draw(canvas)
        return bitmap
    }

    /**
     * bitmap转drawable
     */
    fun bitmapToDrawable(resources: Resources, bitmap: Bitmap) = BitmapDrawable(resources, bitmap)

五、使用Matrix处理图片

通过Matrix可以对图片进行缩放、旋转、移动、裁剪等操作。
Matrix提供的一些常用方法

方法名作用
setScale(sx:Float,sy:Float)图片缩放,sx 和sy 为缩放的比例
setRotate(degrees:Float,px:Float,py:FLoat)图片旋转,degrees为角度,px,py为旋转中心点坐标
setTranslate(dx:Float,dy:Float)图片平移,dx 和dy 为移动的距离
setSkew(kx:Float,ky:Float)图片倾斜,kx 和ky 为倾斜比例

使用方式:

/**
     * 缩放图片
     */
    fun scaleBitmap(bitmap: Bitmap): Bitmap{
        val matrix = Matrix()
        matrix.setScale(0.6f, 0.6f)
        return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
    }
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-10-21 12:18:02  更:2021-10-21 12:18:21 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 1:29:03-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码