admin 管理员组文章数量: 887021
android获取位图字节数,Android
1.基本概念
densityDpi?
这是屏幕像素密度,一英寸屏幕有多个像素点。
通过以下方法可以获取
float densityDpi= getResources().getDisplayMetrics().densityDpi;
打印日志,我手机的densityDpi是480。
2020-08-28 11:20:07.242 20647-20647/com.yang.memorytest D/test: densityDpi=480.0
2.图片占用内存大小如何计算?
这里讨论的是占用内存大小,跟存储文件大小不是一个概念。
以下是Bitmap提供的两个获取图片占用内存大小的方法,
public final int getByteCount();
public final int getAllocationByteCount();
(1)getByteCount(),获取图片占用内存大小的理论值;
(2)getAllocationByteCount(),获取图片占用内存大小的实际值;
怎么理解理论值跟实际值呢?
这跟Bitmap内存复用有关。如果图片加载到内存,是存放在新开辟的内存空间里,那么理论值跟实际值相等,如果是复用其他Bitmap的内存空间,而这个空间比图片所需的空间大,那么实际值大于理论值。
有兴趣的,可以自己研究下 BitmapFactory.Options的inBitmap属性。
除了以上在运行时调用方法来获取图片占用大小以外,还可以自己计算。
图片大小=长宽每个像素占的字节数
ARGB8888的图片,每个像素占4个字节;
RGB565的图片,每个像素占2个字节;
有一张宽640 长1136的图片,存放在drawable-xxhdpi文件下,刚好匹配我手机的480dpi,ARGB8888加载为例,
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.rtoy_splash);
Log.d("test", "bitmap.getWidth()=" + bitmap.getWidth());
Log.d("test", "bitmap.getHeight()=" + bitmap.getHeight());
Log.d("test", "bitmap size=" + bitmap.getWidth() * bitmap.getHeight() * 4);
Log.d("test", "bitmap.getAllocationByteCount()=" + bitmap.getAllocationByteCount());
Log.d("test", "bitmap.getByteCount()=" + bitmap.getByteCount());
BitmapFactory.decodeResource默认情况下采用ARGB8888加载,
从日志中可以看出,图片占用内存2908160B,跟getByteCount、getByteCount获取的结果一致。
2020-08-28 14:37:50.529 24368-24368/com.yang.memorytest D/test: bitmap.getWidth()=640
2020-08-28 14:37:50.529 24368-24368/com.yang.memorytest D/test: bitmap.getHeight()=1136
2020-08-28 14:37:50.529 24368-24368/com.yang.memorytest D/test: bitmap size=2908160
2020-08-28 14:37:50.529 24368-24368/com.yang.memorytest D/test: bitmap.getAllocationByteCount()=2908160
2020-08-28 14:37:50.529 24368-24368/com.yang.memorytest D/test: bitmap.getByteCount()=2908160
缩放系数
当图片资源所在文件夹与手机dpi不一致时,图片加载进来会被缩放。
缩放系数=手机dpi/图片资源所在文件夹dpi
序号
文件夹
dpi
匹配dpi区间
1
drawable-mdpi
160
120-160,包含160
2
drawable-hdpi
240
160-240,包含240
3
drawable-xhdpi
320
240-320,包含320
4
drawable-xxhdpi
480
320-480,包含480
5
drawable-xxxhdpi
640
480-640,包含640
6
drawable
160
160
如果手机是480dpi,图片放在drawable-xxhdpi,缩放系数是480/480=1;
如果手机是480dpi,图片放在drawable-xxxhdpi,缩放系数是480/640=0.75;
图片大小计算公式要发生变化:
图片大小=长宽每个像素占的字节数*缩放系数
同样以加载宽640 长1136的图片,用ARGB8888加载为例,图片放在drawable-xxxhdpi文件夹下(手机是480dpi),
加载代码不变,打印结果如下:
从日志可以看出,图片被缩放了,宽由640缩放成480,系数是0.75。
2020-08-28 14:54:53.132 24371-24371/com.yang.memorytest D/test: bitmap.getWidth()=480
2020-08-28 14:54:53.132 24371-24371/com.yang.memorytest D/test: bitmap.getHeight()=852
2020-08-28 14:54:53.132 24371-24371/com.yang.memorytest D/test: bitmap size=1635840
2020-08-28 14:54:53.132 24371-24371/com.yang.memorytest D/test: bitmap.getAllocationByteCount()=1635840
2020-08-28 14:54:53.132 24371-24371/com.yang.memorytest D/test: bitmap.getByteCount()=1635840
如果图片放在drawable-nodpi、raw、assert文件下,加载时不做任何缩放,原样输出。
2.源码分析
源码分析基于Android-28
BitmapFactory.decodeResource,
主要工作:
(1)构建value获取图片参数,包含图片所在文件夹dpi;
(2)res.openRawResource,加载图片流;
(3)调用res.openRawResource解析图片;
public static Bitmap decodeResource(Resources res, int id, Options opts) {
validate(opts);
Bitmap bm = null;
InputStream is = null;
try {
final TypedValue value = new TypedValue();
is = res.openRawResource(id, value);
bm = decodeResourceStream(res, value, is, null, opts);
} catch (Exception e) {
}
......
return bm;
}
BitmapFactory.decodeResourceStream
主要工作:
(1)判断条件density == TypedValue.DENSITY_DEFAULT是否成立,成立,那就是图片在drawable文件夹下,opts.inDensity赋值为160;
(2)判断条件density != TypedValue.DENSITY_NONE是否成立,成立,那就是图片没有在drawable-nodpi文件夹下,opts.inDensity就是文件夹dpi;
(3)当图片在drawable-nodpi文件夹下,opts.inDensity赋值为0;
(4)opts.inTargetDensity赋值为手机dpi。
public static Bitmap decodeResourceStream(@Nullable Resources res, @Nullable TypedValue value,
@Nullable InputStream is, @Nullable Rect pad, @Nullable Options opts) {
validate(opts);
if (opts == null) {
opts = new Options();
}
if (opts.inDensity == 0 && value != null) {
final int density = value.density;
if (density == TypedValue.DENSITY_DEFAULT) {
opts.inDensity = DisplayMetrics.DENSITY_DEFAULT;
} else if (density != TypedValue.DENSITY_NONE) {
opts.inDensity = density;
}
}
if (opts.inTargetDensity == 0 && res != null) {
opts.inTargetDensity = res.getDisplayMetrics().densityDpi;
}
return decodeStream(is, pad, opts);
}
BitmapFactory.decodeStream->decodeStreamInternal->BitmapFactory.cpp.nativeDecodeStream->doDecode
主要工作:
(1)根据图片所在dpi、手机dpi,计算缩放系数,scale = (float) targetDensity / density(手机dpi除以图片资源所在文件夹dpi);
(2)如果设置了BitmapFactory.Options inSampleSize,根据参数进行缩放;
(3)根据(1)得到的缩放系数进行缩放,结果四舍五入;
(4)注意:当图片放在drawable-nodpi文件夹下,获取到的density 为0,那么scale默认就是1,不进行缩放。
static jobject doDecode(JNIEnv* env, std::unique_ptr stream,
jobject padding, jobject options) {
...
//(1)
if (env->GetBooleanField(options, gOptions_scaledFieldID)) {
const int density = env->GetIntField(options, gOptions_densityFieldID);
const int targetDensity = env->GetIntField(options, gOptions_targetDensityFieldID);
const int screenDensity = env->GetIntField(options, gOptions_screenDensityFieldID);
if (density != 0 && targetDensity != 0 && density != screenDensity) {
scale = (float) targetDensity / density;
}
}
...
//(2)
if (needsFineScale(codec->getInfo().dimensions(), size, sampleSize)) {
willScale = true;
scaledWidth = codec->getInfo().width() / sampleSize;
scaledHeight = codec->getInfo().height() / sampleSize;
}
....
if (scale != 1.0f) {
willScale = true;
scaledWidth = static_cast(scaledWidth * scale + 0.5f);
scaledHeight = static_cast(scaledHeight * scale + 0.5f);
}
...
}
总结:
(1)图片大小=长宽每个像素占的字节数*缩放系数;
(2)缩放系数=手机dpi/图片资源所在文件夹dpi;
(3)如果图片放在drawable-nodpi、raw、assert文件下,加载时不做任何缩放,原样输出。
以上分析有不对的地方,请指出,互相学习,谢谢哦!
本文标签: android获取位图字节数 Android
版权声明:本文标题:android获取位图字节数,Android 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.freenas.com.cn/free/1700347868h407578.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论