@Nullable
public static Bitmap decodeResourceStream(@Nullable Resources res, @Nullable TypedValue value,
@Nullable InputStream is, @Nullable Rect pad, @Nullable Options opts) {
validate(opts);
if (opts == null) {
opts = new Options();
}
if (opts.inDensity == 0 && value != null) {
final int density = value.density;
if (density == TypedValue.DENSITY_DEFAULT) {
opts.inDensity = DisplayMetrics.DENSITY_DEFAULT;
} else if (density != TypedValue.DENSITY_NONE) {
opts.inDensity = density;
}
}
if (opts.inTargetDensity == 0 && res != null) {
opts.inTargetDensity = res.getDisplayMetrics().densityDpi;
}
return decodeStream(is, pad, opts);
}
複製代碼
/**
* 第一種:質量壓縮法
* @param image 目標原圖
* @param maxSize 最大的圖片大小
* @return bitmap,注意能夠測試如下壓縮先後bitmap的大小值
*/
public static Bitmap compressImage(Bitmap image , long maxSize) {
int byteCount = image.getByteCount();
Log.i("yc壓縮圖片","壓縮前大小"+byteCount);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// 把ByteArrayInputStream數據生成圖片
Bitmap bitmap = null;
// 質量壓縮方法,options的值是0-100,這裏100表示原來圖片的質量,不壓縮,把壓縮後的數據存放到baos中
image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
int options = 90;
// 循環判斷若是壓縮後圖片是否大於maxSize,大於繼續壓縮
while (baos.toByteArray().length > maxSize) {
// 重置baos即清空baos
baos.reset();
// 這裏壓縮options%,把壓縮後的數據存放到baos中
image.compress(Bitmap.CompressFormat.JPEG, options, baos);
// 每次都減小10,當爲1的時候中止,options<10的時候,遞減1
if(options == 1){
break;
}else if (options <= 10) {
options -= 1;
} else {
options -= 10;
}
}
byte[] bytes = baos.toByteArray();
if (bytes.length != 0) {
// 把壓縮後的數據baos存放到bytes中
bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
int byteCount1 = bitmap.getByteCount();
Log.i("yc壓縮圖片","壓縮後大小"+byteCount1);
}
return bitmap;
}
/**
* 第一種:質量壓縮法
*
* @param src 源圖片
* @param maxByteSize 容許最大值字節數
* @param recycle 是否回收
* @return 質量壓縮壓縮過的圖片
*/
public static Bitmap compressByQuality(final Bitmap src, final long maxByteSize, final boolean recycle) {
if (src == null || src.getWidth() == 0 || src.getHeight() == 0 || maxByteSize <= 0) {
return null;
}
Log.i("yc壓縮圖片","壓縮前大小"+src.getByteCount());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
src.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] bytes;
if (baos.size() <= maxByteSize) {// 最好質量的不大於最大字節,則返回最佳質量
bytes = baos.toByteArray();
} else {
baos.reset();
src.compress(Bitmap.CompressFormat.JPEG, 0, baos);
if (baos.size() >= maxByteSize) { // 最差質量不小於最大字節,則返回最差質量
bytes = baos.toByteArray();
} else {
// 二分法尋找最佳質量
int st = 0;
int end = 100;
int mid = 0;
while (st < end) {
mid = (st + end) / 2;
baos.reset();
src.compress(Bitmap.CompressFormat.JPEG, mid, baos);
int len = baos.size();
if (len == maxByteSize) {
break;
} else if (len > maxByteSize) {
end = mid - 1;
} else {
st = mid + 1;
}
}
if (end == mid - 1) {
baos.reset();
src.compress(Bitmap.CompressFormat.JPEG, st, baos);
}
bytes = baos.toByteArray();
}
}
if (recycle && !src.isRecycled()){
src.recycle();
}
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
Log.i("yc壓縮圖片","壓縮後大小"+bitmap.getByteCount());
return bitmap;
}
/**
* 第一種:質量壓縮法
*
* @param src 源圖片
* @param quality 質量
* @param recycle 是否回收
* @return 質量壓縮後的圖片
*/
public static Bitmap compressByQuality(final Bitmap src, @IntRange(from = 0, to = 100) final int quality, final boolean recycle) {
if (src == null || src.getWidth() == 0 || src.getHeight() == 0) {
return null;
}
Log.i("yc壓縮圖片","壓縮前大小"+src.getByteCount());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
src.compress(Bitmap.CompressFormat.JPEG, quality, baos);
byte[] bytes = baos.toByteArray();
if (recycle && !src.isRecycled()) {
src.recycle();
}
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
Log.i("yc壓縮圖片","壓縮後大小"+bitmap.getByteCount());
return bitmap;
}
複製代碼
/**
* 第二種:按採樣大小壓縮
*
* @param src 源圖片
* @param sampleSize 採樣率大小
* @param recycle 是否回收
* @return 按採樣率壓縮後的圖片
*/
public static Bitmap compressBySampleSize(final Bitmap src, final int sampleSize, final boolean recycle) {
if (src == null || src.getWidth() == 0 || src.getHeight() == 0) {
return null;
}
Log.i("yc壓縮圖片","壓縮前大小"+src.getByteCount());
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = sampleSize;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
src.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] bytes = baos.toByteArray();
if (recycle && !src.isRecycled()) {
src.recycle();
}
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
Log.i("yc壓縮圖片","壓縮後大小"+bitmap.getByteCount());
return bitmap;
}
/**
* 第二種:按採樣大小壓縮
*
* @param src 源圖片
* @param maxWidth 最大寬度
* @param maxHeight 最大高度
* @param recycle 是否回收
* @return 按採樣率壓縮後的圖片
*/
public static Bitmap compressBySampleSize(final Bitmap src, final int maxWidth, final int maxHeight, final boolean recycle) {
if (src == null || src.getWidth() == 0 || src.getHeight() == 0) {
return null;
}
Log.i("yc壓縮圖片","壓縮前大小"+src.getByteCount());
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
src.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] bytes = baos.toByteArray();
BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight);
options.inJustDecodeBounds = false;
if (recycle && !src.isRecycled()) {
src.recycle();
}
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
Log.i("yc壓縮圖片","壓縮後大小"+bitmap.getByteCount());
return bitmap;
}
/**
* 計算獲取縮放比例inSampleSize
*/
private 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 = heightRatio < widthRatio ? heightRatio : widthRatio;
}
final float totalPixels = width * height;
final float totalReqPixelsCap = reqWidth * reqHeight * 2;
while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
inSampleSize++;
}
return inSampleSize;
}
複製代碼
setTranslate(float dx,float dy):控制Matrix進行位移。
setSkew(float kx,float ky):控制Matrix進行傾斜,kx、ky爲X、Y方向上的比例。
setSkew(float kx,float ky,float px,float py):控制Matrix以px、py爲軸心進行傾斜,kx、ky爲X、Y方向上的傾斜比例。
setRotate(float degrees):控制Matrix進行depress角度的旋轉,軸心爲(0,0)。
setRotate(float degrees,float px,float py):控制Matrix進行depress角度的旋轉,軸心爲(px,py)。
setScale(float sx,float sy):設置Matrix進行縮放,sx、sy爲X、Y方向上的縮放比例。
setScale(float sx,float sy,float px,float py):設置Matrix以(px,py)爲軸心進行縮放,sx、sy爲X、Y方向上的縮放比例。
複製代碼
/**
* 第三種:按縮放壓縮
*
* @param src 源圖片
* @param newWidth 新寬度
* @param newHeight 新高度
* @param recycle 是否回收
* @return 縮放壓縮後的圖片
*/
public static Bitmap compressByScale(final Bitmap src, final int newWidth, final int newHeight, final boolean recycle) {
return scale(src, newWidth, newHeight, recycle);
}
public static Bitmap compressByScale(final Bitmap src, final float scaleWidth, final float scaleHeight, final boolean recycle) {
return scale(src, scaleWidth, scaleHeight, recycle);
}
/**
* 縮放圖片
*
* @param src 源圖片
* @param scaleWidth 縮放寬度倍數
* @param scaleHeight 縮放高度倍數
* @param recycle 是否回收
* @return 縮放後的圖片
*/
private static Bitmap scale(final Bitmap src, final float scaleWidth, final float scaleHeight, final boolean recycle) {
if (src == null || src.getWidth() == 0 || src.getHeight() == 0) {
return null;
}
Matrix matrix = new Matrix();
matrix.setScale(scaleWidth, scaleHeight);
Bitmap ret = Bitmap.createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), matrix, true);
if (recycle && !src.isRecycled()) {
src.recycle();
}
return ret;
}
複製代碼
if (bitmap != null && !bitmap.isRecycled()) {
bitmap.recycle();
bitmap = null;
}
複製代碼
public void recycle() {
if (!mRecycled && mNativePtr != 0) {
if (nativeRecycle(mNativePtr)) {
// return value indicates whether native pixel object was actually recycled.
// false indicates that it is still in use at the native level and these
// objects should not be collected now. They will be collected later when the
// Bitmap itself is collected.
mNinePatchChunk = null;
}
mRecycled = true;
}
}
複製代碼
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
private void initBitmap() {
BitmapFactory.Options options = new BitmapFactory.Options();
// 圖片複用,這個屬性必須設置;
options.inMutable = true;
// 手動設置縮放比例,使其取整數,方便計算、觀察數據;
options.inDensity = 320;
options.inTargetDensity = 320;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bg_autumn_tree_min, options);
// 對象內存地址;
Log.i("ycBitmap", "bitmap = " + bitmap);
Log.i("ycBitmap", "ByteCount = " + bitmap.getByteCount() + ":::bitmap:AllocationByteCount = " + bitmap.getAllocationByteCount());
// 使用inBitmap屬性,這個屬性必須設置;
options.inBitmap = bitmap; options.inDensity = 320;
// 設置縮放寬高爲原始寬高一半;
options.inTargetDensity = 160;
options.inMutable = true;
Bitmap bitmapReuse = BitmapFactory.decodeResource(getResources(), R.drawable.bg_kites_min, options);
// 複用對象的內存地址;
Log.i("ycBitmap", "bitmapReuse = " + bitmapReuse);
Log.i("ycBitmap", "bitmap:ByteCount = " + bitmap.getByteCount() + ":::bitmap:AllocationByteCount = " + bitmap.getAllocationByteCount());
Log.i("ycBitmap", "bitmapReuse:ByteCount = " + bitmapReuse.getByteCount() + ":::bitmapReuse:AllocationByteCount = " + bitmapReuse.getAllocationByteCount());
//11-26 18:24:07.971 15470-15470/com.yc.cn.ycbanner I/ycBitmap: bitmap = android.graphics.Bitmap@9739bff
//11-26 18:24:07.972 15470-15470/com.yc.cn.ycbanner I/ycBitmap: bitmap:ByteCount = 4346880:::bitmap:AllocationByteCount = 4346880
//11-26 18:24:07.994 15470-15470/com.yc.cn.ycbanner I/ycBitmap: bitmapReuse = android.graphics.Bitmap@9739bff
//11-26 18:24:07.994 15470-15470/com.yc.cn.ycbanner I/ycBitmap: bitmap:ByteCount = 1228800:::bitmap:AllocationByteCount = 4346880
//11-26 18:24:07.994 15470-15470/com.yc.cn.ycbanner I/ycBitmap: bitmapReuse:ByteCount = 1228800:::bitmapReuse:AllocationByteCount = 4346880
}
複製代碼
public final int getAllocationByteCount() {
if (mRecycled) {
Log.w(TAG, "Called getAllocationByteCount() on a recycle()'d bitmap! "
+ "This is undefined behavior!");
return 0;
}
return nativeGetAllocationByteCount(mNativePtr);
}
複製代碼