文章目录

  • 一、解码图片参数 inJustDecodeBounds
  • 二、计算图片的缩小比例
  • 三、设置图片缩小配置 inSampleSize
  • 四、设置图片像素格式 inPreferredConfig
  • 五、设置图片复用机制
  • 六、Bitmap 图像尺寸缩小代码示例
    • 1、图片缩小工具类
    • 2、Activity 调用工具类代码
    • 3、执行结果

一、解码图片参数 inJustDecodeBounds


1 . 解码图片参数 :

① 设置获取参数解码选项 : 设置解码时的 BitmapFactory.Options 对象的 inJustDecodeBounds 为 true ,

② 解码图像 : 解析器返回的 Bitmap 对象为 null ;

③ 解码选项 : BitmapFactory.Options 中的 outXxx 字段会被设置对应的图片属性值 ;

④ 解码选项参数示例 : 如 : outWidth 输出图像的 宽度 , outHeight 输出高度 , outMimeType 输出类型 , outConfig 像素格式 , outColorSpace 输出颜色空间 ;

2 . 代码示例 :

// Bitmap 图片加载选项
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(resources, iamgeResId, options);

二、计算图片的缩小比例


计算图片的缩小比例 :

① 目标图片宽高要求 : 宽度和高度只要存在一个大于限定的最大值时 , 就进行缩小操作 ; 要求指定的图片必须能放到 maxBitmapWidth 宽度 , maxBitmapHeight 高度的矩形框中 ; 最终要求就是 宽度必须小于 maxBitmapWidth, 同时高度也要小于 maxBitmapHeight ;

