Android開(kāi)發(fā)之超強(qiáng)圖片工具類(lèi)BitmapUtil完整實(shí)例
本文實(shí)例講述了Android開(kāi)發(fā)之超強(qiáng)圖片工具類(lèi)BitmapUtil。分享給大家供大家參考,具體如下:
說(shuō)明:為了方便大家使用,本人把大家常用的圖片處理代碼集中到這個(gè)類(lèi)里
使用了LruCache與SoftReference
/** * 圖片加載及轉(zhuǎn)化工具 ----------------------------------------------------------------------- 延伸:一個(gè)Bitmap到底占用多大內(nèi)存?系統(tǒng)給每個(gè)應(yīng)用程序分配多大內(nèi)存? Bitmap占用的內(nèi)存為:像素總數(shù) * * 每個(gè)像素占用的內(nèi)存。在Android中, Bitmap有四種像素類(lèi)型:ARGB_8888、ARGB_4444、ARGB_565、ALPHA_8, 他們每個(gè)像素占用的字節(jié)數(shù)分別為4、2、2、1。因此,一個(gè)2000*1000的ARGB_8888 * 類(lèi)型的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)中 * 因而無(wú)法用一種可預(yù)見(jiàn)的方式將其釋放,這就有潛在的風(fēng)險(xiǎn)造成應(yīng)用程序的內(nèi)存溢出并崩潰, * 3)因?yàn)閺?Android 2.3 (API Level 9)開(kāi)始,垃圾回收器會(huì)更傾向于回收持有軟引用或弱引用的對(duì)象, 這讓軟引用和弱引用變得不再可靠。 * */ private static Map<String, SoftReference<Bitmap>> imageCache = new HashMap<String, SoftReference<Bitmap>>(); /** * 初始化lrucache,最少使用最先移除,LruCache來(lái)緩存圖片, * 當(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ù)類(lèi) * * @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ù)組通過(guò)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,表示沒(méi)變化,==2,表示寬高都縮小一倍 ---------------------------------------------------------------------------- * inSampleSize是BitmapFactory.Options類(lèi)的一個(gè)參數(shù),該參數(shù)為int型, 他的值指示了在解析圖片為Bitmap時(shí)在長(zhǎng)寬兩個(gè)方向上像素縮小的倍數(shù)。inSampleSize的默認(rèn)值和最小值為1(當(dāng)小于1時(shí),解碼器將該值當(dāng)做1來(lái)處理), * 且在大于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)存占用都被縮小為了原來(lá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)過(guò)縮放的圖片) * * @param res * @param resId * @param reqWidth * @param reqHeight * @return */ public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) { // 首先設(shè)置 inJustDecodeBounds=true 來(lái)獲取圖片尺寸 final BitmapFactory.Options options = new BitmapFactory.Options(); /** * inJustDecodeBounds屬性設(shè)置為true,decodeResource()方法就不會(huì)生成Bitmap對(duì)象,而僅僅是讀取該圖片的尺寸和類(lèi)型信息: */ options.inJustDecodeBounds = true; BitmapFactory.decodeResource(res, resId, options); // 計(jì)算 inSampleSize 的值 options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // 根據(jù)計(jì)算出的 inSampleSize 來(lái)解碼圖片生成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)存并沒(méi)有改變 * * @param bmp * @param file */ public static void compressBmpToFile(Bitmap bmp, File file) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); int options = 80;// 個(gè)人喜歡從80開(kāi)始, 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): 通過(guò)設(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);//原來(lái)的方法調(diào)用了這個(gè)方法企圖進(jìn)行二次壓縮 // 其實(shí)是無(wú)效的,大家盡管?chē)L試 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)容感興趣的讀者可查看本站專(zhuān)題:《Android圖形與圖像處理技巧總結(jié)》、《Android開(kāi)發(fā)入門(mén)與進(jìn)階教程》、《Android調(diào)試技巧與常見(jiàn)問(wèn)題解決方法匯總》、《Android基本組件用法總結(jié)》、《Android視圖View技巧總結(jié)》、《Android布局layout技巧總結(jié)》及《Android控件用法總結(jié)》
希望本文所述對(duì)大家Android程序設(shè)計(jì)有所幫助。
- Android中使用Bitmap類(lèi)將矩形圖片轉(zhuǎn)為圓形的方法
- Android圖片加載的緩存類(lèi)
- 非常實(shí)用的Android圖片工具類(lèi)
- Android開(kāi)發(fā)之多媒體文件獲取工具類(lèi)實(shí)例【音頻,視頻,圖片等】
- Android開(kāi)發(fā)之圖片壓縮工具類(lèi)完整實(shí)例
- Android開(kāi)發(fā)實(shí)現(xiàn)的IntentUtil跳轉(zhuǎn)多功能工具類(lèi)【包含視頻、音頻、圖片、攝像頭等操作功能】
- Android圖片處理工具類(lèi)BitmapUtils
- Android開(kāi)發(fā)之圖片切割工具類(lèi)定義與用法示例
- Android編程圖片加載類(lèi)ImageLoader定義與用法實(shí)例分析
- Android編程圖片操作類(lèi)定義與用法示例【拍照,相冊(cè)選圖及裁剪】
相關(guān)文章
Android中使用ShareSDK集成分享功能的實(shí)例代碼
下面小編就為大家分享一篇Android中使用ShareSDK集成分享功能的實(shí)例代碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-01-01Android自定義View播放Gif動(dòng)畫(huà)的示例
本篇文章主要介紹了Android自定義View播放Gif動(dòng)畫(huà)的示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-10-10Android10?客戶(hù)端事務(wù)管理ClientLifecycleManager源碼解析
這篇文章主要介紹了Android10?客戶(hù)端事務(wù)管理ClientLifecycleManager源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10Android 跨進(jìn)程模擬按鍵(KeyEvent )實(shí)例詳解
這篇文章主要介紹了Android 跨進(jìn)程模擬按鍵(KeyEvent )實(shí)例詳解的相關(guān)資料,類(lèi)似手機(jī)遙控器的需求就可以這么做,需要的朋友可以參考下2016-11-11Android studio案例之實(shí)現(xiàn)電話(huà)撥號(hào)
這篇文章主要介紹了Android studio案例之實(shí)現(xiàn)電話(huà)撥號(hào),并有詳細(xì)的步驟和實(shí)現(xiàn)代碼,對(duì)此感興趣的同學(xué),可以參考下2021-04-04Android實(shí)現(xiàn)直播聊天區(qū)域中頂部的漸變效果
最近在研究直播的彈幕,東西有點(diǎn)多,準(zhǔn)備記錄一下免得自己忘了又要重新研究,下面這篇文章主要給大家介紹了關(guān)于Android如何實(shí)現(xiàn)直播聊天區(qū)域中頂部漸變效果的相關(guān)資料,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2018-04-04