首先扯点别的:最近上海的天气也是热的不得了,早上跑步也不合适了,中午吃饭也没胃口。
今天记录一下Android中的图片压缩。注意,为了简单,代码中需要的读写存储空间的权限已经在上一个页面申请过了。
尺寸压缩
改变图片的尺寸,比如说原来是1280×1902的变成640×320的。压缩图片的尺寸可以减少图片占用的内存大小。
获取一个Bitmap占用内存大小的方法,可以使用Bitmap的getByteCount()方法。
/**
* Returns the minimum number of bytes that can be used to store this bitmap's pixels.
*/
public final int getByteCount() {
// int result permits bitmaps up to 46,340 x 46,340
return getRowBytes() * getHeight();
}
举个例子:从drawable目录下加载一张图片到ImageView上,对比不使用尺寸压缩和使用尺寸压缩后,bitmap所占用的内存。(ImageView的宽为200dp,高为140dp)
先把上面的图片放到drawable-xxhdpi目录下。
不使用尺寸压缩
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_compress);
ButterKnife.bind(this);
Bitmap bitmap = ImageUtil.getBitmapFromResource(getResources(), R.drawable.airplane);
Log.e(TAG, "bitmap占用的内存" + bitmap.getByteCount()/1024/1024 + "MB");
imgLarge.setImageBitmap(bitmap);
}
public static Bitmap getBitmapFromResource(Resources res, int resId) {
return BitmapFactory.decodeResource(res, resId);
}
占用的内存
CompressActivity: bitmap占用的内存8MB
使用尺寸压缩
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_compress);
ButterKnife.bind(this);
//把dp转化成px
width = ScreenUtil.dipToPx(this, 200);
height = ScreenUtil.dipToPx(this, 140);
Bitmap bitmap = ImageUtil.getSampledBitmapFromResource(getResources(), R.drawable.airplane, width, height);
Log.e(TAG, "bitmap占用的内存" + bitmap.getByteCount()/1024/1024 + "MB");
imgLarge.setImageBitmap(bitmap);
}
public static Bitmap getSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
/**
* @param options options
* @param reqWidth 目标宽度
* @param reqHeight 目标高度
* @return inSampleSize 指示了在解析图片为Bitmap时在长宽两个方向上像素缩小的倍数
*/
private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) >= reqHeight
&& (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
使用尺寸压缩后,占用的内存
CompressActivity: bitmap占用的内存2MB
可以看到根据ImageView的大小来对要加载的图片进行尺寸压缩,可以明显减少图片占用内存的大小。
质量压缩
改变图片所占的存储空间的大小,比如把一个3M的图片压缩到400KB。
当我们在浏览一些新闻,想要把图片保存到手机上的时候,就应该使用质量压缩。
把这个ImageView(尺寸200dp×140dp)上的图片保存到本地。
/**
* 把imageView上的bitmap保存到本地,直接在主线程保存
*/
@OnClick(R.id.btn_save_bitmap)
public void saveBitmap() {
String destination = null;
imgLarge.setDrawingCacheEnabled(true);
Bitmap bitmap = imgLarge.getDrawingCache();
if (bitmap != null) {
try {
destination = ImageUtil.compressImage(CompressActivity.this, bitmap, 70);
} catch (IOException e) {
e.printStackTrace();
}
if (TextUtils.isEmpty(destination)) {
Toast.makeText(CompressActivity.this, "保存失败", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(CompressActivity.this, "保存成功", Toast.LENGTH_SHORT).show();
}
}
imgLarge.setDrawingCacheEnabled(false);
}
/**
* @param context 上下文对象
* @param bitmap 要存在
* @param quantity 压缩质量
* @return 存储的压缩后的路径
* @throws FileNotFoundException
*/
public static String compressImage(Context context, Bitmap bitmap, int quantity) throws IOException {
File imageFile = createImageFile();
FileOutputStream out = new FileOutputStream(imageFile);
bitmap.compress(Bitmap.CompressFormat.JPEG, quantity, out);
out.flush();
out.close();
//通知媒体扫描器扫描文件
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri contentUri = Uri.fromFile(imageFile);
mediaScanIntent.setData(contentUri);
context.sendBroadcast(mediaScanIntent);
} else {
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + imageFile.getAbsoluteFile())));
}
return imageFile.getPath();
}
/**
* 创建图片File对象
*
* @return
*/
public static File createImageFile() {
File imageFile = null;
String storagePath;
File storageDir;
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
try {
storagePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsolutePath() + File.separator + "camerademo";
storageDir = new File(storagePath);
storageDir.mkdirs();
imageFile = File.createTempFile(timeStamp, ".jpg", storageDir);
} catch (IOException e) {
e.printStackTrace();
}
return imageFile;
}
这个图片原来的大小是290KB,尺寸是1920×1200。采用质量压缩后的大小是52KB,尺寸是600×420,压缩效果还是不错的。而且图片也没失真。
总结:当我们要把图片加载到内存中,应该使用尺寸压缩。当我们要把图片保存的本地,应该使用质量压缩。质量压缩并不能减少图片所占用的内存。如果我们要把图片传输到网络上,可以先把图片进行尺寸压缩加载到应用中,然后把加载进来的图片再进行质量压缩,然后再保存到手机中。我们传输这个压缩后的图片即可。(省流量)
参考链接
【1】http://blog.csdn.net/love_techlive/article/details/52024844