Android 基于Bitmap的四种图片压缩方式

知识点介绍

Android 中图片主要以 Bitmap 的形式存在,所以压缩图片主要就是减少 Bitmap 的大小。Bitmap 的大小可以通过如下的公式计算得到:size = width * height * 单个像素所占字节数。因此压缩图片通过改变公式中的三个变量即可实现。

单个像素所占空间大小在 Android 中有多种,详见如下

格式 所占空间 说明
Bitmap.Config.ALPHA_8 1B 该种格式表示图片只有透明度没有颜色,1个像素占用8位
Bitmap.Config.ARGB_4444 2B 该种格式表示图片透明通道 A 及颜色 R、G、B 各占用4位,共16位
Bitmap.Config.ARGB_8888 4B 该种格式表示图片透明通道 A 及颜色 R、G、B 各占用8位,共32位
Bitmap.Config.RGB_565 2B 该种格式表示图片没有透明通道,颜色 R、G、B 各占用5、6、6位,共16位

Android 中加载图片默认用的是 ARGB_8888 格式,所以加载一张3000 * 4000 的图片默认占用的空间为 45MB 左右,这个值还是很大的😂

测试代码

fun showBitmapInfo(bitmap: Bitmap){
        Log.d("Tag","压缩后的图片大小:${bitmap.byteCount/1024/1024}MB,宽度:${bitmap.width},高度:${bitmap.height}")
}

结果

正文

接下来介绍四种压缩方式

1、质量压缩

质量压缩主要通过 Bitmap.compress()实现,方法介绍

/**
*
* @param format 压缩图像的格式
* @param quality 提示压缩机,0-100。 根据Bitmap.CompressFormat不同,该值的解释也不同。
* @param stream –写入压缩数据的输出流。
* @return 如果成功压缩到指定的流,则为true
*/
public boolean compress(CompressFormat format, int quality, OutputStream stream) {
}

CompressFormat 表示图片压缩格式,Android 源码中包含了五种格式

格式名 解释
CompressFormat.JPEG 压缩为JPEG格式。 quality 0表示压缩为最小大小。 100表示压缩以获得最大视觉质量。
CompressFormat.PNG 压缩为PNG格式。 PNG是无损的,因此quality被忽略。
CompressFormat.WEBP 压缩为WEBP格式。 quality 0表示压缩为最小大小。 100表示压缩以获得最大视觉质量。 从Build.VERSION_CODES.Q ,值100导致文件采用无损WEBP格式。 否则,文件将为有损WEBP格式
CompressFormat.WEBP_LOSSY 压缩为WEBP有损格式。 quality 0表示压缩为最小大小。 100表示压缩以获得最大视觉质量。
CompressFormat.WEBP_LOSSLESS 压缩为WEBP无损格式。 quality是指投入多少精力进行压缩。 值0表示快速压缩,导致文件大小相对较大。 100表示要花费更多时间进行压缩,从而使文件更小。

测试代码

/**
 * 压缩图片质量
*/
fun getCompressBitmap(bitmap: Bitmap,quality:Int): Bitmap {
    val baos = ByteArrayOutputStream()
    bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos)
    val byte = baos.toByteArray()
    val ins = ByteArrayInputStream(byte)
    val bm = BitmapFactory.decodeStream(ins)
    ins.close()
    baos.close()
    return bm
}

效果

根据上面的日志,你会看到质量压缩并不能改变图片在内存中的大小,因为质量压缩既不能改变图片分辨率也不能改变图片的单个像素大小。

那么你可能有些疑问:既然不能改变大小,那么还费这么大功夫转化而且图片还失真是为了什么?

答:源码中对于compress方法的解释是,将位图的压缩版本写入指定的输出流。所以应该是对输出流中的字节数有影响

验证

val baos = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos)
val byte = baos.toByteArray()
Log.d("Tag","quality=$quality,byte-size=${byte.size}")

结果真的是对输出流的字节数有影响

2、采样率压缩

BitmapFactory.Options 中有个属性 inSampleSize,系统中采样率压缩就是通过该属性

