欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android中的Bitmap的詳細介紹

 更新時間:2018年01月02日 09:39:24   作者:null在掘金  
本篇文章主要介紹了Android中的Bitmap,是Windows標(biāo)準(zhǔn)格式圖形文件,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

Bitmap簡介(摘抄于網(wǎng)絡(luò))

位圖文件(Bitmap),擴展名可以是.bmp或者.dib。位圖是Windows標(biāo)準(zhǔn)格式圖形文件,它將圖像定義為由點(像素)組成,每個點可以由多種色彩表示,包括2、4、8、16、24和32位色彩。

例如,一幅1024×768分辨率的32位真彩圖片,其所占存儲字節(jié)數(shù)為:1024×768×32/(8*1024)=3072KB

位圖文件圖像效果好,但是非壓縮格式的,需要占用較大存儲空間,不利于在網(wǎng)絡(luò)上傳送。jpg/png格式則恰好彌補了位圖文件的缺點。

在Android中計算bitmap的大?。篵itmap.getByteCount()(返回byte)

掃盲:1M=1024KB=1024*1024byte

一般1920X1080尺寸的圖片在內(nèi)存中的大小,1920x1080x4=2025kb=1.977539M
乘以4位的原因是在安卓系統(tǒng)中bitmap圖片一般是以ARGB_8888(ARGB分別代表的是透明度,紅色,綠色,藍色,每個值分別用8bit來記錄,也就是一個像素會占用4byte,共32bit。)來進行存儲的。

Android中圖片有四種顏色格式

顏色格式 每個像素占用內(nèi)存(單位byte) 每個像素占用內(nèi)存(單位bit)
ALPHA_8 1 8
ARGB_8888(默認(rèn)) 4 32
ARGB_4444 2 16
RGB_565 2 16

ARGB_8888占位算法: 8+8+8+8 =32

1 bit   0/1 ;最小單位

1 byte = 8bit      10101010  (0-255)00000000  ---  11111111

說明:

ARGB_8888:ARGB分別代表的是透明度,紅色,綠色,藍色,每個值分別用8bit來記錄,也就是一個像素會占用4byte,共32bit.

ARGB_4444:ARGB的是每個值分別用4bit來記錄,一個像素會占用2byte,共16bit.

RGB_565:R=5bit,G=6bit,B=5bit,不存在透明度,每個像素會占用2byte,共16bit.

ALPHA_8:該像素只保存透明度,會占用1byte,共8bit.

在實際應(yīng)用中而言,建議使用ARGB_8888以及RGB_565。

如果你不需要透明度,那么就選擇RGB_565,可以減少一半的內(nèi)存占用.

Bitmap的回收

在安卓3.0以前Bitmap是存放在堆中的,我們只要回收堆內(nèi)存即可

在安卓3.0以后Bitmap是存放在內(nèi)存中的,我們需要回收native層和Java層的內(nèi)存

官方建議我們3.0以后使用recycle方法進行回收,該方法也可以不主動調(diào)用,因為垃圾回收器會自動收集不可用的Bitmap對象進行回收

recycle方法會判斷Bitmap在不可用的情況下,將發(fā)送指令到垃圾回收器,讓其回收native層和Java層的內(nèi)存,則Bitmap進入dead狀態(tài)

recycle方法是不可逆的,如果再次調(diào)用getPixels()等方法,則獲取不到想要的結(jié)果

LruCache原理

LruCache是個泛型類,內(nèi)部采用LinkedHashMap來實現(xiàn)緩存機制,它提供get方法和put方法來獲取緩存和添加緩存,其最重要的方法trimToSize是用來移除最少使用的緩存和使用最久的緩存,并添加最新的緩存到隊列中

計算inSampleSize

  public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
    final int width = options.outWidth;
    final int height = options.outHeight;
    int inSampleSize = 1;
    
    if (width > reqWidth || height > reqHeight) {
      if (width > height) {
        inSampleSize = Math.round((float) height / (float) reqHeight);
      } else {
        inSampleSize = Math.round((float) width / (float) reqWidth);
      }
    }
    return inSampleSize;
  }