② 缩小倍数要求 : 缩小倍数只能是 2 的幂次方值 , 1 , 2 , 4 , 8 , 16 , 32 , 64 ;

        /*计算缩小的比例宽度和高度只要存在一个大于限定的最大值时 , 就进行缩小操作要求指定的图片必须能放到 maxBitmapWidth 宽度 , maxBitmapHeight 高度的矩形框中最终要求就是 宽度必须小于 maxBitmapWidth, 同时高度也要小于 maxBitmapHeight*/if(imageWidth > maxBitmapWidth || imageHeight > maxBitmapHeight){// 如果需要启动缩小功能 , 那么进入如下循环 , 试探最小的缩放比例是多少while ( imageWidth / inSampleSize > maxBitmapWidth ||imageHeight / inSampleSize > maxBitmapHeight ){// 注意该值必须是 2 的幂次方值 , 1 , 2 , 4 , 8 , 16 , 32 , 64inSampleSize = inSampleSize * 2;}// 执行到此处 , 说明已经找到了最小的缩放比例 , 打印下最小比例Log.w(TAG, "getResizedBitmap inSampleSize=" + inSampleSize);}

三、设置图片缩小配置 inSampleSize


1 . 图片缩小配置 inSampleSize :

① inSampleSize 设置大于 1 : 如果值大于 1 , 那么就会缩小图片 ;

② 解码器操作 : 此时解码器对原始的图片数据进行子采样 , 返回较小的 Bitmap 对象 ;

③ 样本个数 : 样本的大小是在两个维度计算的像素个数 , 每个像素对应一个解码后的图片中的单独的像素点 ;

④ 样本个数计算示例 : 如果 inSampleSize 值为 2 , 那么宽度的像素个数会缩小 2 倍 , 高度也会缩小两倍 ; 整体像素个数缩小 4 倍 , 内存也缩小了 4 倍 ;

2 . inSampleSize 取值要求 :

① 小于 1 取值 : 如果取值小于 1 , 那么就会被当做 1 , 1 相当于 2 的 0 次方 ;

② 取值要求 : 该值必须是 2 的幂次方值 , 2 的次方值 , 如 1 , 2 , 4 , 8 , 16 , 32

③ 不合法值 : 如果出现了不合法的值 , 就会就近四舍五入到最近的 2 的幂次方值

3 . 代码示例 :

BitmapFactory.Options options = new BitmapFactory.Options();
// ...
options.inSampleSize = inSampleSize;

四、设置图片像素格式 inPreferredConfig


1 . 解码像素格式 :

① 指定配置解码 : 如果配置为非空 , 解码器会将 Bitmap 的像素解码成该指定的非空像素格式 ;

② 自动匹配配置解码 : 如果该配置为空 , 或者像素配置无法满足 , 解码器会尝试根据系统的屏幕深度 , 源图像的特点 , 选择合适的像素格式 ; 如果源图像有透明度通道 , 那么自动匹配的默认配置也有对应通道 ;

③ 默认配置 : 默认使用 ARGB_8888 进行解码

2 . 代码示例 :

options.inPreferredConfig = Bitmap.Config.RGB_565;

五、设置图片复用机制


1 . 图片复用机制 :

① 图片复用 : 如果设置了一个 Bitmap 对象给 inBitmap 参数 , 解码方法会获取该 Bitmap 对象 , 当加载图片内容时 , 会尝试复用该 Bitmap 对象的内存

② 无法复用抛出异常 : 如果解码方法无法复用该 Bitmap 对象 , 解码方法可能会抛出 IllegalArgumentException 异常 ;

③ 图片可变性 : 当前的实现是很有必要的 , 被复用的图片必须是可变的 , 解码后的 Bitmap 对象也是可变的 , 即使当解码一个资源图片时 , 经常会得到一个不可变的 Bitmap 对象 ;

2 . 解码结果判定 :

① 解码可能失败 : 该解码方法返回的 Bitmap 对象是可以使用的 , 鉴于上述约束情况 和 可能发生的失败故障 , 不能假定该图片解码操作是成功的 ;

② 检查复用是否成功 : 解码检查解码返回的 Bitmap 对象是否与设置给 Options 对象的 inBitmap 相匹配 , 来判断该 inBitmap 是否被复用 ;

③ 后续操作 : 不管有没有复用成功 , 你应该使用解码函数返回的 Bitmap 对象 , 保证程序的正常运行 ;

3 . 与 BitmapFactory 配合使用 :

① Android 4.4 以后的复用机制 : 在 KITKAT 以后的代码中 , 只要被解码生成的 Bitmap 对象的字节大小 ( 缩放后的 ) , 小于等于 inBitmap 的字节大小 , 就可以复用成功 ;

② Android 4.4 之前的复用机制 : 在 KITKAT ( Android 4.4 系统 , android-19 平台 ) 之前的代码中 , 被解码的图像必须是

  • JPEG 或 PNG 格式 ,
  • 并且 图像大小必须是相等的 ,
  • inssampleSize 设置为 1 ,

才能复用成功 , 另外被复用的图像的 像素格式 Config ( 如 RGB_565 ) 会覆盖设置的 inPreferredConfig 参数

4 . 代码示例 :

options.inBitmap = inBitmap;

六、Bitmap 图像尺寸缩小代码示例


1、图片缩小工具类

图片缩小工具类 :

package kim.hsl.bm.utils;import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;/*** Bitmap 尺寸缩小*/
public class BitmapSizeReduce {private static final String TAG = "BitmapSizeReduce";/*** 获取指定尺寸于鏊求的 Bitmap 对象* 该方法有缺陷 , 计算值的时候没有考虑像素密度* 如果从不同像素密度的资源文件中加载* 可能计算出的值与指定的 maxBitmapWidth maxBitmapHeight 略有出入** @param context           上下文对象* @param iamgeResId        要解析的图片资源 id* @param maxBitmapWidth    Bitmap 的最大宽度* @param maxBitmapHeight   Bitmap 的最大高度* @param hasAlphaChannel   是否包含 ALPHA 通道, 即透明度信息* @param inBitmap          复用的 Bitmap, 将新的 Bitmap 对象解析到该 Bitmap 内存中* @return  返回新的 Bitmap 对象*/public static Bitmap getResizedBitmap(Context context,int iamgeResId, int maxBitmapWidth, int maxBitmapHeight,boolean hasAlphaChannel, Bitmap inBitmap){// 0. 声明方法中使用的局部变量// 用于解析资源Resources resources = context.getResources();// Bitmap 图片加载选项BitmapFactory.Options options = new BitmapFactory.Options();// 图片宽度int imageWidth;// 图片高度int imageHeight;/*根据 图片宽度 imageWidth , 图片高度 imageHeight ,最大宽度 maxBitmapWidth , 最大高度 maxBitmapHeight ,计算出的图片缩放系数 , 该值最终要设置到 BitmapFactory.Options 对象中*/int inSampleSize = 1;// 1. 解析图片参数 : 该阶段不解析所有的数据 , 否则会将实际的图片数据解析到内存中 , 这里只解析图片的宽高信息/*设置 inJustDecodeBounds 为 true , 解析器会返回 null但是 outXxx 字段会被设置对应的图片属性值 ,如 : outWidth 输出图像的 宽度 , outHeight 输出高度 , outMimeType 输出类型 ,outConfig 像素格式 , outColorSpace 输出颜色空间*/options.inJustDecodeBounds = true;/*由于设置了 inJustDecodeBounds = true , 该方法返回值为空 ;但是传入的 BitmapFactory.Options 对象中的 outXxx 字段都会被赋值 ;如 outWidth , outHeight , outConfig , outColorSpace 等 ;可以获取该图片的宽高 , 像素格式 , 颜色空间等信息*/BitmapFactory.decodeResource(resources, iamgeResId, options);// 获取 iamgeResId 图片资源对应的图片宽度imageWidth = options.outWidth;// 获取 iamgeResId 图片资源对应的图片高度imageHeight = options.outHeight;// 2. 计算图片缩小比例/*计算缩小的比例宽度和高度只要存在一个大于限定的最大值时 , 就进行缩小操作要求指定的图片必须能放到 maxBitmapWidth 宽度 , maxBitmapHeight 高度的矩形框中最终要求就是 宽度必须小于 maxBitmapWidth, 同时高度也要小于 maxBitmapHeight*/if(imageWidth > maxBitmapWidth || imageHeight > maxBitmapHeight){// 如果需要启动缩小功能 , 那么进入如下循环 , 试探最小的缩放比例是多少while ( imageWidth / inSampleSize > maxBitmapWidth ||imageHeight / inSampleSize > maxBitmapHeight ){// 注意该值必须是 2 的幂次方值 , 1 , 2 , 4 , 8 , 16 , 32 , 64inSampleSize = inSampleSize * 2;}// 执行到此处 , 说明已经找到了最小的缩放比例 , 打印下最小比例Log.w(TAG, "getResizedBitmap inSampleSize=" + inSampleSize);}// 3. 设置图像解码参数/*inSampleSize 设置大于 1 : 如果值大于 1 , 那么就会缩小图片 ;解码器操作 : 此时解码器对原始的图片数据进行子采样 , 返回较小的 Bitmap 对象 ;样本个数 : 样本的大小是在两个维度计算的像素个数 , 每个像素对应一个解码后的图片中的单独的像素点 ;样本个数计算示例 :如果 inSampleSize 值为 2 , 那么宽度的像素个数会缩小 2 倍 , 高度也会缩小两倍 ;整体像素个数缩小 4 倍 , 内存也缩小了 4 倍 ;小于 1 取值 : 如果取值小于 1 , 那么就会被当做 1 , 1 相当于 2 的 0 次方 ;取值要求 : 该值必须是 2 的幂次方值 , 2 的次方值 , 如 1 , 2 , 4 , 8 , 16 , 32如果出现了不合法的值 , 就会就近四舍五入到最近的 2 的幂次方值*/options.inSampleSize = inSampleSize;// 用户设置的是否保留透明度选项 , 如果不保留透明度选项 , 设置像素格式为 RGB_565// 每个像素占 2 字节内存if (!hasAlphaChannel){/*指定配置解码 : 如果配置为非空 , 解码器会将 Bitmap 的像素解码成该指定的非空像素格式 ;自动匹配配置解码 : 如果该配置为空 , 或者像素配置无法满足 , 解码器会尝试根据系统的屏幕深度 ,源图像的特点 , 选择合适的像素格式 ;如果源图像有透明度通道 , 那么自动匹配的默认配置也有对应通道 ;默认配置 : 默认使用 ARGB_8888 进行解码*/options.inPreferredConfig = Bitmap.Config.RGB_565;}/*注意解码真实图像的时候 , 要将 inJustDecodeBounds 设置为 false否则将不会解码 Bitmap 数据 , 只会将outWidth , outHeight , outConfig , outColorSpace 等 outXxx 图片参数解码出来*/options.inJustDecodeBounds = false;/*设置图片可以被复用*/options.inMutable = true;/*如果设置了一个 Bitmap 对象给 inBitmap 参数解码方法会获取该 Bitmap 对象 , 当加载图片内容时 , 会尝试复用该 Bitmap 对象的内存如果解码方法无法复用该 Bitmap 对象 , 解码方法可能会抛出 IllegalArgumentException 异常 ;当前的实现是很有必要的 , 被复用的图片必须是可变的 , 解码后的 Bitmap 对象也是可变的 ,即使当解码一个资源图片时 , 经常会得到一个不可变的 Bitmap 对象 ;确保是否解码成功 :该解码方法返回的 Bitmap 对象是可以使用的 ,鉴于上述约束情况 和 可能发生的失败故障 , 不能假定该图片解码操作是成功的 ;检查解码返回的 Bitmap 对象是否与设置给 Options 对象的 inBitmap 相匹配 ,来判断该 inBitmap 是否被复用 ;不管有没有复用成功 , 你应该使用解码函数返回的 Bitmap 对象 , 保证程序的正常运行 ;与 BitmapFactory 配合使用 :在 KITKAT 以后的代码中 , 只要被解码生成的 Bitmap 对象的字节大小 ( 缩放后的 )小于等于 inBitmap 的字节大小 , 就可以复用成功 ;在 KITKAT 之前的代码中 , 被解码的图像必须是JPEG 或 PNG 格式 ,并且 图像大小必须是相等的 ,inssampleSize 设置为 1 ,才能复用成功 ;另外被复用的图像的 像素格式 Config ( 如 RGB_565 ) 会覆盖设置的 inPreferredConfig 参数*/options.inBitmap = inBitmap;// 4. 解码图片 , 并返回被解码的图片return BitmapFactory.decodeResource(resources, iamgeResId, options);}}

2、Activity 调用工具类代码

Activity 代码 :

package kim.hsl.bm;import androidx.appcompat.app.AppCompatActivity;import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;import kim.hsl.bm.utils.BitmapSizeReduce;public class MainActivity extends AppCompatActivity {static {System.loadLibrary("native-lib");}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);TextView tv = findViewById(R.id.sample_text);tv.setText(stringFromJNI());// 缩小图像尺寸sizeReduce();}/*** 图像尺寸缩小*/private void sizeReduce(){// 从资源文件中加载内存Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.blog);// 打印 Bitmap 对象的宽高, 字节大小Log.i("Bitmap", "blog : " + bitmap.getWidth() + " , " +bitmap.getHeight() + " , " +bitmap.getByteCount());// 从资源文件中加载内存Bitmap reduceSizeBitmap = BitmapSizeReduce.getResizedBitmap(this, R.drawable.blog,100, 100 , false , null);// 打印 Bitmap 对象的宽高, 字节大小Log.i("Bitmap", "reduceSizeBitmap : " + reduceSizeBitmap.getWidth() + " , " +reduceSizeBitmap.getHeight() + " , " +reduceSizeBitmap.getByteCount());}public native String stringFromJNI();
}

3、执行结果

执行结果 :

2020-06-30 22:04:22.959 3766-3766/? I/Bitmap: blog : 5224 , 2678 , 55959488
2020-06-30 22:04:22.960 3766-3766/? W/BitmapSizeReduce: getResizedBitmap inSampleSize=32
2020-06-30 22:04:22.980 3766-3766/? I/Bitmap: reduceSizeBitmap : 163 , 81 , 26406

分析结果 :

① 源图像分析 : 从资源中加载 , 普通情况下宽度 5224 像素 , 高度 2678 像素 , ARGB_8888 像素格式 , 每个像素 444 字节 , 计算公式为

5224×2678×4=55,959,4885224 \times 2678 \times 4 = 55,959,4885224×2678×4=55,959,488

② 缩小后的图像分析 : 从资源中加载 , 普通情况下宽度 163 像素 , 高度 81 像素 , RGB_565 像素格式 , 每个像素 222 字节 , 计算公式为

163×81×2=26,406‬163 \times 81 \times 2 = 26,406‬163×81×2=26,406‬

【Android 内存优化】Bitmap 图像尺寸缩小 ( 设置 Options 参数 | inJustDecodeBounds | inSampleSize | 工具类实现 )相关推荐

  1. 【Android 内存优化】Bitmap 图像尺寸缩小 ( 考虑像素密度、针对从不同像素密度资源中解码对应的 Bitmap 对象 | inDensity | inTargetDensity )

    文章目录 一.像素密度对解码图片的影响 二.不考虑像素密度会导致图片缩小尺寸不准确 三.DisplayMetrics 源码阅读.研究手机资源获取规则 四.像素密度参数设置取值 ( inDensity ...

  2. 【Android 内存优化】自定义组件长图组件 ( 获取图像宽高 | 计算解码区域 | 设置图像解码属性 复用 像素格式 | 图像绘制 )

    文章目录 一.获取图像真实宽高 二.计算解码区域 三.设置解码参数 内存复用 像素格式 四.图像绘制 五.执行效果 六.源码及资源下载 官方文档 API : BitmapRegionDecoder 在 ...

  3. 【Android 内存优化】Android 工程中使用 libjpeg-turbo 压缩图片 ( 初始化压缩对象 | 打开文件 | 设置压缩参数 | 写入压缩图像数据 | 完成压缩 | 释放资源 )

    文章目录 一.使用 libjpeg-turbo 压缩图片流程 二.初始化 JPEG 压缩对象 三.打开文件 四.设置压缩参数 五.开始压缩 六.循环写入压缩数据 七.完成图片压缩及收尾 八.libjp ...

  4. 【Android 内存优化】Android 工程中使用 libjpeg-turbo 压缩图片 ( JNI 传递 Bitmap | 获取位图信息 | 获取图像数据 | 图像数据过滤 | 释放资源 )

    文章目录 一.Bitmap 图像数据处理 二.Java 层 Bitmap 对象转为 JNI 层 bitmap 对象 三.获取 bitmap 中的图像数据 四.过滤 bitmap 中的图像数据 ( 获取 ...

  5. 【Android 内存优化】Bitmap 硬盘缓存 ( Google 官方 Bitmap 示例 | DiskLruCache 开源库 | 代码示例 )

    文章目录 一.Google 官方 Bitmap 相关示例参考 二.磁盘缓存类 DiskLruCache 三.磁盘缓存初始化 四.存储数据到磁盘缓存中 五.从磁盘缓存中读取数据 六. Android 1 ...

  6. 【Android 内存优化】Bitmap 内存缓存 ( Bitmap 内存复用 | 弱引用 | 引用队列 | 针对不同 Android 版本开发不同的 Bitmap 复用策略 | 工具类代码 )

    文章目录 一.Bitmap 复用池 二.弱引用 Bitmap 内存释放 三.从 Bitmap 复用池中获取对应可以被复用的 Bitmap 对象 1.Android 2.3.3(API 级别 10)及以 ...

  7. Android 系统性能优化(39)---Android内存优化之三:打开MAT中的Bitmap原图

    Android内存优化之三:打开MAT中的Bitmap原图 在使用MAT查看应用程序内存使用情况的时候,我们经常会碰到Bitmap对象以及BitmapDrawable$BitmapState对象,而且 ...

  8. ANDROID内存优化(大汇总——中)

    转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! 写在最前: 本文的思路主要借鉴了2014年AnDevCon开发者大会的一个演讲PPT,加上 ...

  9. 【Android 内存优化】自定义组件长图组件 ( 长图滚动区域解码 | 手势识别 GestureDetector | 滑动计算类 Scroller | 代码示例 )

    文章目录 一.GestureDetector 创建与设置 二.GestureDetector 触摸事件传递 三.触摸滑动操作 四.惯性滑动操作 五.长图滑动组件代码示例 六.运行效果 七.源码及资源下 ...

最新文章

  1. 扩增子文献笔记1白杨内生和根际微生物组在不同生态位存在特异的群落结构
  2. linux下怎么修改mysql的字符集编码
  3. RuntimeError: one of the variables needed for gradient computation has been modified by an inplace o
  4. 在京东、天猫、淘宝都存在情况下,为什么聚美还能崛起?
  5. 《高性能JavaScript》第三章 DOM编程
  6. How is note created - backend implementation
  7. asp.net 导入excel显示进度
  8. [QNAP crontab 定時執行程式
  9. 线程八锁,同步锁的应用
  10. linux c++应用程序内存高或者占用CPU高的解决方案_20161213
  11. 《深入理解计算机网络》读后小记 8、IP地址和子网
  12. Python基础教程,Python入门教程(非常详细)
  13. 用matlab实现人脸识别,Matlab实现简单的人脸识别程序
  14. 新hp设备无法连接到计算机,联想的台式机,用的win7系统,无法装惠普1108打印机驱动,一直显示新设备现已连接,然后无限循环!!!...
  15. 吉他指弹入门——日式指弹的pm技巧
  16. LiveZilla 详细 配置 设置 (三) 配置 LiveZilla 服务
  17. Matlab学习手记——输出到MathType公式编辑器
  18. Lazy Binomial Heaps
  19. Apache Pulsar 生态项目 RocketMQ-on-Pulsar 新增 3 位腾讯 Maintainer
  20. 关于word文档误点不保存后文档的恢复

热门文章

  1. legend3---4、lavarel中session使用注意
  2. 第二次作业 郭昭杰 201731062608
  3. MongoDB · 引擎特性 · MongoDB索引原理
  4. PHP安装memcache扩展
  5. Rsync和Sersync(企业实时同步方案)
  6. eclipse中访问不了tomcat首页server Locations变灰无法编辑
  7. Angular复习笔记(一)
  8. 视频与图像RGB/YUV格式详解
  9. luogu P1064 金明的预算方案
  10. jmeter测试soap协议时候 路径不需要添加