1、圖片壓縮
知識點:
inDensity 原始密度:爲0則設置爲默認 160dpi; 文件夾代表密度
inTargetDensity 顯示目標圖片密度
inScreenDensity 屏幕密度
原因:
直接顯示Bitmap佔用內存會過大導致內存溢出OOM問題:
粗略方式:
計算公式:圖片長 * 寬 * 4bytes/ARG_8888 - 不正確Native 方法中,mBitmapWidth = mOriginalWidth * (scale = opts.inTargetDensity / opts.inDensity) * 1/inSampleSize,
mBitmapHeight = mOriginalHeight * (scale = opts.inTargetDensity / opts.inDensity) * 1/inSampleSize
例如:
將一張 720x1080圖片放在 drawable-xhdpi 目錄下(inDensity = 320),
- 在 720x1080 手機上加載(inTargetDensity = 320),圖片不會被壓縮;
- 在 480x800 手機上加載(inTargetDensity = 240),圖片會被壓縮 9/16;
- 在 1080x1920 手機上加載(inTargetDensity = 480),圖片會被放大 2.25;
手機屏幕大小 1280 x 720(inTarget = 320),加載 xxhdpi (inDensity = 480)中的圖片 1920 x 1080,scale = 320 / 480,inSampleSize = 1,最終獲得的 Bitmap 的圖像大小是 :
mBitmapWidth = opts.outWidth = 1080 * (320 / 480) * 1/1 = 720,
mBitmapHeight = opt.outHeight = 1920 * (320 / 480) * 1/1 = 1280,
getAllocatedMemory() = mBitmapWidth * mBitmapHeight * 4 = Bitmap佔用內存。
圖片壓縮
BitmapFactory.Options
2、利用inJustDecodeBounds參數不分配bitmap獲取原始圖片寬、高:
inJustDecodeBounds:爲true時僅返回 Bitmap 寬高等屬性,返回bmp=null,爲false時才返回佔內存的 bmp;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;//不分配bitmap內存:不會造成內存溢出OOM
/**
* decodeFile 本地文件
* decodeStream 網絡上的圖片
* decodeResource 資源文件中圖片
*/
BitmapFactory.decodeFile(path, options);
int outHeight = options.outHeight;
int outWidth = options.outWidth;
2、獲取計算inSampleSize對寬、高,壓縮
inSampleSize:表示 Bitmap 的壓縮比例,值必須 > 1 & 是2的冪次方。inSampleSize = 2 時,表示壓縮寬高各1/2,最後返回原始圖1/4大小的Bitmap;
public static int calculateInSampleSize(BitmapFactory.Options options,
int reqWidth, int reqHeight) {
// 源圖片的高度和寬度
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
// 計算出實際寬高和目標寬高的比率
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// 選擇寬和高中最小的比率作爲inSampleSize的值,這樣可以保證最終圖片的寬和高
// 一定都會大於等於目標的寬和高。
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
return inSampleSize;
}
3、最終代碼:
public class TestActivity extends RootActivity {
private ImageView imageView;
private Handler handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case 1:
imageView.setImageBitmap(bitmap);
break;
case 2:
RingToast.show("bitmap= null");
break;
}
return false;
}
});
@Override
protected void onInit() {
super.onInit();
setContentView(R.layout.activity_test);
}
@Override
protected void onFindViews() {
super.onFindViews();
imageView = findViewById(R.id.imageView);
}
public void onClick(View view) {
RingToast.show("下載");
if (view.getId() == R.id.localBtn) {
showResources();
} else
new DownloadImage("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1585219233084&di=3f992df116687f73f7174be2d602389b&imgtype=0&src=http%3A%2F%2Fa3.att.hudong.com%2F68%2F61%2F300000839764127060614318218_950.jpg").start();
}
private Bitmap bitmap;
private class DownloadImage extends Thread {
String path;
public DownloadImage(String path) {
this.path = path;
}
@Override
public void run() {
super.run();
HttpURLConnection urlConnection = null;
InputStream inputStream = null;
try {
URL url = new URL(path);
//保存本地
urlConnection = (HttpURLConnection) url.openConnection();
inputStream = urlConnection.getInputStream();
File file = createDir(Config.CAMERA_CLASS_PATH + File.separator + "原始圖片" + ".jpg");
FileOutputStream outputStream = new FileOutputStream(file);
int hasRead = 0;
while ((hasRead = inputStream.read()) != -1) {
outputStream.write(hasRead);
}
outputStream.close();
//獲取原圖片尺寸
urlConnection = (HttpURLConnection) url.openConnection();
inputStream = urlConnection.getInputStream();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(inputStream, null, options);
inputStream.close();
//獲取壓縮係數
BitmapFactory.Options options2 = new BitmapFactory.Options();
options2.inSampleSize = ImageToolsUtils.calculateInSampleSize(options, ScreenUtils.getScreenWidth(TestActivity.this), ScreenUtils.getScreenHeight(TestActivity.this));
// options2.inSampleSize = 1;
options2.inJustDecodeBounds = false;
//獲取最終壓縮圖片bitmap
urlConnection = (HttpURLConnection) url.openConnection();
inputStream = urlConnection.getInputStream();
bitmap = BitmapFactory.decodeStream(inputStream, null, options2);
FileUtil.saveBitmap(bitmap);
if (bitmap != null) {
Message message = new Message();
message.what = 1;
handler.sendMessage(message);
} else {
Message message = new Message();
message.what = 2;
handler.sendMessage(message);
}
} catch (Exception e) {
RingLog.e("訪問網絡異常:" + e.getMessage());
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
}
}
}
}
private void showResources() {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = false;
Bitmap bm = BitmapFactory.decodeResource(getResources(), R.mipmap.launch_welcome, options);
FileUtil.saveBitmap(bm);
//獲取壓縮係數
options.inSampleSize = ImageToolsUtils.calculateInSampleSize(options, 300, 300);
options.inJustDecodeBounds = false;
//獲取最終壓縮圖片bitmap
bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.launch_welcome, options);
FileUtil.saveBitmap(bitmap);
if (bitmap != null) {
Message message = new Message();
message.what = 1;
handler.sendMessage(message);
} else {
Message message = new Message();
message.what = 2;
handler.sendMessage(message);
}
}
}
參考:
https://www.jianshu.com/p/4ba3e63c8cdc
https://www.tuicool.com/articles/3eMNr2n
https://blog.csdn.net/guolin_blog/article/details/9316683