热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

Android开发之超强图片工具类BitmapUtil完整实例

这篇文章主要介绍了Android开发之超强图片工具类BitmapUtil,结合完整实例形式分析了Android图片的常用操作技巧,包括图片的加载、转换、缩放、计算等相关操作技巧,需要的朋友可以参考下

本文实例讲述了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。
 * 
 * @author chen.lin
 *
 */
public class BitmapUtil {
 /**
  * 1)软引用 ,已经不适合缓存图片信息,加载图片时会出现重叠的现象
  * 2)Android 3.0 (API Level 11)中,图片的数据会存储在本地的内存当中
  * 因而无法用一种可预见的方式将其释放,这就有潜在的风险造成应用程序的内存溢出并崩溃,
  * 3)因为从 Android 2.3 (API Level 9)开始,垃圾回收器会更倾向于回收持有软引用或弱引用的对象,
   这让软引用和弱引用变得不再可靠。
  * 
  */
 private static Map> imageCache = new HashMap>();
 /**
  * 初始化lrucache,最少使用最先移除,LruCache来缓存图片,
  * 当存储Image的大小大于LruCache设定的值,系统自动释放内存,
  */
 private static LruCache mMemoryCache;
 static {
  final int memory = (int) (Runtime.getRuntime().maxMemory() / 1024);
  final int cacheSize = memory / 8;
  mMemoryCache = new LruCache(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);
  }
 }
 /**
  * 任务类
  * 
  * @Project App_View
  * @Package com.android.view.tool
  * @author chenlin
  * @version 1.0
  * @Date 2014年5月10日
  */
 class BitmapWorkerTask extends AsyncTask {
  private Context mContext;
  public BitmapWorkerTask(Context context) {
   mCOntext= context;
  }
  // 在后台加载图片。
  @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) {
  // 强引用的Bitmap对象
  Bitmap bitmap = BitmapFactory.decodeFile(path);
  // 软引用的Bitmap对象
  SoftReference softBitmap = new SoftReference(bitmap);
  // 添加该对象到Map中使其缓存
  imageCache.put(path, softBitmap);
 }
 public static Bitmap getBitmapByPath(String path) {
  // 从缓存中取软引用的Bitmap对象
  SoftReference softBitmap = imageCache.get(path);
  // 判断是否存在软引用
  if (softBitmap == null) {
   return null;
  }
  // 取出Bitmap对象,如果由于内存不足Bitmap被回收,将取得空
  Bitmap bitmap = softBitmap.get();
  return bitmap;
 }
 public Bitmap loadBitmap(final String imageUrl, final ImageCallBack imageCallBack) {
  SoftReference 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));
    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);
 }
 // ----其它工具----------------------------------------------------------------------------------
 /**
  * 从网上下载图片
  * 
  * @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 转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 转 drawable
  * 
  * @param bm
  * @return
  */
 public static Drawable bitmap2Drable(Bitmap bm) {
  return new BitmapDrawable(bm);
 }
 /**
  * 把字节数组通过BASE64Encoder转换成字符串
  * 
  * @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;
 }
 /**
  * 把字节数据转换成Drawable
  * 
  * @param imgByte
  *   字节数据
  * @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;
 }
 /**
  * 把图片转换成字节数组
  * 
  * @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------------>发生未知异常!");
   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);
 }
 /**
  * 计算图片的缩放大小 如果==1,表示没变化,==2,表示宽高都缩小一倍 ----------------------------------------------------------------------------
  * inSampleSize是BitmapFactory.Options类的一个参数,该参数为int型, 他的值指示了在解析图片为Bitmap时在长宽两个方向上像素缩小的倍数。inSampleSize的默认值和最小值为1(当小于1时,解码器将该值当做1来处理),
  * 且在大于1时,该值只能为2的幂(当不为2的幂时,解码器会取与该值最接近的2的幂)。 例如,当inSampleSize为2时,一个2000*1000的图片,将被缩小为1000*500,相应地, 它的像素数和内存占用都被缩小为了原来的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宽高分别大于目标尺寸宽高的前提下,取可能的inSampleSize的最大值
   while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) {
    inSampleSize *= 2;
   }
  }
  return inSampleSize;
 }
 /**
  * 根据计算出的inSampleSize生成Bitmap(此时的bitmap是经过缩放的图片)
  * 
  * @param res
  * @param resId
  * @param reqWidth
  * @param reqHeight
  * @return
  */
 public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) {
  // 首先设置 inJustDecodeBounds=true 来获取图片尺寸
  final BitmapFactory.Options optiOns= new BitmapFactory.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;
  return BitmapFactory.decodeResource(res, resId, options);
 }
 /**
  * 将图片保存到本地时进行压缩, 即将图片从Bitmap形式变为File形式时进行压缩, 
  * 特点是: File形式的图片确实被压缩了, 但是当你重新读取压缩后的file为 Bitmap是,它占用的内存并没有改变
  * 
  * @param bmp
  * @param file
  */
 public static void compressBmpToFile(Bitmap bmp, File file) {
  ByteArrayOutputStream baos = new ByteArrayOutputStream();
  int optiOns= 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 {
   FileOutputStream fos = new FileOutputStream(file);
   fos.write(baos.toByteArray());
   fos.flush();
   fos.close();
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
 /**
  * 将图片从本地读到内存时,进行压缩 ,即图片从File形式变为Bitmap形式
  * 特点: 通过设置采样率, 减少图片的像素, 达到对内存中的Bitmap进行压缩
  * @param srcPath
  * @return
  */
 public static Bitmap compressImageFromFile(String srcPath, float pixWidth, float pixHeight) {
  BitmapFactory.Options optiOns= new BitmapFactory.Options();
  options.inJustDecodeBounds = true;// 只读边,不读内容
  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  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);
  // return compressBmpFromBmp(bitmap);//原来的方法调用了这个方法企图进行二次压缩
  // 其实是无效的,大家尽管尝试
  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根据设备屏幕尺寸和dpi的不同,给系统分配的单应用程序内存大小也不同,具体如下表
  * 
  * 屏幕尺寸 DPI 应用内存 
  * 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
  */
}

更多关于Android相关内容感兴趣的读者可查看本站专题:《Android图形与图像处理技巧总结》、《Android开发入门与进阶教程》、《Android调试技巧与常见问题解决方法汇总》、《Android基本组件用法总结》、《Android视图View技巧总结》、《Android布局layout技巧总结》及《Android控件用法总结》

希望本文所述对大家Android程序设计有所帮助。


推荐阅读
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • 【Windows】实现微信双开或多开的方法及步骤详解
    本文介绍了在Windows系统下实现微信双开或多开的方法,通过安装微信电脑版、复制微信程序启动路径、修改文本文件为bat文件等步骤,实现同时登录两个或多个微信的效果。相比于使用虚拟机的方法,本方法更简单易行,适用于任何电脑,并且不会消耗过多系统资源。详细步骤和原理解释请参考本文内容。 ... [详细]
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • 本文介绍了在SpringBoot中集成thymeleaf前端模版的配置步骤,包括在application.properties配置文件中添加thymeleaf的配置信息,引入thymeleaf的jar包,以及创建PageController并添加index方法。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • 本文讲述了作者通过点火测试男友的性格和承受能力,以考验婚姻问题。作者故意不安慰男友并再次点火,观察他的反应。这个行为是善意的玩人,旨在了解男友的性格和避免婚姻问题。 ... [详细]
  • 安卓select模态框样式改变_微软Office风格的多端(Web、安卓、iOS)组件库——Fabric UI...
    介绍FabricUI是微软开源的一套Office风格的多端组件库,共有三套针对性的组件,分别适用于web、android以及iOS,Fab ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 后台获取视图对应的字符串
    1.帮助类后台获取视图对应的字符串publicclassViewHelper{将View输出为字符串(注:不会执行对应的ac ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Google Play推出全新的应用内评价API,帮助开发者获取更多优质用户反馈。用户每天在Google Play上发表数百万条评论,这有助于开发者了解用户喜好和改进需求。开发者可以选择在适当的时间请求用户撰写评论,以获得全面而有用的反馈。全新应用内评价功能让用户无需返回应用详情页面即可发表评论,提升用户体验。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
author-avatar
狠心狼fd
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有