縮略圖

  public static Bitmap thumbnail(String path, int maxWidth, int maxHeight,boolean autoRotate) {
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    Bitmap bitmap = BitmapFactory.decodeFile(path);
    options.inJustDecodeBounds = false;
    int sampleSize = calculateInSampleSize(options,maxWidth,maxHeight);
    options.inSampleSize =sampleSize;
    options.inPreferredConfig = Bitmap.Config.RGB_565;
    options.inPurgeable =true;
    options.inInputShareable = true;
    if(bitmap !=null&&!bitmap.isRecycled()){
      bitmap.recycle();
    }
    bitmap = BitmapFactory.decodeFile(path,options);
    return bitmap;
  }

保存Bitmap

public static String save(Bitmap bitmap, Bitmap.CompressFormat format, int quality,File desFile) {
    try{
      FileOutputStream out = new FileOutputStream(desFile);
      if(bitmap.compress(format,quality,out)){
        out.flush();
        out.close();
      }
      if(bitmap!=null&&!bitmap.isRecycled()){
        bitmap.recycle();
      }
      return desFile.getAbsolutePath();
    }catch (FileNotFoundException e){
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }
    return null;
  }

保存到SD卡

public static String save(Bitmap bitmap, Bitmap.CompressFormat format, int quality,Context context) {
    if(!Environment.getExternalStorageState()
        .equals(Environment.MEDIA_MOUNTED)){
      return null;
    }
    File dir = new File(Environment.getExternalStorageDirectory()+
    "/"+context.getPackageName());
    if(!dir.exists()){
      dir.mkdir();
    }
    File desFile = new File(dir, UUID.randomUUID().toString());
    return save(bitmap,format,quality,desFile);
  }

壓縮

一、質(zhì)量壓縮

質(zhì)量壓縮方法:在保持像素的前提下改變圖片的位深及透明度等,來達到壓縮圖片的目的:

1、bitmap圖片的大小不會改變

2、bytes.length是隨著quality變小而變小的。

這樣適合去傳遞二進制的圖片數(shù)據(jù),比如分享圖片,要傳入二進制數(shù)據(jù)過去,限制500kb之內(nèi)。

public static Bitmap compressImage(Bitmap image) {
  ByteArrayOutputStream baos = new ByteArrayOutputStream();
  // 把ByteArrayInputStream數(shù)據(jù)生成圖片
  Bitmap bitmap = null;
  image.compress(Bitmap.CompressFormat.JPEG, 5, baos);
  byte[] bytes = baos.toByteArray();
  // 把壓縮后的數(shù)據(jù)baos存放到bytes中
  bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
  if (bitmap != null) {
    loga(bitmap, baos.toByteArray());
  }
  return bitmap;
}

// 質(zhì)量壓縮方法,options的值是0-100,這里100表示原來圖片的質(zhì)量,不壓縮,把壓縮后的數(shù)據(jù)存放到baos中
image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
int options = 90;
// 循環(huán)判斷如果壓縮后圖片是否大于500kb,大于繼續(xù)壓縮
while (baos.toByteArray().length / 1024 > 100) {
  // 重置baos即清空baos
  baos.reset();
  // 這里壓縮options%,把壓縮后的數(shù)據(jù)存放到baos中
  image.compress(Bitmap.CompressFormat.JPEG, options, baos);
  // 每次都減少10
  if(options == 1){
    break;
  }else if (options <= 10) {
    options -= 1;
  } else {
    options -= 10;
  }
}

二、采樣率壓縮

設(shè)置inSampleSize的值(int類型)后,假如設(shè)為n,則寬和高都為原來的1/n,寬高都減少,內(nèi)存降低。上面的代碼沒用過options.inJustDecodeBounds = true; 因為我是固定來取樣的數(shù)據(jù),為什么這個壓縮方法叫采樣率壓縮?

