获得清晰且占用native内存很小的bitmap
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
/**
* 图片采样,获得清晰且占用内存很小的bitmap(Bitmap对象由Native方法生成) 。类说明 : 图片大小修改 避免oom内存溢出;
* 暂时使用的方法都采用 decodeSampledBitmapFromPathMoreSafe(),后期需要用到其他方法,
* 按照decodeSampledBitmapFromPathMoreSafe重新修改,测试通过后在此记录,并更新备份此代码。 已修改代码:1、Bitmap
* decodeSampledBitmapFromPath(String path, int reqWidth, int reqHeight);
*
* @version 创建时间:2016年7月14日 下午1:45:06
*
*/
public class ImageResizer {
private static final String TAG = "ImageResizer";
public ImageResizer() {
}
// 传入资源文件,计算合适的大小,返回一个Bitmap对象
public Bitmap decodeSampledBitmapFromResource(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);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);// 或者其他方式
}
/**
* 为了加载文件系统的文件避免二次decodeStream返回null而专门调整的方法decode方法 解释:
* FileInputStream是一种有序的文件流,而两次的decodeStream调用影响了文件流的位置属性,
* 导致了第二次decodeStream时得到的是null,为了解决这个问题,可以通过文件流来得到他所对应的文件描述符, 然后在通过
* BitmapFactory.decodeFileDescriptor方法来加载一张缩放过的图片
*/
public Bitmap decodeSampledBitmapFromFileDescriptor(FileDescriptor fd,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFileDescriptor(fd, null, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFileDescriptor(fd, null, options);
}
/**
* 方法说明:可能还是解决不了内存溢出,最多捕获内存溢出。使用decodeSampledBitmapFromPathMoreSafe处理
*/
@Deprecated
public Bitmap decodeSampledBitmapFromPath(String path, int reqWidth,
int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
try {
return BitmapFactory.decodeFile(path, options);
} catch (OutOfMemoryError e) {
e.printStackTrace();
}
return null;
}
/**
* 20160918新增:inSampleSize 重新计算(之前的方法计算的值不够精确),并捕获异常。
* if(!bmp.isRecycle() ){ bmp.recycle() //回收图片所占的内存 system.gc() //提醒系统及时回收 }
* 从ImageView中获取
*/
public Bitmap decodeSampledBitmapFromPathMoreSafe(String path,
int reqWidth, int reqHeight) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inDither = false;
options.inPurgeable = true;
options.inTempStorage = new byte[12 * 1024];// 创建一个12kb的临时空间
options.inJustDecodeBounds = true;
File file = new File(path);
FileInputStream fs = null;
try {
fs = new FileInputStream(file);
BitmapFactory.decodeFileDescriptor(fs.getFD(), null, options);
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
// Calculate inSampleSize
// options.inSampleSize = calculateInSampleSize(options, reqWidth,
// reqHeight);
/**
* 使用此方法计算inSampleSize值 20160918新增
*/
final int minSideLength = Math.min(reqWidth, reqHeight);
options.inSampleSize = computeSampleSize(options, minSideLength,
reqWidth * reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
Bitmap bmp = null;
try {
fs = new FileInputStream(file);
if (fs != null)
bmp = BitmapFactory.decodeFileDescriptor(fs.getFD(), null,
options);
if (fs != null) {
fs.close();
fs = null;
}
return bmp;
} catch (Exception e) {
try {
if (fs != null) {
fs.close();
fs = null;
}
} catch (IOException e1) {
e1.printStackTrace();
}
Log.i("test",
"ImageResizer(图片压缩) decodeSampledBitmapFromPathMoreSafe 出现内存溢出 并返回null对象");
e.printStackTrace();
}
return null;
}
/**
* 方法说明: 直接使用 BitmapFactory.decodeStream(is) 返回空
*
* @version 创建时间:2016年8月16日 下午6:14:26
*
* @param is
* @param reqWidth
* @param reqHeight
* @return
*/
public Bitmap decodeSampledBitmapFromInputStream(InputStream is,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
Log.i("test", "decodeStream is0 == null " + String.valueOf(is == null));
byte[] data = null;
try {
data = readStream(is);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(data, 0, data.length, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
Bitmap decodeStream = BitmapFactory.decodeByteArray(data, 0,
data.length, options);
Log.i("test",
"decodeStream Bitmap == null "
+ String.valueOf(decodeStream == null));
Log.i("test", "decodeStream is1 == null " + String.valueOf(is == null));
Log.i("test", "decodeStream Bitmap size " + decodeStream.getByteCount());
Log.i("test", "decodeStream options.inSampleSize = "
+ options.inSampleSize);
return decodeStream;
}
/**
* 原始方法计算的inSampleSize值不够精确,容易导致oom
*/
public int calculateInSampleSize(BitmapFactory.Options options,
int reqWidth, int reqHeight) {
if (reqWidth == 0 || reqHeight == 0) {
return 1;
}
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
Log.d(TAG, "origin, w= " + width + " h=" + height);
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;
}
}
Log.d(TAG, "sampleSize:" + inSampleSize);
return inSampleSize;
}
public static int computeSampleSize(BitmapFactory.Options options,
int minSideLength, int maxNumOfPixels) {
int initialSize = computeInitialSampleSize(options, minSideLength,
maxNumOfPixels);
int roundedSize;
if (initialSize <= 8) {
roundedSize = 1;
while (roundedSize < initialSize) {
roundedSize <<= 1;
}
} else {
roundedSize = (initialSize + 7) / 8 * 8;
}
return roundedSize;
}
private static int computeInitialSampleSize(BitmapFactory.Options options,
int minSideLength, int maxNumOfPixels) {
double w = options.outWidth;
double h = options.outHeight;
int lowerBound = (maxNumOfPixels == -1) ? 1 : (int) Math.ceil(Math
.sqrt(w * h / maxNumOfPixels));
int upperBound = (minSideLength == -1) ? 128 : (int) Math.min(
Math.floor(w / minSideLength), Math.floor(h / minSideLength));
if (upperBound < lowerBound) {
// return the larger one when there is no overlapping zone.
return lowerBound;
}
if ((maxNumOfPixels == -1) && (minSideLength == -1)) {
return 1;
} else if (minSideLength == -1) {
return lowerBound;
} else {
return upperBound;
}
}
/*
* 得到图片字节流 数组大小
*/
public static byte[] readStream(InputStream inStream) throws Exception {
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = inStream.read(buffer)) != -1) {
outStream.write(buffer, 0, len);
}
outStream.close();
inStream.close();
return outStream.toByteArray();
}
}