热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

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

本文中探究的图片压缩方式主要是基于Bitmap的api实现。文中探究实现的压缩方式有四种:质量压缩、采样率压缩、Matrix缩放压缩、图片编码格式压缩,感兴趣的朋友可以参考下

知识点介绍

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 

结果

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

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图片压缩的资料请关注其它相关文章!


推荐阅读
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 本文内容为asp.net微信公众平台开发的目录汇总,包括数据库设计、多层架构框架搭建和入口实现、微信消息封装及反射赋值、关注事件、用户记录、回复文本消息、图文消息、服务搭建(接入)、自定义菜单等。同时提供了示例代码和相关的后台管理功能。内容涵盖了多个方面,适合综合运用。 ... [详细]
  • 本文详细介绍了SQL日志收缩的方法,包括截断日志和删除不需要的旧日志记录。通过备份日志和使用DBCC SHRINKFILE命令可以实现日志的收缩。同时,还介绍了截断日志的原理和注意事项,包括不能截断事务日志的活动部分和MinLSN的确定方法。通过本文的方法,可以有效减小逻辑日志的大小,提高数据库的性能。 ... [详细]
  • 本文介绍了解决Netty拆包粘包问题的一种方法——使用特殊结束符。在通讯过程中,客户端和服务器协商定义一个特殊的分隔符号,只要没有发送分隔符号,就代表一条数据没有结束。文章还提供了服务端的示例代码。 ... [详细]
  • Linux服务器密码过期策略、登录次数限制、私钥登录等配置方法
    本文介绍了在Linux服务器上进行密码过期策略、登录次数限制、私钥登录等配置的方法。通过修改配置文件中的参数,可以设置密码的有效期、最小间隔时间、最小长度,并在密码过期前进行提示。同时还介绍了如何进行公钥登录和修改默认账户用户名的操作。详细步骤和注意事项可参考本文内容。 ... [详细]
  • 本文介绍了在rhel5.5操作系统下搭建网关+LAMP+postfix+dhcp的步骤和配置方法。通过配置dhcp自动分配ip、实现外网访问公司网站、内网收发邮件、内网上网以及SNAT转换等功能。详细介绍了安装dhcp和配置相关文件的步骤,并提供了相关的命令和配置示例。 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • 本文介绍了使用AJAX的POST请求实现数据修改功能的方法。通过ajax-post技术,可以实现在输入某个id后,通过ajax技术调用post.jsp修改具有该id记录的姓名的值。文章还提到了AJAX的概念和作用,以及使用async参数和open()方法的注意事项。同时强调了不推荐使用async=false的情况,并解释了JavaScript等待服务器响应的机制。 ... [详细]
  • PHP设置MySQL字符集的方法及使用mysqli_set_charset函数
    本文介绍了PHP设置MySQL字符集的方法,详细介绍了使用mysqli_set_charset函数来规定与数据库服务器进行数据传送时要使用的字符集。通过示例代码演示了如何设置默认客户端字符集。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • Centos7.6安装Gitlab教程及注意事项
    本文介绍了在Centos7.6系统下安装Gitlab的详细教程,并提供了一些注意事项。教程包括查看系统版本、安装必要的软件包、配置防火墙等步骤。同时,还强调了使用阿里云服务器时的特殊配置需求,以及建议至少4GB的可用RAM来运行GitLab。 ... [详细]
  • 本文介绍了在Hibernate配置lazy=false时无法加载数据的问题,通过采用OpenSessionInView模式和修改数据库服务器版本解决了该问题。详细描述了问题的出现和解决过程,包括运行环境和数据库的配置信息。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • 本文介绍了如何找到并终止在8080端口上运行的进程的方法,通过使用终端命令lsof -i :8080可以获取在该端口上运行的所有进程的输出,并使用kill命令终止指定进程的运行。 ... [详细]
author-avatar
WenFJ
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有