是因為配合inJustDecodeBounds,先獲取圖片的寬、高(這個過程就是取樣)。

然后通過獲取的寬高,動態(tài)的設(shè)置inSampleSize的值。 當(dāng)inJustDecodeBounds設(shè)置為true的時候, BitmapFactory通過decodeResource或者decodeFile解碼圖片時, 將會返回空(null)的Bitmap對象,這樣可以避免Bitmap的內(nèi)存分配, 但是它可以返回Bitmap的寬度、高度以及MimeType。

用法

int inSampleSize = getScaling(bitmap); bitmap = samplingRateCompression(path,inSampleSize);
private Bitmap samplingRateCompression(String path, int scaling) {

BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = scaling;

Bitmap bitmap = BitmapFactory.decodeFile(path, options);

int size = (bitmap.getByteCount() / 1024 / 1024);

Log.i("wechat", "壓縮后圖片的大小" + (bitmap.getByteCount() / 1024 / 1024)
    + "M寬度為" + bitmap.getWidth() + "高度為" + bitmap.getHeight());
return bitmap;
}

/**
* 獲取縮放比例
* @param bitmap
* @return
*/
private int getScaling(Bitmap bitmap) {
  //設(shè)置目標(biāo)尺寸(以像素的寬度為標(biāo)準(zhǔn))
  int Targetsize = 1500;
  int width = bitmap.getWidth();
  int height = bitmap.getHeight();
  //選擇最大值作為比較值(保證圖片的壓縮大小)
  int handleValue = width > height ? width : height;
  //循環(huán)計算壓縮比
  int i = 1;
  while (handleValue / i > Targetsize) {
    i++;
  }
}

三、縮放法壓縮, 效果和方法2一樣

Android中使用Matrix對圖像進行縮放、旋轉(zhuǎn)、平移、斜切等變換的。 Matrix是一個3*3的矩陣,其值對應(yīng)如下:
|scaleX,  skewX,  translateX|
|skewY,  scaleY,  translateY|
|0  , 0 ,   scale |

Matrix提供了一些方法來控制圖片變換:

  1. setTranslate(float dx,float dy):控制Matrix進行位移。
  2. setSkew(float kx,float ky):控制Matrix進行傾斜,kx、ky為X、Y方向上的比例。
  3. setSkew(float kx,float ky,float px,float py):控制Matrix以px、py為軸心進行傾斜,kx、ky為X、Y方向上的傾斜比例。
  4. setRotate(float degrees):控制Matrix進行depress角度的旋轉(zhuǎn),軸心為(0,0)。
  5. setRotate(float degrees,float px,float py):控制Matrix進行depress角度的旋轉(zhuǎn),軸心為(px,py)。
  6. setScale(float sx,float sy):設(shè)置Matrix進行縮放,sx、sy為X、Y方向上的縮放比例。
  7. setScale(float sx,float sy,float px,float py):設(shè)置Matrix以(px,py)為軸心進行縮放,sx、sy為X、Y方向上的縮放比例。

注意:以上的set方法,均有對應(yīng)的post和pre方法,Matrix調(diào)用一系列set,pre,post方法時,可視為將這些方法插入到一個隊列. 當(dāng)然,按照隊列中從頭至尾的順序調(diào)用執(zhí)行. 其中pre表示在隊頭插入一個方法,post表示在隊尾插入一個方法. 而set表示把當(dāng)前隊列清空,并且總是位于隊列的最中間位置. 當(dāng)執(zhí)行了一次set后: pre方法總是插入到set前部的隊列的最前面,post方法總是插入到set后部的隊列的最后面

private Bitmap ScalingCompression(Bitmap bitmap) {
  Matrix matrix = new Matrix();
  matrix.setScale(0.25f, 0.25f);//縮放效果類似于方法2
  Bitmap bm = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
    bitmap.getHeight(), matrix, true);
  Log.i("wechat", "壓縮后圖片的大小" + (bm.getByteCount() / 1024 / 1024)
    + "M寬度為" + bm.getWidth() + "高度為" + bm.getHeight());
  return bm;
}

