我看到好多博客都是這樣計算的,可是這樣算對嗎?有沒有哥們試驗過這種方法正確性?我以爲看博客要對博主表示懷疑,論證別人寫的是否正確。更多詳細能夠看個人GitHub:https://github.com/yangchong211php
加載一張本地資源圖片,那麼它佔用的內存 = width height nTargetDensity/inDensity nTargetDensity/inDensity 一個像素所佔的內存。android
@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); }
質量壓縮方法:在保持像素的前提下改變圖片的位深及透明度等,來達到壓縮圖片的目的,這樣適合去傳遞二進制的圖片數據,好比分享圖片,要傳入二進制數據過去,限制500kb以內。git
/** * 第一種:質量壓縮法 * @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; }
/**github
/**面試
什麼是採樣率壓縮?算法
/** * 第二種:按採樣大小壓縮 * * @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; }
/**segmentfault
/**api
Android中使用Matrix對圖像進行縮放、旋轉、平移、斜切等變換的。 緩存
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);
}markdown
/**
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; } }
Bitmap複用的實驗,代碼以下所示,而後看打印的日誌信息
getByteCount()獲取到的是當前圖片應當所佔內存大小,getAllocationByteCount()獲取到的是被複用Bitmap真實佔用內存大小。雖然bitmapReuse的內存只有4346880,可是由於是複用的bitmap的內存,於是其真實佔用的內存大小是被複用的bitmap的內存大小(1228800)。這也是getAllocationByteCount()可能比getByteCount()大的緣由。
@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); }