/**
* 如果设置为大于1的值,则请求解码器对原始图像进行二次采样,返回较小的图像以节省内存。
* 样本大小是任一维度中与解码后的位图中的单个像素相对应的像素数。 例如,inSampleSize == 4
* 返回的图像为原始宽度/高度的1/4,像素数目的1/16。 任何小于等于1的值都与1相同。
* 注意:解码器使用基于2的幂的最终值,任何其他值将四舍五入为最接近的2的幂。
**/
 public int inSampleSize;

直接上代码

    /**
     * 根据设定的宽高计算缩放比
     */
    fun calculateInSampleSize(options: BitmapFactory.Options, reqWidth: Int, reqHeight: Int): Int {
        val height = options.outHeight
        val width = options.outWidth
        var inSampleSize = 1
        if (height > reqHeight || width > reqWidth) {
            val heightRatio = round(height.toFloat() / reqHeight.toFloat()).toInt()
            val widthRatio = round(width.toFloat() / reqWidth.toFloat()).toInt()
            inSampleSize = if (heightRatio < widthRatio) heightRatio else widthRatio
        }
        return inSampleSize
    }

    /**
     * 获取缩放后的图片
     */
    fun getSmallBitmap(filePath: String,reqWidth: Int,reqHeight: Int): Bitmap {
        val options = BitmapFactory.Options()
        options.inJustDecodeBounds = true //不加载 bitmap 进内存,只获取他的基本信息
        BitmapFactory.decodeFile(filePath, options)
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight)
        options.inJustDecodeBounds = false
        return BitmapFactory.decodeFile(filePath, options)
    }

结果

采样率压缩的方式使用的还是挺多的,因为我们获取到的图片它的尺寸可能很大,但是我们在手机上显示的可能不需要那么大,那我们就将图片缩放成我们需要的大小。

3、缩放法压缩

这种方法主要是依赖 Matrix 矩阵变换的方式对图片进行处理。Matrix 中有很多对图片变换的 api 这里只使用它的缩放功能,其他功能可以自行了解

代码

    /**
     * 通过矩阵缩放
     */
    fun matrixBitmap(bitmap: Bitmap,scale:Float):Bitmap{
        val matrix = Matrix()
        matrix.setScale(scale,scale)
        var bm = Bitmap.createBitmap(bitmap,0,0,bitmap.width,bitmap.height,matrix,true)
        return bm
    }

当设置缩放比为0.5时,图片整体就缩放为原来的1/4

4、RGB_565 通过改变图片格式来实现压缩

系统默认使用的是ARGB_8888的格式,所以我们只要改变这个 options 值就能实现

fun rgb565Bitmap(filePath: String):Bitmap{
        val options = BitmapFactory.Options()
        options.inPreferredConfig = Bitmap.Config.RGB_565
        var bitmap = BitmapFactory.decodeFile(filePath,options)
        return bitmap
}

结果图片变成了原图的一半

总结

对于图片的压缩,首先可以先将图片格式改为 RGB_565,这样图片先减小一半,然后对于图片的显示可以使用采样率压缩或者缩放压缩的方式将图片的分辨率改为我们显示的大小,如果是要将图片上传服务器那么可以使用质量压缩的方式,但是这种方式不支持 png 格式的图片。

以上就是Android 基于Bitmap的四种图片压缩方式的详细内容,更多关于Android Bitmap图片压缩的资料请关注我们其它相关文章!

(0)