四、Bitmap.Config

原圖尺寸:4M----轉(zhuǎn)化為File---Bitmap大小

  1. ALPHA_8----------6.77M -------45M
  2. ARGB_4444-------9.37M -------22M
  3. ARGB_8888-------6.77M -------45M
  4. RGB_565-----------8.13M -------22M

一般情況下默認(rèn)使用的是ARGB8888,由此可知它是最占內(nèi)存的,因為一個像素占32位,8位=1字節(jié),所以一個像素占4字節(jié)的內(nèi)存。假設(shè)有一張480x800的圖片,如果格式為ARGB8888,那么將會占用1500KB的內(nèi)存。

private Bitmap bitmapConfig(String path) {
  BitmapFactory.Options options = new BitmapFactory.Options();
  options.inPreferredConfig = Bitmap.Config.RGB_565;

  Bitmap bm = BitmapFactory.decodeFile(path, options);
  Log.i("wechat", "壓縮后圖片的大小" + (bm.getByteCount() / 1024f / 1024f)
  + "M寬度為" + bm.getWidth() + "高度為" + bm.getHeight());
  return bm;
} 

五、Bitmap提供的:createScaledBitmap

方法

Bitmap.createScaledBitmap(src, dstWidth, dstHeight, filter);

參數(shù)說明:

  1. src  用來構(gòu)建子集的源位圖
  2. dstWidth   新位圖期望的寬度
  3. dstHeight  新位圖期望的高度
  4. filter     為true則選擇抗鋸齒

補充抗鋸齒的知識點

在Android中,目前,我知道有兩種出現(xiàn)鋸齒的情況。

1、當(dāng)我們用Canvas繪制位圖的時候,如果對位圖進行了選擇,則位圖會出現(xiàn)鋸齒。
2、在用View的RotateAnimation做動畫時候, 如果View當(dāng)中包含有大量的圖形,也會出現(xiàn)鋸齒。

我們分別以這兩種情況加以考慮。 用Canvas繪制位圖的的情況。 在用Canvas繪制位圖時,一般地,我們使用drawBitmap函數(shù)家族, 在這些函數(shù)中,都有一個Paint參數(shù), 要做到防止鋸齒,我們就要使用到這個參數(shù)。如下:

首先在你的構(gòu)造函數(shù)中,需要創(chuàng)建一個Paint。 Paint mPaint = new Paint();

然后,您需要設(shè)置兩個參數(shù):

1)mPaint.setAntiAlias(Boolean aa);
2)mPaint.setBitmapFilter(true)。

第一個函數(shù)是用來防止邊緣的鋸齒, (true時圖像邊緣相對清晰一點,鋸齒痕跡不那么明顯, false時,寫上去的字不飽滿,不美觀,看地不太清楚)。

第二個函數(shù)是用來對位圖進行濾波處理。

最后,在畫圖的時候,調(diào)用drawBitmap函數(shù),只需要將整個Paint傳入即可。

有時候,當(dāng)你做RotateAnimation時, 你會發(fā)現(xiàn),討厭的鋸齒又出現(xiàn)了。 這個時候,由于你不能控制位圖的繪制, 只能用其他方法來實現(xiàn)防止鋸齒。 另外,如果你畫的位圖很多。 不想每個位圖的繪制都傳入一個Paint。 還有的時候,你不可能控制每個窗口的繪制的時候, 您就需要用下面的方法來處理——對整個Canvas進行處理。

1)在您的構(gòu)造函數(shù)中,創(chuàng)建一個Paint濾波器。 PaintFlagsDrawFilter mSetfil = new PaintFlagsDrawFilter(0, Paint.FILTERBITMAPFLAG); 第一個參數(shù)是你要清除的標(biāo)志位, 第二個參數(shù)是你要設(shè)置的標(biāo)志位。此處設(shè)置為對位圖進行濾波。

