Android開發(fā)之超強(qiáng)圖片工具類BitmapUtil完整實(shí)例
本文實(shí)例講述了Android開發(fā)之超強(qiáng)圖片工具類BitmapUtil。分享給大家供大家參考,具體如下:
說明:為了方便大家使用,本人把大家常用的圖片處理代碼集中到這個(gè)類里
使用了LruCache與SoftReference
/**
* 圖片加載及轉(zhuǎn)化工具 ----------------------------------------------------------------------- 延伸:一個(gè)Bitmap到底占用多大內(nèi)存?系統(tǒng)給每個(gè)應(yīng)用程序分配多大內(nèi)存? Bitmap占用的內(nèi)存為:像素總數(shù)
* * 每個(gè)像素占用的內(nèi)存。在Android中, Bitmap有四種像素類型:ARGB_8888、ARGB_4444、ARGB_565、ALPHA_8, 他們每個(gè)像素占用的字節(jié)數(shù)分別為4、2、2、1。因此,一個(gè)2000*1000的ARGB_8888
* 類型的Bitmap占用的內(nèi)存為2000*1000*4=8000000B=8MB。
*
* @author chen.lin
*
*/
public class BitmapUtil {
/**
* 1)軟引用 ,已經(jīng)不適合緩存圖片信息,加載圖片時(shí)會(huì)出現(xiàn)重疊的現(xiàn)象
* 2)Android 3.0 (API Level 11)中,圖片的數(shù)據(jù)會(huì)存儲(chǔ)在本地的內(nèi)存當(dāng)中
* 因而無法用一種可預(yù)見的方式將其釋放,這就有潛在的風(fēng)險(xiǎn)造成應(yīng)用程序的內(nèi)存溢出并崩潰,
* 3)因?yàn)閺?Android 2.3 (API Level 9)開始,垃圾回收器會(huì)更傾向于回收持有軟引用或弱引用的對(duì)象,
這讓軟引用和弱引用變得不再可靠。
*
*/
private static Map<String, SoftReference<Bitmap>> imageCache = new HashMap<String, SoftReference<Bitmap>>();
/**
* 初始化lrucache,最少使用最先移除,LruCache來緩存圖片,
* 當(dāng)存儲(chǔ)Image的大小大于LruCache設(shè)定的值,系統(tǒng)自動(dòng)釋放內(nèi)存,
*/
private static LruCache<String, Bitmap> mMemoryCache;
static {
final int memory = (int) (Runtime.getRuntime().maxMemory() / 1024);
final int cacheSize = memory / 8;
mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
protected int sizeOf(String key, Bitmap value) {
// return value.getByteCount() / 1024;
return value.getHeight() * value.getRowBytes();
}
};
}
// ---lrucache----------------------------------------------------
/**
* 添加圖片到lrucache
*
* @param key
* @param bitmap
*/
public synchronized void addBitmapToMemCache(String key, Bitmap bitmap) {
if (getBitmapFromMemCache(key) == null) {
if (key != null & bitmap != null) {
mMemoryCache.put(key, bitmap);
}
}
}
/**
* 清除緩存
*/
public void clearMemCache() {
if (mMemoryCache != null) {
if (mMemoryCache.size() > 0) {
mMemoryCache.evictAll();
}
mMemoryCache = null;
}
}
/**
* 移除緩存
*/
public synchronized void removeMemCache(String key) {
if (key != null) {
if (mMemoryCache != null) {
Bitmap bm = mMemoryCache.remove(key);
if (bm != null)
bm.recycle();
}
}
}
/**
* 從lrucache里讀取圖片
*
* @param key
* @return
*/
public Bitmap getBitmapFromMemCache(String key) {
if (key != null) {
return mMemoryCache.get(key);
}
return null;
}
/**
* 加載圖片
*
* @param context
* @param resId
* @param imageView
*/
public void loadBitmap(Context context, int resId, ImageView imageView) {
final String imageKey = String.valueOf(resId);
final Bitmap bitmap = getBitmapFromMemCache(imageKey);
if (bitmap != null) {
imageView.setImageBitmap(bitmap);
} else {
imageView.setImageResource(resId);
BitmapWorkerTask task = new BitmapWorkerTask(context);
task.execute(resId);
}
}
/**
* 任務(wù)類
*
* @Project App_View
* @Package com.android.view.tool
* @author chenlin
* @version 1.0
* @Date 2014年5月10日
*/
class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
private Context mContext;
public BitmapWorkerTask(Context context) {
mContext = context;
}
// 在后臺(tái)加載圖片。
@Override
protected Bitmap doInBackground(Integer... params) {
final Bitmap bitmap = decodeSampledBitmapFromResource(mContext.getResources(), params[0], 100, 100);
addBitmapToMemCache(String.valueOf(params[0]), bitmap);
return bitmap;
}
}
// --軟引用---------------------------------------------------------
public static void addBitmapToCache(String path) {
// 強(qiáng)引用的Bitmap對(duì)象
Bitmap bitmap = BitmapFactory.decodeFile(path);
// 軟引用的Bitmap對(duì)象
SoftReference<Bitmap> softBitmap = new SoftReference<Bitmap>(bitmap);
// 添加該對(duì)象到Map中使其緩存
imageCache.put(path, softBitmap);
}
public static Bitmap getBitmapByPath(String path) {
// 從緩存中取軟引用的Bitmap對(duì)象
SoftReference<Bitmap> softBitmap = imageCache.get(path);
// 判斷是否存在軟引用
if (softBitmap == null) {
return null;
}
// 取出Bitmap對(duì)象,如果由于內(nèi)存不足Bitmap被回收,將取得空
Bitmap bitmap = softBitmap.get();
return bitmap;
}
public Bitmap loadBitmap(final String imageUrl, final ImageCallBack imageCallBack) {
SoftReference<Bitmap> reference = imageCache.get(imageUrl);
if (reference != null) {
if (reference.get() != null) {
return reference.get();
}
}
final Handler handler = new Handler() {
public void handleMessage(final android.os.Message msg) {
// 加入到緩存中
Bitmap bitmap = (Bitmap) msg.obj;
imageCache.put(imageUrl, new SoftReference<Bitmap>(bitmap));
if (imageCallBack != null) {
imageCallBack.getBitmap(bitmap);
}
}
};
new Thread() {
public void run() {
Message message = handler.obtainMessage();
message.obj = downloadBitmap(imageUrl);
handler.sendMessage(message);
}
}.start();
return null;
}
public interface ImageCallBack {
void getBitmap(Bitmap bitmap);
}
// ----其它工具----------------------------------------------------------------------------------
/**
* 從網(wǎng)上下載圖片
*
* @param imageUrl
* @return
*/
private Bitmap downloadBitmap(String imageUrl) {
Bitmap bitmap = null;
try {
bitmap = BitmapFactory.decodeStream(new URL(imageUrl).openStream());
return bitmap;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* drawable 轉(zhuǎn)bitmap
*
* @param drawable
* @return
*/
public static Bitmap drawable2Bitmap(Drawable drawable) {
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(),
drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565);
Canvas canvas = new Canvas(bitmap);
// canvas.setBitmap(bitmap);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
drawable.draw(canvas);
return bitmap;
}
/**
* bitmap 轉(zhuǎn) drawable
*
* @param bm
* @return
*/
public static Drawable bitmap2Drable(Bitmap bm) {
return new BitmapDrawable(bm);
}
/**
* 把字節(jié)數(shù)組通過BASE64Encoder轉(zhuǎn)換成字符串
*
* @param image
* @return
*/
public static String getBase64(byte[] image) {
String string = "";
try {
BASE64Encoder encoder = new BASE64Encoder();
string = encoder.encodeBuffer(image).trim();
} catch (Exception e) {
e.printStackTrace();
}
return string;
}
/**
* 把字節(jié)數(shù)據(jù)轉(zhuǎn)換成Drawable
*
* @param imgByte
* 字節(jié)數(shù)據(jù)
* @return
*/
@SuppressWarnings("deprecation")
public static Drawable byte2Drawable(byte[] imgByte) {
Bitmap bitmap;
if (imgByte != null) {
bitmap = BitmapFactory.decodeByteArray(imgByte, 0, imgByte.length);
Drawable drawable = new BitmapDrawable(bitmap);
return drawable;
}
return null;
}
/**
* 把圖片轉(zhuǎn)換成字節(jié)數(shù)組
*
* @param bmp
* @return
*/
public static byte[] bitmap2Byte(Bitmap bm) {
Bitmap outBitmap = Bitmap.createScaledBitmap(bm, 150, bm.getHeight() * 150 / bm.getWidth(), true);
if (bm != outBitmap) {
bm.recycle();
bm = null;
}
byte[] compressData = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
try {
outBitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
} catch (Exception e) {
e.printStackTrace();
}
compressData = baos.toByteArray();
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
return compressData;
}
/**
* 縮放圖片
*
* @param bitmap
* 原圖片
* @param newWidth
* @param newHeight
* @return
*/
public static Bitmap setBitmapSize(Bitmap bitmap, int newWidth, int newHeight) {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
float scaleWidth = (newWidth * 1.0f) / width;
float scaleHeight = (newHeight * 1.0f) / height;
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
return Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
}
/**
* 縮放圖片
*
* @param bitmapPath
* 圖片路徑
* @return
*/
public static Bitmap setBitmapSize(String bitmapPath, float newWidth, float newHeight) {
Bitmap bitmap = BitmapFactory.decodeFile(bitmapPath);
if (bitmap == null) {
Logger.i("bitmap", "bitmap------------>發(fā)生未知異常!");
return null;
}
int width = bitmap.getWidth();
int height = bitmap.getHeight();
float scaleWidth = newWidth / width;
float scaleHeight = newHeight / height;
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
return Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
}
/**
* 計(jì)算圖片的縮放大小 如果==1,表示沒變化,==2,表示寬高都縮小一倍 ----------------------------------------------------------------------------
* inSampleSize是BitmapFactory.Options類的一個(gè)參數(shù),該參數(shù)為int型, 他的值指示了在解析圖片為Bitmap時(shí)在長(zhǎng)寬兩個(gè)方向上像素縮小的倍數(shù)。inSampleSize的默認(rèn)值和最小值為1(當(dāng)小于1時(shí),解碼器將該值當(dāng)做1來處理),
* 且在大于1時(shí),該值只能為2的冪(當(dāng)不為2的冪時(shí),解碼器會(huì)取與該值最接近的2的冪)。 例如,當(dāng)inSampleSize為2時(shí),一個(gè)2000*1000的圖片,將被縮小為1000*500,相應(yīng)地, 它的像素?cái)?shù)和內(nèi)存占用都被縮小為了原來的1/4:
*
* @param options
* @param reqWidth
* @param reqHeight
* @return
*/
public 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 halfHeight = height / 2;
final int halfWidth = width / 2;
// 在保證解析出的bitmap寬高分別大于目標(biāo)尺寸寬高的前提下,取可能的inSampleSize的最大值
while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
/**
* 根據(jù)計(jì)算出的inSampleSize生成Bitmap(此時(shí)的bitmap是經(jīng)過縮放的圖片)
*
* @param res
* @param resId
* @param reqWidth
* @param reqHeight
* @return
*/
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) {
// 首先設(shè)置 inJustDecodeBounds=true 來獲取圖片尺寸
final BitmapFactory.Options options = new BitmapFactory.Options();
/**
* inJustDecodeBounds屬性設(shè)置為true,decodeResource()方法就不會(huì)生成Bitmap對(duì)象,而僅僅是讀取該圖片的尺寸和類型信息:
*/
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// 計(jì)算 inSampleSize 的值
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// 根據(jù)計(jì)算出的 inSampleSize 來解碼圖片生成Bitmap
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
/**
* 將圖片保存到本地時(shí)進(jìn)行壓縮, 即將圖片從Bitmap形式變?yōu)镕ile形式時(shí)進(jìn)行壓縮,
* 特點(diǎn)是: File形式的圖片確實(shí)被壓縮了, 但是當(dāng)你重新讀取壓縮后的file為 Bitmap是,它占用的內(nèi)存并沒有改變
*
* @param bmp
* @param file
*/
public static void compressBmpToFile(Bitmap bmp, File file) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int options = 80;// 個(gè)人喜歡從80開始,
bmp.compress(Bitmap.CompressFormat.JPEG, options, baos);
while (baos.toByteArray().length / 1024 > 100) {
baos.reset();
options -= 10;
bmp.compress(Bitmap.CompressFormat.JPEG, options, baos);
}
try {
FileOutputStream fos = new FileOutputStream(file);
fos.write(baos.toByteArray());
fos.flush();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 將圖片從本地讀到內(nèi)存時(shí),進(jìn)行壓縮 ,即圖片從File形式變?yōu)锽itmap形式
* 特點(diǎn): 通過設(shè)置采樣率, 減少圖片的像素, 達(dá)到對(duì)內(nèi)存中的Bitmap進(jìn)行壓縮
* @param srcPath
* @return
*/
public static Bitmap compressImageFromFile(String srcPath, float pixWidth, float pixHeight) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;// 只讀邊,不讀內(nèi)容
Bitmap bitmap = BitmapFactory.decodeFile(srcPath, options);
options.inJustDecodeBounds = false;
int w = options.outWidth;
int h = options.outHeight;
int scale = 1;
if (w > h && w > pixWidth) {
scale = (int) (options.outWidth / pixWidth);
} else if (w < h && h > pixHeight) {
scale = (int) (options.outHeight / pixHeight);
}
if (scale <= 0)
scale = 1;
options.inSampleSize = scale;// 設(shè)置采樣率
options.inPreferredConfig = Config.ARGB_8888;// 該模式是默認(rèn)的,可不設(shè)
options.inPurgeable = true;// 同時(shí)設(shè)置才會(huì)有效
options.inInputShareable = true;// 。當(dāng)系統(tǒng)內(nèi)存不夠時(shí)候圖片自動(dòng)被回收
bitmap = BitmapFactory.decodeFile(srcPath, options);
// return compressBmpFromBmp(bitmap);//原來的方法調(diào)用了這個(gè)方法企圖進(jìn)行二次壓縮
// 其實(shí)是無效的,大家盡管嘗試
return bitmap;
}
/**
* 判斷照片的角度
* @param path
* @return
*/
public static int readPictureDegree(String path) {
int degree = 0;
try {
ExifInterface exifInterface = new ExifInterface(path);
int orientation = exifInterface.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
degree = 90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
degree = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
degree = 270;
break;
}
} catch (IOException e) {
e.printStackTrace();
}
return degree;
}
/**
* Android根據(jù)設(shè)備屏幕尺寸和dpi的不同,給系統(tǒng)分配的單應(yīng)用程序內(nèi)存大小也不同,具體如下表
*
* 屏幕尺寸 DPI 應(yīng)用內(nèi)存
* small / normal / large ldpi / mdpi 16MB
* small / normal / large tvdpi / hdpi 32MB
* small / normal / large xhdpi 64MB
* small / normal / large 400dpi 96MB
* small / normal / large xxhdpi 128MB
* -------------------------------------------------------
* xlarge mdpi 32MB
* xlarge tvdpi / hdpi 64MB
* xlarge xhdpi 128MB
* xlarge 400dpi 192MB
* xlarge xxhdpi 256MB
*/
}
更多關(guān)于Android相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Android圖形與圖像處理技巧總結(jié)》、《Android開發(fā)入門與進(jìn)階教程》、《Android調(diào)試技巧與常見問題解決方法匯總》、《Android基本組件用法總結(jié)》、《Android視圖View技巧總結(jié)》、《Android布局layout技巧總結(jié)》及《Android控件用法總結(jié)》
希望本文所述對(duì)大家Android程序設(shè)計(jì)有所幫助。
- Android中使用Bitmap類將矩形圖片轉(zhuǎn)為圓形的方法
- Android圖片加載的緩存類
- 非常實(shí)用的Android圖片工具類
- Android開發(fā)之多媒體文件獲取工具類實(shí)例【音頻,視頻,圖片等】
- Android開發(fā)之圖片壓縮工具類完整實(shí)例
- Android開發(fā)實(shí)現(xiàn)的IntentUtil跳轉(zhuǎn)多功能工具類【包含視頻、音頻、圖片、攝像頭等操作功能】
- Android圖片處理工具類BitmapUtils
- Android開發(fā)之圖片切割工具類定義與用法示例
- Android編程圖片加載類ImageLoader定義與用法實(shí)例分析
- Android編程圖片操作類定義與用法示例【拍照,相冊(cè)選圖及裁剪】
相關(guān)文章
Android利用傳感器實(shí)現(xiàn)微信搖一搖功能
這篇文章主要為大家詳細(xì)介紹了Android利用傳感器實(shí)現(xiàn)微信搖一搖功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11
Android CheckBox中設(shè)置padding無效解決辦法
這篇文章主要介紹了Android CheckBox中設(shè)置padding無效解決辦法的相關(guān)資料,希望通過本文能幫助到大家,讓大家解決這樣類似的問題,需要的朋友可以參考下2017-10-10
Android無障礙監(jiān)聽通知的實(shí)戰(zhàn)過程
開發(fā)微動(dòng)手勢(shì)的時(shí)候,做了一個(gè)通知觸發(fā)的功能,就是在收到某個(gè)預(yù)設(shè)的通知的時(shí)候,自動(dòng)觸發(fā)某個(gè)動(dòng)作,因此需要監(jiān)聽通知消息,這篇文章主要給大家介紹了關(guān)于Android無障礙監(jiān)聽通知的相關(guān)資料,需要的朋友可以參考下2022-07-07
Android中 動(dòng)態(tài)改變對(duì)話框值的方法
Android Dev-Guide 推薦重寫Activity.onCreateDialog()方法來創(chuàng)建Dialog,這樣Dialog就歸屬于這個(gè)Activity了。2013-04-04
ijkPlayer播放器的全自動(dòng)編譯腳本及最終編譯包
這篇文章主要介紹了ijkPlayer播放器的全自動(dòng)編譯腳本及最終編譯包,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
MVVMLight項(xiàng)目的綁定及各種使用場(chǎng)景示例分析
這篇文章主要為大家介紹了MVVMLight項(xiàng)目中的綁定及綁定的各種使用場(chǎng)景示例源碼分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步除夕快樂2022-01-01
Android實(shí)現(xiàn)圓線按鈕進(jìn)度效果
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)圓線按鈕帶進(jìn)度,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05
AndroidStudio重新share代碼和上傳到svn新地址教程
這篇文章主要介紹了AndroidStudio重新share代碼和上傳到svn新地址教程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-04-04
實(shí)現(xiàn)Android 獲取cache緩存的目錄路徑的方法
這篇文章主要介紹了實(shí)現(xiàn)Android 獲取cache緩存的目錄路徑的方法的相關(guān)資料,這里實(shí)現(xiàn)一個(gè)靜態(tài)類來實(shí)現(xiàn)該功能,希望能幫助到大家,需要的朋友可以參考下2017-08-08

