code 方法区 stack 栈区 graphics opengl gup内存 native java 堆区
图像展示原理
- 屏幕图像是由一个一个像素点拼接成的
- 1080*1920 px 代表 每一行有1080个像素点 有1920行
- 屏幕图像是由一个一个像素点的不同颜色拼接而成
- 每个像素点的颜色大小由展示类型决定
- bitmap 展示内容就是一组颜色的二位数组
图像大小换算
A:透明度 R:红色 G:绿 B:蓝
Bitmap.Config ARGB_4444:每个像素占四位,即A=4,R=4,G=4,B=4,那么一个像素点占4+4+4+4=16位
Bitmap.Config ARGB_8888:每个像素占四位,即A=8,R=8,G=8,B=8,那么一个像素点占8+8+8+8=32位=4字节
Bitmap.Config RGB_565:每个像素占四位,即R=5,G=6,B=5,没有透明度,那么一个像素点占5+6+5=16位
Bitmap.Config ALPHA_8:每个像素占四位,只有透明度,没有颜色。
//计算大小
假设有一张480x800的图片,如果格式为ARGB_8888,那么将会占用1500KB的内存。
480*800*4=1536KB
Bitmap 对象的产生
Bitmap 对象大小只跟width、height、colorType有关
//创建Bitmap对象
//传入的宽高影响Bitmap大小
Bitmap bm = Bitmap.createBitmap(dest, width, height, Config.RGB_565);
//内部通过native 层产生对象.
Bitmap bm = nativeCreate(colors, offset, stride, width, height,config.nativeInt, false, null, null);
// 调用链nativeCreate -- > Bitmap_creator
//创建SKBitmao 对象
SkBitmap bitmap;
设置参数
bitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType, colorSpace));
//申请bitmap大小
sk_sp<Bitmap> nativeBitmap = Bitmap::allocateHeapBitmap(&bitmap, NULL);
if (!nativeBitmap) {
return NULL;
}
- 源码JNI 地址
Bitmap.java
- 无法获取到真正的bitmap native层只返回了bitmap对象的指针地址
mNativePtr = nativeBitmap;
- java层将long 类型指针地址传递给native 可以获取到对象地址
native 层Bitmap 显示原理
//绘制操作
AndroidBitmapInfo info;
//根据java层的bitmap对象获取到native需要的AndroidBitmapInfo对象内的信息
AndroidBitmap_getInfo(env, bitmap, &info);
int width = info.width;
int height = info.height;
LOGE("宽%d 高%d: ",width,height);
//此处相等于是二级指针1080*1920,对二级指针每一个像素点复制则可以绘制出当前像素矩阵图像
int *pixels=NULL;
//2 我们要拿到native层的那个指针,指针代表需要展示图片的第一个像素点的指针
AndroidBitmap_lockPixels(env, bitmap, reinterpret_cast<void **>(&pixels));
// pixels hua
int* px = (int *)pixels;
int *line;
for (int y =0 ; y<frameInfo.Height; ++y) {
line = px;
for (int x = 0; x < frameInfo.Width ; ++x) {
// 里面写出 数据
pointPixel = (y ) * frameInfo.Width + (x);
gifByteType= savedImage.RasterBits[pointPixel];
gifColorType= colorMapObject->Colors[gifByteType];
//对矩阵的每一个像素点赋值
line[x] = argb(255, gifColorType.Red, gifColorType.Green, gifColorType.Blue);
}
px = px + info.stride / 4;
}
AndroidBitmap_unlockPixels(env, bitmap);
gif
- gif 不是一张一张图片叠加
- gif 是第一帧颜色值数据和后面每一帧颜色差异值的集合体。
- native 加载 gif 内存开销小
// 取出待绘制的第几帧
SavedImage savedImage = gifFileType->SavedImages[gifBean->current_frame];
// savedImage数据 怎么 最大难题
GifImageDesc frameInfo= savedImage.ImageDesc;
// 颜色表
// 数组下标 索引的
int pointPixel;
//颜色表的索引
GifByteType gifByteType;
//颜色
GifColorType gifColorType;
ColorMapObject *colorMapObject = frameInfo.ColorMap;
int* px = (int *)pixels;
int *line;
for (int y =0 ; y<frameInfo.Height; ++y) {
line = px;
for (int x = 0; x < frameInfo.Width ; ++x) {
// 里面写出 数据
pointPixel = (y ) * frameInfo.Width + (x);
gifByteType= savedImage.RasterBits[pointPixel];
//取出map中的颜色值
gifColorType= colorMapObject->Colors[gifByteType];
//对应像素点上复制
line[x] = argb(255, gifColorType.Red, gifColorType.Green, gifColorType.Blue);
}
px = px + info.stride / 4;
}
图片压缩手段
- 尺寸压缩
- 质量压缩
- Skia (封装的jpej)
Android系统在7.0版本之前内部使用的是libjpeg非turbo版,并且为了性能关闭了Huffman编码。在7.0之后的系统内部使用了libjpeg-turbo库并且启用Huffman编码 - jpej引擎
- 自定义图片压缩,实现Luban原理
- jpej使用 参考simple
- 抽离a、r、g、b 配套 jpej 进行huffman进行图片压缩
- Luban
- huffman无损原理与使用
Bitmap优化与原理
- Bitmap大小只与宽高有关可以尽量复用
- Bitmap 内存属于Native层
- 尺寸优化
- 内存优化
- 大图原理:加载显示区域大小的分辨率图片
//获取Bitmap解码器 mDecoder = BitmapRegionDecoder.newInstance(is, false); //核心-区域解码只加载对应区域需要的分辨率 Bitmap bitmap = mDecoder.decodeRegion(mRect, mDecodeOptions); //放大从模糊到清晰原理- 先把加载出来的布局直接放大,在开启任务获取需要加载区域的原图分辨率替换当前布局Bitmap //其他-- 根据自己的逻辑去做缩放 滑动等操作