2)當(dāng)你在畫圖的時候, 如果是View則在onDraw當(dāng)中,如果是ViewGroup則在dispatchDraw中調(diào)用如下函數(shù)。 canvas.setDrawFilter( mSetfil );

另外,在Drawable類及其子類中, 也有函數(shù)setFilterBitmap可以用來對Bitmap進行濾波處理, 這樣,當(dāng)你選擇Drawable時,會有抗鋸齒的效果。

private Bitmap createScaledBitmap(Bitmap bitmap) {
  Bitmap bm = Bitmap.createScaledBitmap(bitmap, 200, 200, true);
  Log.i("wechat", "壓縮后圖片的大小" + (bm.getByteCount() / 1024) + "KB寬度為"
    + bm.getWidth() + "高度為" + bm.getHeight());
  return bm;
}

六、輔助方法(上述方法的):

通過路徑獲取bitmap的方法

1、利用BitmapFactory解析文件,轉(zhuǎn)換為Bitmap

bitmap = BitmapFactory.decodeFile(path);

2、自己寫解碼,轉(zhuǎn)換為Bitmap過程, 同樣需使用BitmapFactory.decodeByteArray(buf, 0, len);代碼如下:

private Bitmap getBitmapByPath(String path) {
if (!new File(path).exists()) {
  System.err.println("getBitmapByPath: 文件不存在");
  return null;
}
byte[] buf = new byte[1024 * 1024];// 1M
Bitmap bitmap = null;
try {
  FileInputStream fis = new FileInputStream(path);
  int len = fis.read(buf, 0, buf.length);
  bitmap = BitmapFactory.decodeByteArray(buf, 0, len);
  //當(dāng)bitmap為空的時候,說明解析失敗
  if (bitmap == null) {
    System.out.println("文件長度:" + len);
    System.err.println("path: " + path + " 無法解析!!!");
  }
} catch (Exception e) {
  e.printStackTrace();
}
return bitmap;
}

保存圖片

private void savaPictrue(Bitmap bitmap) {
  File file = new File("storage/emulated/0/DCIM/Camera/test.jpg");
  FileOutputStream stream = null;
  try {
    stream = new FileOutputStream(file);
    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
    Log.e("圖片大小:", file.length() / 1024 / 1024 + "M");
  } catch (Exception e) {
    e.printStackTrace();
  }
}

剪切圖片(這里只是裁剪圖片,但是對圖片的大小并不影響)

private void crop(Uri uri) {
  // 裁剪圖片意圖
  Intent intent = new Intent("com.android.camera.action.CROP");
  intent.setDataAndType(uri, "image/*");
  intent.putExtra("crop", "true");
  // 裁剪框的比例,1:1
  intent.putExtra("aspectX", 1);
  intent.putExtra("aspectY", 1);
  // 裁剪后輸出圖片的尺寸大小
  intent.putExtra("outputX", 300);
  intent.putExtra("outputY", 300);

  intent.putExtra("outputFormat", "JPEG");// 圖片格式
  intent.putExtra("noFaceDetection", true);// 取消人臉識別
  intent.putExtra("return-data", true);
  // 開啟一個帶有返回值的Activity,請求碼為PHOTO_REQUEST_CUT
  startActivityForResult(intent, 200);
}

private void logp(Bitmap bitmap) {
Log.i("wechat", "壓縮前圖片的大小" + (bitmap.getByteCount() / 1024 / 1024)
    + "M寬度為" + bitmap.getWidth() + "高度為" + bitmap.getHeight());
}

private static void loga(Bitmap bitmap, byte[] bytes) {
  Log.i("wechat", "壓縮后圖片的大小" + (bitmap.getByteCount() / 1024 / 1024)
    + "M寬度為" + bitmap.getWidth() + "高度為" + bitmap.getHeight()
    + "bytes.length= " + (bytes.length / 1024) + "KB"
  );
}

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評論