Android开发之超强图片工具类BitmapUtil完整实例
本文实例讲述了Android开发之超强图片工具类BitmapUtil。分享给大家供大家参考,具体如下:
说明:为了方便大家使用,本人把大家常用的图片处理代码集中到这个类里
使用了LruCache与SoftReference
/** *图片加载及转化工具-----------------------------------------------------------------------延伸:一个Bitmap到底占用多大内存?系统给每个应用程序分配多大内存?Bitmap占用的内存为:像素总数 **每个像素占用的内存。在Android中,Bitmap有四种像素类型:ARGB_8888、ARGB_4444、ARGB_565、ALPHA_8,他们每个像素占用的字节数分别为4、2、2、1。因此,一个2000*1000的ARGB_8888 *类型的Bitmap占用的内存为2000*1000*4=8000000B=8MB。 * *@authorchen.lin * */ publicclassBitmapUtil{ /** *1)软引用,已经不适合缓存图片信息,加载图片时会出现重叠的现象 *2)Android3.0(APILevel11)中,图片的数据会存储在本地的内存当中 *因而无法用一种可预见的方式将其释放,这就有潜在的风险造成应用程序的内存溢出并崩溃, *3)因为从Android2.3(APILevel9)开始,垃圾回收器会更倾向于回收持有软引用或弱引用的对象, 这让软引用和弱引用变得不再可靠。 * */ privatestaticMap>imageCache=newHashMap >(); /** *初始化lrucache,最少使用最先移除,LruCache来缓存图片, *当存储Image的大小大于LruCache设定的值,系统自动释放内存, */ privatestaticLruCache mMemoryCache; static{ finalintmemory=(int)(Runtime.getRuntime().maxMemory()/1024); finalintcacheSize=memory/8; mMemoryCache=newLruCache (cacheSize){ protectedintsizeOf(Stringkey,Bitmapvalue){ //returnvalue.getByteCount()/1024; returnvalue.getHeight()*value.getRowBytes(); } }; } //---lrucache---------------------------------------------------- /** *添加图片到lrucache * *@paramkey *@parambitmap */ publicsynchronizedvoidaddBitmapToMemCache(Stringkey,Bitmapbitmap){ if(getBitmapFromMemCache(key)==null){ if(key!=null&bitmap!=null){ mMemoryCache.put(key,bitmap); } } } /** *清除缓存 */ publicvoidclearMemCache(){ if(mMemoryCache!=null){ if(mMemoryCache.size()>0){ mMemoryCache.evictAll(); } mMemoryCache=null; } } /** *移除缓存 */ publicsynchronizedvoidremoveMemCache(Stringkey){ if(key!=null){ if(mMemoryCache!=null){ Bitmapbm=mMemoryCache.remove(key); if(bm!=null) bm.recycle(); } } } /** *从lrucache里读取图片 * *@paramkey *@return */ publicBitmapgetBitmapFromMemCache(Stringkey){ if(key!=null){ returnmMemoryCache.get(key); } returnnull; } /** *加载图片 * *@paramcontext *@paramresId *@paramimageView */ publicvoidloadBitmap(Contextcontext,intresId,ImageViewimageView){ finalStringimageKey=String.valueOf(resId); finalBitmapbitmap=getBitmapFromMemCache(imageKey); if(bitmap!=null){ imageView.setImageBitmap(bitmap); }else{ imageView.setImageResource(resId); BitmapWorkerTasktask=newBitmapWorkerTask(context); task.execute(resId); } } /** *任务类 * *@ProjectApp_View *@Packagecom.android.view.tool *@authorchenlin *@version1.0 *@Date2014年5月10日 */ classBitmapWorkerTaskextendsAsyncTask { privateContextmContext; publicBitmapWorkerTask(Contextcontext){ mContext=context; } //在后台加载图片。 @Override protectedBitmapdoInBackground(Integer...params){ finalBitmapbitmap=decodeSampledBitmapFromResource(mContext.getResources(),params[0],100,100); addBitmapToMemCache(String.valueOf(params[0]),bitmap); returnbitmap; } } //--软引用--------------------------------------------------------- publicstaticvoidaddBitmapToCache(Stringpath){ //强引用的Bitmap对象 Bitmapbitmap=BitmapFactory.decodeFile(path); //软引用的Bitmap对象 SoftReference softBitmap=newSoftReference (bitmap); //添加该对象到Map中使其缓存 imageCache.put(path,softBitmap); } publicstaticBitmapgetBitmapByPath(Stringpath){ //从缓存中取软引用的Bitmap对象 SoftReference softBitmap=imageCache.get(path); //判断是否存在软引用 if(softBitmap==null){ returnnull; } //取出Bitmap对象,如果由于内存不足Bitmap被回收,将取得空 Bitmapbitmap=softBitmap.get(); returnbitmap; } publicBitmaploadBitmap(finalStringimageUrl,finalImageCallBackimageCallBack){ SoftReference reference=imageCache.get(imageUrl); if(reference!=null){ if(reference.get()!=null){ returnreference.get(); } } finalHandlerhandler=newHandler(){ publicvoidhandleMessage(finalandroid.os.Messagemsg){ //加入到缓存中 Bitmapbitmap=(Bitmap)msg.obj; imageCache.put(imageUrl,newSoftReference (bitmap)); if(imageCallBack!=null){ imageCallBack.getBitmap(bitmap); } } }; newThread(){ publicvoidrun(){ Messagemessage=handler.obtainMessage(); message.obj=downloadBitmap(imageUrl); handler.sendMessage(message); } }.start(); returnnull; } publicinterfaceImageCallBack{ voidgetBitmap(Bitmapbitmap); } //----其它工具---------------------------------------------------------------------------------- /** *从网上下载图片 * *@paramimageUrl *@return */ privateBitmapdownloadBitmap(StringimageUrl){ Bitmapbitmap=null; try{ bitmap=BitmapFactory.decodeStream(newURL(imageUrl).openStream()); returnbitmap; }catch(Exceptione){ e.printStackTrace(); returnnull; } } /** *drawable转bitmap * *@paramdrawable *@return */ publicstaticBitmapdrawable2Bitmap(Drawabledrawable){ Bitmapbitmap=Bitmap.createBitmap(drawable.getIntrinsicWidth(),drawable.getIntrinsicHeight(), drawable.getOpacity()!=PixelFormat.OPAQUE?Bitmap.Config.ARGB_8888:Bitmap.Config.RGB_565); Canvascanvas=newCanvas(bitmap); //canvas.setBitmap(bitmap); drawable.setBounds(0,0,drawable.getIntrinsicWidth(),drawable.getIntrinsicHeight()); drawable.draw(canvas); returnbitmap; } /** *bitmap转drawable * *@parambm *@return */ publicstaticDrawablebitmap2Drable(Bitmapbm){ returnnewBitmapDrawable(bm); } /** *把字节数组通过BASE64Encoder转换成字符串 * *@paramimage *@return */ publicstaticStringgetBase64(byte[]image){ Stringstring=""; try{ BASE64Encoderencoder=newBASE64Encoder(); string=encoder.encodeBuffer(image).trim(); }catch(Exceptione){ e.printStackTrace(); } returnstring; } /** *把字节数据转换成Drawable * *@paramimgByte *字节数据 *@return */ @SuppressWarnings("deprecation") publicstaticDrawablebyte2Drawable(byte[]imgByte){ Bitmapbitmap; if(imgByte!=null){ bitmap=BitmapFactory.decodeByteArray(imgByte,0,imgByte.length); Drawabledrawable=newBitmapDrawable(bitmap); returndrawable; } returnnull; } /** *把图片转换成字节数组 * *@parambmp *@return */ publicstaticbyte[]bitmap2Byte(Bitmapbm){ BitmapoutBitmap=Bitmap.createScaledBitmap(bm,150,bm.getHeight()*150/bm.getWidth(),true); if(bm!=outBitmap){ bm.recycle(); bm=null; } byte[]compressData=null; ByteArrayOutputStreambaos=newByteArrayOutputStream(); try{ try{ outBitmap.compress(Bitmap.CompressFormat.PNG,100,baos); }catch(Exceptione){ e.printStackTrace(); } compressData=baos.toByteArray(); baos.close(); }catch(IOExceptione){ e.printStackTrace(); } returncompressData; } /** *缩放图片 * *@parambitmap *原图片 *@paramnewWidth *@paramnewHeight *@return */ publicstaticBitmapsetBitmapSize(Bitmapbitmap,intnewWidth,intnewHeight){ intwidth=bitmap.getWidth(); intheight=bitmap.getHeight(); floatscaleWidth=(newWidth*1.0f)/width; floatscaleHeight=(newHeight*1.0f)/height; Matrixmatrix=newMatrix(); matrix.postScale(scaleWidth,scaleHeight); returnBitmap.createBitmap(bitmap,0,0,width,height,matrix,true); } /** *缩放图片 * *@parambitmapPath *图片路径 *@return */ publicstaticBitmapsetBitmapSize(StringbitmapPath,floatnewWidth,floatnewHeight){ Bitmapbitmap=BitmapFactory.decodeFile(bitmapPath); if(bitmap==null){ Logger.i("bitmap","bitmap------------>发生未知异常!"); returnnull; } intwidth=bitmap.getWidth(); intheight=bitmap.getHeight(); floatscaleWidth=newWidth/width; floatscaleHeight=newHeight/height; Matrixmatrix=newMatrix(); matrix.postScale(scaleWidth,scaleHeight); returnBitmap.createBitmap(bitmap,0,0,width,height,matrix,true); } /** *计算图片的缩放大小如果==1,表示没变化,==2,表示宽高都缩小一倍---------------------------------------------------------------------------- *inSampleSize是BitmapFactory.Options类的一个参数,该参数为int型,他的值指示了在解析图片为Bitmap时在长宽两个方向上像素缩小的倍数。inSampleSize的默认值和最小值为1(当小于1时,解码器将该值当做1来处理), *且在大于1时,该值只能为2的幂(当不为2的幂时,解码器会取与该值最接近的2的幂)。例如,当inSampleSize为2时,一个2000*1000的图片,将被缩小为1000*500,相应地,它的像素数和内存占用都被缩小为了原来的1/4: * *@paramoptions *@paramreqWidth *@paramreqHeight *@return */ publicstaticintcalculateInSampleSize(BitmapFactory.Optionsoptions,intreqWidth,intreqHeight){ //原始图片的宽高 finalintheight=options.outHeight; finalintwidth=options.outWidth; intinSampleSize=1; if(height>reqHeight||width>reqWidth){ finalinthalfHeight=height/2; finalinthalfWidth=width/2; //在保证解析出的bitmap宽高分别大于目标尺寸宽高的前提下,取可能的inSampleSize的最大值 while((halfHeight/inSampleSize)>reqHeight&&(halfWidth/inSampleSize)>reqWidth){ inSampleSize*=2; } } returninSampleSize; } /** *根据计算出的inSampleSize生成Bitmap(此时的bitmap是经过缩放的图片) * *@paramres *@paramresId *@paramreqWidth *@paramreqHeight *@return */ publicstaticBitmapdecodeSampledBitmapFromResource(Resourcesres,intresId,intreqWidth,intreqHeight){ //首先设置inJustDecodeBounds=true来获取图片尺寸 finalBitmapFactory.Optionsoptions=newBitmapFactory.Options(); /** *inJustDecodeBounds属性设置为true,decodeResource()方法就不会生成Bitmap对象,而仅仅是读取该图片的尺寸和类型信息: */ options.inJustDecodeBounds=true; BitmapFactory.decodeResource(res,resId,options); //计算inSampleSize的值 options.inSampleSize=calculateInSampleSize(options,reqWidth,reqHeight); //根据计算出的inSampleSize来解码图片生成Bitmap options.inJustDecodeBounds=false; returnBitmapFactory.decodeResource(res,resId,options); } /** *将图片保存到本地时进行压缩,即将图片从Bitmap形式变为File形式时进行压缩, *特点是:File形式的图片确实被压缩了,但是当你重新读取压缩后的file为Bitmap是,它占用的内存并没有改变 * *@parambmp *@paramfile */ publicstaticvoidcompressBmpToFile(Bitmapbmp,Filefile){ ByteArrayOutputStreambaos=newByteArrayOutputStream(); intoptions=80;//个人喜欢从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{ FileOutputStreamfos=newFileOutputStream(file); fos.write(baos.toByteArray()); fos.flush(); fos.close(); }catch(Exceptione){ e.printStackTrace(); } } /** *将图片从本地读到内存时,进行压缩,即图片从File形式变为Bitmap形式 *特点:通过设置采样率,减少图片的像素,达到对内存中的Bitmap进行压缩 *@paramsrcPath *@return */ publicstaticBitmapcompressImageFromFile(StringsrcPath,floatpixWidth,floatpixHeight){ BitmapFactory.Optionsoptions=newBitmapFactory.Options(); options.inJustDecodeBounds=true;//只读边,不读内容 Bitmapbitmap=BitmapFactory.decodeFile(srcPath,options); options.inJustDecodeBounds=false; intw=options.outWidth; inth=options.outHeight; intscale=1; if(w>h&&w>pixWidth){ scale=(int)(options.outWidth/pixWidth); }elseif(w pixHeight){ scale=(int)(options.outHeight/pixHeight); } if(scale<=0) scale=1; options.inSampleSize=scale;//设置采样率 options.inPreferredConfig=Config.ARGB_8888;//该模式是默认的,可不设 options.inPurgeable=true;//同时设置才会有效 options.inInputShareable=true;//。当系统内存不够时候图片自动被回收 bitmap=BitmapFactory.decodeFile(srcPath,options); //returncompressBmpFromBmp(bitmap);//原来的方法调用了这个方法企图进行二次压缩 //其实是无效的,大家尽管尝试 returnbitmap; } /** *判断照片的角度 *@parampath *@return */ publicstaticintreadPictureDegree(Stringpath){ intdegree=0; try{ ExifInterfaceexifInterface=newExifInterface(path); intorientation=exifInterface.getAttributeInt( ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); switch(orientation){ caseExifInterface.ORIENTATION_ROTATE_90: degree=90; break; caseExifInterface.ORIENTATION_ROTATE_180: degree=180; break; caseExifInterface.ORIENTATION_ROTATE_270: degree=270; break; } }catch(IOExceptione){ e.printStackTrace(); } returndegree; } /** *Android根据设备屏幕尺寸和dpi的不同,给系统分配的单应用程序内存大小也不同,具体如下表 * *屏幕尺寸DPI应用内存 *small/normal/largeldpi/mdpi16MB *small/normal/largetvdpi/hdpi32MB *small/normal/largexhdpi64MB *small/normal/large400dpi96MB *small/normal/largexxhdpi128MB *------------------------------------------------------- *xlargemdpi32MB *xlargetvdpi/hdpi64MB *xlargexhdpi128MB *xlarge400dpi192MB *xlargexxhdpi256MB */ }
更多关于Android相关内容感兴趣的读者可查看本站专题:《Android图形与图像处理技巧总结》、《Android开发入门与进阶教程》、《Android调试技巧与常见问题解决方法汇总》、《Android基本组件用法总结》、《Android视图View技巧总结》、《Android布局layout技巧总结》及《Android控件用法总结》
希望本文所述对大家Android程序设计有所帮助。