Android Bitmap知识梳理学习
2017-04-04 11:50
555 查看
学习资料:
Bitmap api
8位位图;1 个字节,只有透明度,没有颜色值
16位位图;2 个字节,r = 5,g = 6,b = 5,一个像素点 5+6+5 = 16
16位位图;2 个字节,a = 4,r = 4,g = 4,b = 4,一个像素点 4+4+4+4 = 16
32 位位图; 4个字节,a = 8,r = 8,g = 8, b = 8,一个像素点 8 + 8 + 8 + 8 = 32
每8位一个字节
以上主要摘自:关于ARGB_8888、ALPHA_8、ARGB_4444、RGB_565的理解
并不理解
一张 1024 * 1024 像素,采用
若采用
Creates Bitmap objects from various sources, including files, streams, and byte-arrays.
通过
一个采用
缩小规律就是:
创建
将
利用
根据采样率的规则并结合实际需要显示的宽高计算出
将
效果
代码就是按照流程走的。 只是加入了34行
34行,通过
如果已经得到了
在
例如,
这只是我的分析,代码是从
这时已经可以大大减少
其他从文件,流中读取也差不太多,流程没啥变化,细节不同
Write a compressed version of the bitmap to the specified outputstream.
If this returns true, the bitmap can be reconstructed by passing a corresponding inputstream to BitmapFactory.decodeStream(). Note: not all Formats support all bitmap configs directly, so it is possible that the returned bitmap from BitmapFactory could be in
a different bitdepth, and/or may have lost per-pixel alpha (e.g. JPEG only supports opaque pixels).
@param format The format of the compressed image
@param quality Hint to the compressor, 0-100. 0 meaning compress for small size, 100 meaning compress for max quality. Some formats, like PNG which is lossless, will ignore the quality setting
@param stream The outputstream to write the compressed data.
@return true if successfully compressed to the specified stream.
将
返回值,
简单使用:
在变换成输出流的过程中,把
Tries to make a new bitmap based on the dimensions of this bitmap,setting the new bitmap's config to the one specified, and then copying this bitmap's pixels into the new bitmap. If the conversion is not supported, or the allocator fails, then this returns
NULL. The returned bitmap initially has the same density as the original.
@param config The desired config for the resulting bitmap
@param isMutable True if the resulting bitmap should be mutable (i.e.its pixels can be modified)
@return the new bitmap, or null if the copy could not be made.
拷贝一个
返回值,
简单使用:
方法中
返回值 一个不可变的
由资源
1->2,2->本方法
本方法简单使用:
需要注意:
这两个方法最终都调用了一个没有对外公开的
返回值 一个不可变的
1,2,3调用了本方法
本方法简单使用:
这个方法并没有使用过。对参数要求比较多,使用时在源码中看一下参数要求。这个方法目前不清楚使用场景,只能遇到时,再次学习
其他的用到再学习了。
其他更不常见的用到再学习
android 开发艺术探索
Bitmap api
1.关于 Bitmap
在Android中
Bitamp指的就是一张图片,一般是
png和
jpeg格式。
Bitmap类中有一个
enum类型的
Config,其中有4个值
ALPHA_8
8位位图;1 个字节,只有透明度,没有颜色值
RGB_565
16位位图;2 个字节,r = 5,g = 6,b = 5,一个像素点 5+6+5 = 16
ARGB_4444
16位位图;2 个字节,a = 4,r = 4,g = 4,b = 4,一个像素点 4+4+4+4 = 16
ARGB_8888
32 位位图; 4个字节,a = 8,r = 8,g = 8, b = 8,一个像素点 8 + 8 + 8 + 8 = 32
每8位一个字节
以上主要摘自:关于ARGB_8888、ALPHA_8、ARGB_4444、RGB_565的理解
并不理解
a,r,g,b对像素的影响,主要了解一下,不同的类型格式,占用内存情况
一张 1024 * 1024 像素,采用
ARGB8888格式,一个像素32位,每个像素就是4字节,占有内存就是4M
若采用
RGB565,一个像素16位,每个像素就是2字节,占有内存就是2M
Glide加载图片默认格式
RGB565,
Picasso为
ARGB8888,默认情况下,
Glide占用内存会比
Picasso低,色彩不如
Picasso鲜艳,自然清晰度就低
BitmaFactory
Creates Bitmap objects from various sources, including files, streams, and byte-arrays.
通过
BitmapFactory从文件系统,资源,输入流,字节数组中加载得到一个
Bitmap对象。
decodeByteArray()
decodeFile()
decodeResource()
decodeStream()
decodeFileDescriptor()
decodeResourceStream()
BitmapFactory所有
public method都是静态方法。一共也就6个方法,后两个用的几率不如前4个高 :)
2.Bitmap 的高效加载
核心思想: 利用BitmapFactory.Options来加载实际所需的尺寸
2.1 BitmapFactory.Options
这个类中只有一个方法requestCancelDecode(),剩下全是一些常量值
BitmapFactory.Options缩放图片主要用到
inSample采样率
inSample = 1,采样后图片的宽高为原始宽高
inSample > 1,例如2,宽高均为原图的宽高的1/2
一个采用
ARGB8888的
1024 * 1024的图片
inSample = 1,占用内存就
1024 * 1024 * 4 = 4M
inSample = 2,占用内存就
512 * 512 * 4 = 1M
缩小规律就是:
1 /(inSample ^ 2)
inSample的值最小为1,低于1时无效的。
inSample的值最好为2,4,8,16,2的指数。在某些时候,系统会向下取整,例如为3时,系统会用2来代替。2 的指数,可以一定程度上避免图片拉伸变形。
2.2 获取采样率的流程
以读取资源文件为例:创建
BitmapFactory.Options对象
options
将
options的
inJustDecodeBounds参数设为
true,然后使用
BitmapFactory.decodeResource(res,resId,options)加载图片
利用
options取出图片的原始宽高信息,
outWidth,outHeight
根据采样率的规则并结合实际需要显示的宽高计算出
inSample
将
options的
inJustDecodeBounds参数设为
false,并再次使用
BitmapFactory.decodeResource(res,resId,options)返回采样后的
Bitmap
inJustDecodeBounds设为
true,
BitmapFactory只会解析图片的原始信息,并不会真正的加载图片
BitmapFactory读取图片的宽高的信息受图片所在
drawable文件夹和设备屏幕本身的像素密度影响。
2.3 压缩图片简单实践
直接百度了一张imac的5k分辨率
5120 * 2880大小为
5.97M的壁纸,直接加载我的手机百分百会出现
oom
效果
java代码:
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } private void initView() { final ImageView iv = (ImageView) findViewById(R.id.iv_main); iv.post(new Runnable() { @Override public void run() { int width = iv.getWidth(); int height = iv.getHeight(); iv.setImageBitmap(decodeBitmap(getResources(),R.drawable.test,width,height)); } }); } /** * 对图片进行压缩 * * @param res * @param resId * @param targetWidth * @param targetHeight * @return */ private Bitmap decodeBitmap(Resources res , int resId, int targetWidth, int targetHeight){ final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; 34行 options.inPreferredConfig = Bitmap.Config.RGB_565;//将Config设为RGB565 BitmapFactory.decodeResource(res,resId,options); options.inSampleSize = calculateInSample(options,targetWidth,targetWidth); options.inJustDecodeBounds = false; return BitmapFactory.decodeResource(res,resId,options); } /** * 计算inSample * * @param options * @param targetWidth * @param targetHeight * @return */ private int calculateInSample(BitmapFactory.Options options, int targetWidth, int targetHeight) { final int rawWidth = options.outWidth; final int rawHeight = options.outHeight; int inSample = 1; 54行 if (rawWidth > targetWidth || rawHeight > targetHeight){ final int halfWidth = rawWidth / 2;//为了避免过分压缩 例如 图片大小为 250 * 250 view 200 * 200 final int halfHeight = rawHeight / 2; 57行 while((halfWidth / intSample) >= targetWidth && (halfHeight / intSample) >= targetHeight){ inSample *= 2; } } return inSample; } }
代码就是按照流程走的。 只是加入了34行
Bitmap色彩格式的修改
34行,通过
options把
Bitmap的格式设为
RGB565。设置成
RGB565后,占用内存会少一半,也会减少
OOM。个人感觉,除非是专门的图像处理app,大部分时候都可以用
RGB565代替
ARGB8888,牺牲图像的清晰度,换来一半的占用内存,个人感觉还是比较划算的。并且,清晰度的差别,不同时放在一起比较是不会有很大直观差别的。
Bitmap中有一个
setConfig()方法,源码中调用了
reconfigure(int width, int height, Config config),这个方法是创建一个新的
bitmap用的。看了看不是很理解。这个方法不能用于目前已经存在的
Bitmap。修改
config还是利用
Options类
如果已经得到了
Bitmap,想要修改
Bitmap的
Config值,可以使用3.1
Bitmap.cropress()和3.2
Bitmap.copy()方法
在
calculateInSample()方法中,
final int halfWidth = rawWidth / 2这行代码的目的在于防止过度压缩。因为54行已经做了判断,到了57行条件必然满足,当要显示的目标大小和图像的实际大小比较接近时,会产生过度没必要的压缩。
例如,
ImageView的大小为
200 * 200,而图像的大小为为
250 * 250,如果不进行除以2,到了57行,条件成立,此时
inSample的值会再次乘以2,根据缩小规律
缩小 = inSample ^ 2,就会又次缩小4倍。
这只是我的分析,代码是从
Android开发艺术探索学到的,若分析的不对,请指出
这时已经可以大大减少
oom的发生,若还发生,可以把57行的
&&改为
||,这样改后,
final int halfWidth = rawWidth / 2的作用就会受到影响。可能会出现过度压缩
其他从文件,流中读取也差不太多,流程没啥变化,细节不同
3.Bitmap中的方法
主要是查看api文档,想了解下都有哪些方法3.1compress方法
compress(Bitmap.CompressFormat format, int quality, OutputStream stream)
Write a compressed version of the bitmap to the specified outputstream.
If this returns true, the bitmap can be reconstructed by passing a corresponding inputstream to BitmapFactory.decodeStream(). Note: not all Formats support all bitmap configs directly, so it is possible that the returned bitmap from BitmapFactory could be in
a different bitdepth, and/or may have lost per-pixel alpha (e.g. JPEG only supports opaque pixels).
@param format The format of the compressed image
@param quality Hint to the compressor, 0-100. 0 meaning compress for small size, 100 meaning compress for max quality. Some formats, like PNG which is lossless, will ignore the quality setting
@param stream The outputstream to write the compressed data.
@return true if successfully compressed to the specified stream.
将
bitmap数据质量压缩并转换成流,若
format参数设置为了
png格式,
quality设置无效
format图片的格式,支持3种
JPEG,PNG,WEBP
quality压缩质量压缩率,0-100,0表示压缩程度最大,100为原质量,但
png无效
stream输出流
返回值,
boolean
简单使用:
private void initView() { Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.cc); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(1024 * 8); bitmap.compress(Bitmap.CompressFormat.PNG,100,outputStream); BitmapFactory.Options options = new BitmapFactory.Options(); options.inPreferredConfig = Bitmap.Config.RGB_565; bitmap =BitmapFactory.decodeByteArray(outputStream.toByteArray(),0,outputStream.size(),options); Log.e(TAG,"++"+outputStream.size()+","+bitmap.getConfig().name()+","+bitmap.getByteCount()+","+bitmap.getHeight()+","+bitmap.getWidth()); }
在变换成输出流的过程中,把
Bitmap的
Config变为了
RGB565,这里遇到个情况,
mipmap文件夹下的图片,这种方法并不能改变其
Config,一直都是默认
ARGB8888
3.2 copy方法
copy(Bitmap.Config config, boolean isMutable)
Tries to make a new bitmap based on the dimensions of this bitmap,setting the new bitmap's config to the one specified, and then copying this bitmap's pixels into the new bitmap. If the conversion is not supported, or the allocator fails, then this returns
NULL. The returned bitmap initially has the same density as the original.
@param config The desired config for the resulting bitmap
@param isMutable True if the resulting bitmap should be mutable (i.e.its pixels can be modified)
@return the new bitmap, or null if the copy could not be made.
拷贝一个
Bitmap的像素到一个新的指定信息配置的
Bitmap
config配置信息
isMutable是否支持可改变可写入
返回值,
bitmap,成功返回一个新的
bitmap,失败就
null
简单使用:
private void initView() { Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.m); bitmap = bitmap.copy(Bitmap.Config.RGB_565,true); Log.e(TAG,"++"+bitmap.getConfig().name()+","+bitmap.getByteCount()+","+bitmap.getHeight()+","+bitmap.getWidth()); }
方法中
isMutable这个参数暂时不了解具体作用和使用场景
3.3 createBitmap方法
这个方法一共有9个重载方法createBitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter)
source资源
bitmap
x资源
bitmap的第一个像素的
x坐标
y资源
bitmap的第一个像素的
y坐标
m矩阵
filter是否过滤资源
bitmap
返回值 一个不可变的
btimap
由资源
bitmap根据坐标系截取创建一个新的
bitmap
createBitmap(Bitmap src)
createBitmap(Bitmap source, int x, int y, int width, int height)
1->2,2->本方法
本方法简单使用:
private void initView() { Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.m); Matrix matrix = new Matrix(); Bitmap b = bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),matrix,true); Log.e(TAG,"==bitmap-->"+bitmap.getConfig().name()+","+bitmap.getByteCount()+","+bitmap.getHeight()+","+bitmap.getWidth()); Log.e(TAG,"==b--->"+b.getConfig().name()+","+b.getByteCount()+","+b.getHeight()+","+b.getWidth()); }
需要注意:
x+
width<= 资源
bitmap.getWidth()
y+
height<= 资源
bitmap.getHeight()
createBitmap(int width, int height, Config config)
createBitmap(DisplayMetrics display, int width,int height, Config config)
private void initView() { Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.m); Bitmap b = bitmap.createBitmap(new DisplayMetrics(),10,10, Bitmap.Config.RGB_565); Bitmap b2 = bitmap.createBitmap(10,10, Bitmap.Config.RGB_565); Log.e(TAG,"==bitmap-->"+bitmap.getConfig().name()+","+bitmap.getByteCount()+","+bitmap.getHeight()+","+bitmap.getWidth()); Log.e(TAG,"==b--->"+b.getConfig().name()+","+b.getByteCount()+","+b.getHeight()+","+b.getWidth()); Log.e(TAG,"==b2--->"+b2.getConfig().name()+","+b2.getByteCount()+","+b2.getHeight()+","+b2.getWidth()); }
这两个方法最终都调用了一个没有对外公开的
private方法。返回值是一个可变的
bitmap
createBitmap(DisplayMetrics display, int colors[],int offset, int stride, int width, int height, Config config)
display
DisplayMetrics对象,指定初始密度
colors初始化颜色的数组,数组的长度至少大于
width*height
offset偏移量
stride
Number of colors in the array between rows (must be >=width or <= -width)并不理解作用
width
bitmap的宽
height
bitmap的高
config格式
返回值 一个不可变的
bitmap
createBitmap(int colors[], int width, int height, Config config)
createBitmap(DisplayMetrics display, int colors[], int width, int height, Config config)
createBitmap(int colors[], int offset, int stride, int width, int height, Config config)
1,2,3调用了本方法
本方法简单使用:
private void initView() { Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.m); Bitmap b = bitmap.createBitmap(new DisplayMetrics(),new int[]{10,20,30,40,50},0,1,1,1, Bitmap.Config.RGB_565); Log.e(TAG,"==bitmap-->"+bitmap.getConfig().name()+","+bitmap.getByteCount()+","+bitmap.getHeight()+","+bitmap.getWidth()); Log.e(TAG,"==b--->"+b.getConfig().name()+","+b.getByteCount()+","+b.getHeight()+","+b.getWidth()); }
这个方法并没有使用过。对参数要求比较多,使用时在源码中看一下参数要求。这个方法目前不清楚使用场景,只能遇到时,再次学习
3.4其他方法
方法 | 作用 |
---|---|
recycle() | 释放bitmap所占的内存 |
isRecycled() | 判断是否回收内存 |
getWidth() | 得到宽 |
getHeight | 得到高 |
isMutable() | 是否可以改变 |
sameAs(Bitmap other) | 判断两个bitmap大小,格式,像素信息是否相同 |
4.BitmapFactory.Options类
属性 | 作用 |
---|---|
boolean inJustDecodeBounds | 是否只扫描轮廓 |
int inSample | 采样率 |
Bitmap.Config inPreferredConfig | 格式,色彩模式 |
int outWidth | bitmap的宽 |
int outHeight | bitmap的高 |
boolean inDither | 防抖动,默认false |
int inDensity | 像素密度 |
boolean inScaled | 是否可以缩放,默认true |
boolean inMutable | 是否可变,设为ture, decode转换方法返回的结果全部可改变 |
5 最后
bitmap基础知识大概就了解这些,深入的知识就随着工作再学习。
相关文章推荐
- 【Android开发新手的学习笔记】异步加载知识梳理
- Android知识体系梳理笔记五:Kotlin学习笔记一:类和继承以及Anko(全)的基本使用
- Android知识体系梳理笔记四:组件化开发学习笔记
- Android知识体系梳理笔记五:Kotlin学习笔记二:空安全,操作符,Lambad表达式...
- Android Bitmap和Canvas学习笔记(转)
- Android Map开发基础知识学习笔记
- Android Map开发基础知识学习笔记(转)
- Android Bitmap和Canvas学习笔记
- 关于手机定时服务的小知识(Android学习随笔六)
- Android画图学习总结(二)——Bitmap
- Android Bitmap和Canvas学习笔记
- 关于TelephonyManager的使用与手机电池电量小知识(Android学习随笔五)
- Android画图学习总结(二)——Bitmap
- Android Bitmap和Canvas学习笔记
- Android Bitmap和 Canvas学习笔记
- Android Map开发基础知识学习笔记
- Android Map开发基础知识学习笔记
- Android Bitmap和Canvas学习笔记
- android学习必备java基础知识——内部类
- 关于Android初学者的学习线路的相关知识