BitmapFactory.Options的属性解析
BitmapFactory.Options中有以下属性:inBitmap——在解析Bitmap时重用该Bitmap,不过sdk11->18必须等大的Bitmap,
sdk19以上新的bitmap需小于或等于旧的Bitmap,而且inMutable须为
true
inMutable——配置Bitmap是否可以更改,比如:在Bitmap上隔几个像素加一条线段
inJustDecodeBounds——为
true
仅返回Bitmap的宽高等属性
inSampleSize——须>=
1
,表示Bitmap的压缩比例,如:inSampleSize=
4,代表宽高压缩为原来的1/4,
返回一个是原始图的
1
/
16
大小的Bitmap
inPreferredConfig——Bitmap.Config.ARGB_8888等
inDither——是否抖动,默认为
false
inPremultiplied——默认为
true
,一般不改变它的值
inDensity——Bitmap的像素密度
inTargetDensity——Bitmap最终的像素密度
inScreenDensity——当前屏幕的像素密度
inScaled——是否支持缩放,默认为
true
,当设置了这个,Bitmap将会以inTargetDensity的值进行缩放
inPurgeable——当存储Pixel的内存空间在系统内存不足时是否可以被回收
inInputShareable——inPurgeable为
true
情况下才生效,是否可以共享一个InputStream
inPreferQualityOverSpeed——为
true
则优先保证Bitmap质量其次是解码速度
outWidth——返回的Bitmap的宽
outHeight——返回的Bitmap的高
inTempStorage——解码时的临时空间,建议
16
*
1024
优化策略
1、BitmapConfig的配置
2、使用decodeFile、decodeResource、decodeStream进行解析Bitmap时,配置inDensity和inTargetDensity,
两者应该相等,值可以等于屏幕像素密度*0.75f
3、使用inJustDecodeBounds预判断Bitmap的大小及使用inSampleSize进行压缩
4、对Density>240的设备进行Bitmap的适配(缩放Density)
5、2.3版本inNativeAlloc的使用
6、4.4以下版本inPurgeable、inInputShareable的使用
7、Bitmap的回收
针对上面方案,把Bitmap解码的代码封装成了一个工具类,如下:
public class BitmapDecodeUtil {
private static final int DEFAULT_DENSITY = 240;
private static final float SCALE_FACTOR = 0.75f;
private static final Bitmap.Config DEFAULT_BITMAP_CONFIG = Bitmap.Config.RGB_565;
private static BitmapFactory.Options getBitmapOptions(Context context) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = true;
options.inPreferredConfig = DEFAULT_BITMAP_CONFIG;
options.inPurgeable = true;
options.inInputShareable = true;
options.inJustDecodeBounds = false;
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) {
Field field = null;
try {
field = BitmapFactory.Options.class.getDeclaredField("inNativeAlloc");
field.setAccessible(true);
field.setBoolean(options, true);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
int displayDensityDpi = context.getResources().getDisplayMetrics().densityDpi;
float displayDensity = context.getResources().getDisplayMetrics().density;
if (displayDensityDpi > DEFAULT_DENSITY && displayDensity > 1.5f) {
int density = (int) (displayDensityDpi * SCALE_FACTOR);
options.inDensity = density;
options.inTargetDensity = density;
}
return options;
}
public static Bitmap decodeBitmap(Context context, int resId) {
checkParam(context);
return BitmapFactory.decodeResource(context.getResources(), resId, getBitmapOptions(context));
}
public static Bitmap decodeBitmap(Context context, String pathName) {
checkParam(context);
return BitmapFactory.decodeFile(pathName, getBitmapOptions(context));
}
public static Bitmap decodeBitmap(Context context, InputStream is) {
checkParam(context);
checkParam(is);
return BitmapFactory.decodeStream(is, null, getBitmapOptions(context));
}
public static Bitmap compressBitmap(Context context,int resId, int maxWidth, int maxHeight) {
checkParam(context);
final TypedValue value = new TypedValue();
InputStream is = null;
try {
is = context.getResources().openRawResource(resId, value);
return compressBitmap(context, is, maxWidth, maxHeight);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
public static Bitmap compressBitmap(Context context, String pathName, int maxWidth, int maxHeight) {
checkParam(context);
InputStream is = null;
try {
is = new FileInputStream(pathName);
return compressBitmap(context, is, maxWidth, maxHeight);
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
public static Bitmap compressBitmap(Context context, InputStream is, int maxWidth, int maxHeight) {
checkParam(context);
checkParam(is);
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inJustDecodeBounds = true;
BitmapFactory.decodeStream(is, null, opt);
int height = opt.outHeight;
int width = opt.outWidth;
int sampleSize = computeSampleSize(width, height, maxWidth, maxHeight);
BitmapFactory.Options options = getBitmapOptions(context);
options.inSampleSize = sampleSize;
return BitmapFactory.decodeStream(is, null, options);
}
private static int computeSampleSize(int width, int height, int maxWidth, int maxHeight) {
int inSampleSize = 1;
if (height > maxHeight || width > maxWidth) {
final int heightRate = Math.round((float) height / (float) maxHeight);
final int widthRate = Math.round((float) width / (float) maxWidth);
inSampleSize = heightRate < widthRate ? heightRate : widthRate;
}
if (inSampleSize % 2 != 0) {
inSampleSize -= 1;
}
return inSampleSize <= 1 ? 1 : inSampleSize;
}
private static <t> void checkParam(T param){
if(param == null)
throw new NullPointerException();
}
}
主要有两类方法:
一、decodeBitmap:对Bitmap不压缩,但是会根据屏幕的密度合适的进行缩放压缩
二、compressBimtap:对Bitmap进行超过最大宽高的压缩,同时也会根据屏幕的密度合适的进行缩放压缩。
本文转自http://www.2cto.com/kf/201602/490655.html#0-tsina-1-36305-397232819ff9a47a7b7e80a40613cfe1