安卓开发图片压缩一直是一个头痛的问题,一不小心就会
oom
。
我对一个github
上的库就行了简单的改写,把代码记录下来,自己也梳理了下图片压缩的过程。
本文的代码参考自github项目 Compressor,我只是进行了我认为需要的改动
尺寸压缩
尺寸压缩也就是按比例压缩尺寸,当我们需要显示图片时,控件加载的是
bitmap
,而bitmap
的大小主要和尺寸和图片格式有关,这时候我们不需要进行质量压缩
计算采样比(图片压缩比例)
1234567891011121314151617private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {// 获得原始宽高final int height = options.outHeight;final int width = options.outWidth;//默认为1(不压缩)int inSampleSize = 1;if (height > reqHeight || width > reqWidth) {//压缩到宽高都小于我们要求的大小while ((height / inSampleSize) >= reqHeight || (width / inSampleSize) >= reqWidth) {//android内部只会取2的倍数,也就是一半一半的压缩inSampleSize *= 2;}}return inSampleSize;}压缩尺寸
12345678910111213141516171819202122232425262728293031static Bitmap decodeSampledBitmapFromFile(File imageFile, int reqWidth, int reqHeight) throws IOException {BitmapFactory.Options options = new BitmapFactory.Options();//设置inJustDecodeBounds=true,时BitmapFactory加载图片不返回bitmap,只返回信息,减少内存开销options.inJustDecodeBounds = true;//相当于加载空图片获取尺寸信息BitmapFactory.decodeFile(imageFile.getAbsolutePath(), options);//用我们上面的方法计算压缩比例options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);//设置inJustDecodeBounds=false,返回bitmapoptions.inJustDecodeBounds = false;Bitmap scaledBitmap = BitmapFactory.decodeFile(imageFile.getAbsolutePath(), options);//把图片旋转成正确的方向ExifInterface exif = new ExifInterface(imageFile.getAbsolutePath());int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0);Matrix matrix = new Matrix();if (orientation == 6) {matrix.postRotate(90);} else if (orientation == 3) {matrix.postRotate(180);} else if (orientation == 8) {matrix.postRotate(270);}//复制一份旋转后的bitmap后返回scaledBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0, scaledBitmap.getWidth(),scaledBitmap.getHeight(), matrix, true);return scaledBitmap;}
质量压缩
质量压缩代码比较简单但要注意非常耗时
12345678910111213141516171819 private static ByteArrayOutputStream compressBitmapSize(Bitmap bitmap, Bitmap.CompressFormat compressFormat,int defaultQuality, long maxSize) {ByteArrayOutputStream baos = new ByteArrayOutputStream();int quality = defaultQuality;bitmap.compress(compressFormat, quality, baos);//当大于我们指定的大小时,我就继续压缩while (baos.toByteArray().length / 1024 > maxSize) {if (quality <= 10) { //压缩比例要大于0break;} else {baos.reset();quality -= 10;//quality 表示压缩多少 100 表示不压缩bitmap.compress(compressFormat, quality, baos);}}return baos;}
完整的压缩工具类
|
|
封装成一个工厂模式工具类
|
|
使用
推荐大家使用WEBP格式的图片,内存更小(png无损格式很大)而且不会损失透明度(jpg没有透明)
简单用法
123File file = new Compressor(CompressorActivity.this).compressToFile(getExternalCacheDir().getAbsoluteFile(),UUID.randomUUID().toString() + ".jpg");指定压缩的参数
12345678File file = new Compressor(CompressorActivity.this).setMaxWidth(1080).setMaxHeight(1080).setQuality(75).setMaxSize(100).setCompressFormat(Bitmap.CompressFormat.WEBP).setDestinationDirectoryPath(getExternalCacheDir().getAbsolutePath()).compressToFile(new File(getPath(CompressorActivity.this, uri)), UUID.randomUUID().toString() + ".webp");