相关推荐

  • Android三种常见的图片压缩方式

    下面就为大家带来3种比较常见的压缩方式 先给出一组数据 原图:width:2976; height:2976 原图实际:--->byte:2299820 Mb:2.19328 质量压缩 size--->:byte:1599831 kb:1562.33496 按比例压缩 size--->:byte:191707 kb:187.21387 鲁班压缩 size--->:byte:143792 kb:140.42188 压缩效果:鲁班压缩 > 按比例压缩 > 质量压缩 1.质量

  • android图片压缩工具类分享

    本文实例为大家分享了android图片压缩工具类的具体代码,供大家参考,具体内容如下 import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; imp

  • Android开发之图片压缩实现方法分析

    本文实例讲述了Android开发之图片压缩实现方法.分享给大家供大家参考,具体如下: 由于Android本身的机制限定 由于系统对每个应用内存分配规则的限制,如果加载过大图片很有可能会导致OOM 即闪退或者卡屏现象 但是手机上拇指大小的图片,超清是完全没有必要的 这是我们就需要对 对片进行压缩处理: 大多数人采用先生成bitmap对象,反复压缩bitmap至100k一下的方法,对图片进行反复压缩,但如果是超级大图,bitmap生成本身就已经会导致OOM,所以我们应先对bitmap进行设置: pu

  • Android整理好的图片压缩工具类

    Android设备的内存有限,对于大图片,必须进行压缩后再进行显示,否则会出现内存溢出:OOM: 处理策略: 1.使用缩略图(Thumbnails): Android系统会给检测到的图片创建缩略图:可以操作Media内容提供者中的Image对图片进行操作: 2.手动压缩: (1)根据图片和屏幕尺寸,等比压缩,完美显示: (2)降低图片质量,压缩图片大小: 以下是自己整理的小工具类(对于按比例缩放后,在此并未再进行质量缩放,此时图片大小有可能超出我们期望的限制:假如我们有严格的大小限制需求,可先进

  • Android Tiny集成图片压缩框架的使用

    为了简化对图片压缩的调用,提供最简洁与合理的api压缩逻辑,对于压缩为Bitmap根据屏幕分辨率动态适配最佳大小,对于压缩为File优化底层libjpeg的压缩,整个图片压缩过程全在压缩线程池中异步压缩,结束后分发回UI线程. 支持的压缩类型 Tiny图片压缩框架支持的压缩数据源类型: 1.Bytes 2.File 3.Bitmap 4.Stream 5.Resource 6.Uri(network.file.content) Tiny支持单个数据源压缩以及批量压缩,支持的压缩类型: 1.数据源

  • Android图片压缩的实例详解

    Android图片压缩的实例详解 在做微信分享的时候,由于分享的缩略图要求不得大于32K,否则不能调起微信,所以总结了一下Android图片的压缩问题,大部分资料都是来自网上各位的分享,自己只是完善或修改了一下,本着继续分享的精神,也方便自己记忆,于是总结如下. android图片压缩主要有两种方式:1.压缩图片分辨率 2.压缩图片质量 一.先看压缩图片分辨率,很好理解,如本来1280*768的图片压缩为640*384大小.废话不说,直接上代码: /** * 按比例压缩图片分辨率 * @para

  • Android LuBan与Compressor图片压缩方式

    1,LuBan压缩问题    https://github.com/Curzibn/Luban 之前选择压缩图片库,在github上找的这个star最多的,使用方法是传入图片数组,在异步线程中回调返回的结果.接下来就出现问题了,压缩的图片质量模糊,虽然可以设置多少KB一下不压缩,在正常手机屏幕压缩没太大问题.但是在平板,同一张图片,压缩就会模糊. Luban.with(this) .load(photos) // 传人要压缩的图片列表 .ignoreBy(100) // 忽略不压缩图片的大小 .

  • Android 高效图片压缩的实现

    使用libjpeg-turbo进行图片压缩 1. JEPG 是什么? 相信有一部分使用 iPhone 手机用微信发送图片的时候,明明图片大小只有 1M ,但清晰度比 Android 手机 5 M 图片大小的还要清晰,那么这是为什么呢 ?. 当时谷歌开发 Android 的时候,考虑了大部分手机的配置并没有那么高,所以对图片处理使用的是 Skia.当然这个库的底层还是用的 jpeg 图片压缩处理.但是为了能够适配低端的手机(这里的低端是指以前的硬件配置不高的手机,CPU 和内存在手机上都非常吃紧,

  • Android图片压缩方法并压缩到指定大小

    一.图片质量压缩 /** * 质量压缩方法 * @param image * @return */ public static Bitmap compressImage(Bitmap image) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); image.compress(Bitmap.CompressFormat.JPEG, 100, baos);// 质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中

  • Android开发之图片压缩工具类完整实例

    本文实例讲述了Android图片压缩工具类.分享给大家供大家参考,具体如下: 这里共享一个图片压缩工具类: package com.sanweidu.TddPay.util2; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import android.graphics.Bitmap; import android.graphics.BitmapFactory; public class Im

随机推荐