Android整理好的图片压缩工具类

Android设备的内存有限,对于大图片,必须进行压缩后再进行显示,否则会出现内存溢出:OOM;

处理策略:

1.使用缩略图(Thumbnails);

Android系统会给检测到的图片创建缩略图;可以操作Media内容提供者中的Image对图片进行操作;

2.手动压缩:

  • (1)根据图片和屏幕尺寸,等比压缩,完美显示;
  • (2)降低图片质量,压缩图片大小;

以下是自己整理的小工具类(对于按比例缩放后,在此并未再进行质量缩放,此时图片大小有可能超出我们期望的限制;假如我们有严格的大小限制需求,可先进行按比例缩放后,判断此时图片大小是否超出限制;如果超出限制,对其再进行质量缩放即可。建议使用按比例缩放,按质量缩放很有可能导致图片失真。)

</pre><p><pre name="code" class="java">package com.util;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.media.ExifInterface;
/**
 * 图片压缩工具类
 * @author 丶Life_
 */
public class ImageCompressUtil {
  /**
   * 通过降低图片的质量来压缩图片
   * @param bmp
   *      要压缩的图片位图对象
   * @param maxSize
   *      压缩后图片大小的最大值,单位KB
   * @return 压缩后的图片位图对象
   */
  public static Bitmap compressByQuality(Bitmap bitmap, int maxSize) {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    int quality = 100;
    bitmap.compress(CompressFormat.JPEG, quality, baos);
    System.out.println("图片压缩前大小:" + baos.toByteArray().length + "byte");
    boolean isCompressed = false;
    while (baos.toByteArray().length / 1024 > maxSize) {
      quality -= 10;
      baos.reset();
      bitmap.compress(CompressFormat.JPEG, quality, baos);
      System.out.println("质量压缩到原来的" + quality + "%时大小为:"
          + baos.toByteArray().length + "byte");
      isCompressed = true;
    }
    System.out.println("图片压缩后大小:" + baos.toByteArray().length + "byte");
    if (isCompressed) {
      Bitmap compressedBitmap = BitmapFactory.decodeByteArray(
          baos.toByteArray(), 0, baos.toByteArray().length);
      recycleBitmap(bitmap);
      return compressedBitmap;
    } else {
      return bitmap;
    }
  }
  /**
   * 传入图片url,通过压缩图片的尺寸来压缩图片大小
   * @param pathName 图片的完整路径
   * @param targetWidth 缩放的目标宽度
   * @param targetHeight 缩放的目标高度
   * @return 缩放后的图片
   */
  public static Bitmap compressBySize(String pathName, int targetWidth,
      int targetHeight) {
    BitmapFactory.Options opts = new BitmapFactory.Options();
    opts.inJustDecodeBounds = true;// 不去真的解析图片,只是获取图片的头部信息,包含宽高等;
    Bitmap bitmap = BitmapFactory.decodeFile(pathName, opts);
    // 得到图片的宽度、高度;
    int imgWidth = opts.outWidth;
    int imgHeight = opts.outHeight;
    // 分别计算图片宽度、高度与目标宽度、高度的比例;取大于等于该比例的最小整数;
    int widthRatio = (int) Math.ceil(imgWidth / (float) targetWidth);
    int heightRatio = (int) Math.ceil(imgHeight / (float) targetHeight);
    if (widthRatio > 1 || heightRatio > 1) {
      if (widthRatio > heightRatio) {
        opts.inSampleSize = widthRatio;
      } else {
        opts.inSampleSize = heightRatio;
      }
    }
    // 设置好缩放比例后,加载图片进内容;
    opts.inJustDecodeBounds = false;
    bitmap = BitmapFactory.decodeFile(pathName, opts);
    return bitmap;
  }
  /**
   * 传入bitmap,通过压缩图片的尺寸来压缩图片大小
   * @param bitmap 要压缩图片
   * @param targetWidth 缩放的目标宽度
   * @param targetHeight 缩放的目标高度
   * @return 缩放后的图片
   */
  public static Bitmap compressBySize(Bitmap bitmap, int targetWidth,
      int targetHeight) {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    bitmap.compress(CompressFormat.JPEG, 100, baos);
    BitmapFactory.Options opts = new BitmapFactory.Options();
    opts.inJustDecodeBounds = true;
    bitmap = BitmapFactory.decodeByteArray(baos.toByteArray(), 0,
        baos.toByteArray().length, opts);
    // 得到图片的宽度、高度;
    int imgWidth = opts.outWidth;
    int imgHeight = opts.outHeight;
    // 分别计算图片宽度、高度与目标宽度、高度的比例;取大于该比例的最小整数;
    int widthRatio = (int) Math.ceil(imgWidth / (float) targetWidth);
    int heightRatio = (int) Math.ceil(imgHeight / (float) targetHeight);
    if (widthRatio > 1 || heightRatio > 1) {
      if (widthRatio > heightRatio) {
        opts.inSampleSize = widthRatio;
      } else {
        opts.inSampleSize = heightRatio;
      }
    }
    // 设置好缩放比例后,加载图片进内存;
    opts.inJustDecodeBounds = false;
    Bitmap compressedBitmap = BitmapFactory.decodeByteArray(
        baos.toByteArray(), 0, baos.toByteArray().length, opts);
    recycleBitmap(bitmap);
    return compressedBitmap;
  }
  /**
   * 通过压缩图片的尺寸来压缩图片大小,通过读入流的方式,可以有效防止网络图片数据流形成位图对象时内存过大的问题;
   * @param InputStream 要压缩图片,以流的形式传入
   * @param targetWidth 缩放的目标宽度
   * @param targetHeight 缩放的目标高度
   * @return 缩放后的图片
   * @throws IOException 读输入流的时候发生异常
   */
  public static Bitmap compressBySize(InputStream is, int targetWidth,
      int targetHeight) throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte[] buff = new byte[1024];
    int len = 0;
    while ((len = is.read(buff)) != -1) {
      baos.write(buff, 0, len);
    }
    byte[] data = baos.toByteArray();
    BitmapFactory.Options opts = new BitmapFactory.Options();
    opts.inJustDecodeBounds = true;
    Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length,
        opts);
    // 得到图片的宽度、高度;
    int imgWidth = opts.outWidth;
    int imgHeight = opts.outHeight;
    // 分别计算图片宽度、高度与目标宽度、高度的比例;取大于该比例的最小整数;
    int widthRatio = (int) Math.ceil(imgWidth / (float) targetWidth);
    int heightRatio = (int) Math.ceil(imgHeight / (float) targetHeight);
    if (widthRatio > 1 || heightRatio > 1) {
      if (widthRatio > heightRatio) {
        opts.inSampleSize = widthRatio;
      } else {
        opts.inSampleSize = heightRatio;
      }
    }
    // 设置好缩放比例后,加载图片进内存;
    opts.inJustDecodeBounds = false;
    bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, opts);
    return bitmap;
  }
  /**
   * 旋转图片摆正显示
   * @param srcPath
   * @param bitmap
   * @return
   */
  public static Bitmap rotateBitmapByExif(String srcPath, Bitmap bitmap) {
    ExifInterface exif;
    Bitmap newBitmap = null;
    try {
      exif = new ExifInterface(srcPath);
      if (exif != null) { // 读取图片中相机方向信息
        int ori = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
            ExifInterface.ORIENTATION_NORMAL);
        int digree = 0;
        switch (ori) {
        case ExifInterface.ORIENTATION_ROTATE_90:
          digree = 90;
          break;
        case ExifInterface.ORIENTATION_ROTATE_180:
          digree = 180;
          break;
        case ExifInterface.ORIENTATION_ROTATE_270:
          digree = 270;
          break;
        }
        if (digree != 0) {
          Matrix m = new Matrix();
          m.postRotate(digree);
          newBitmap = Bitmap.createBitmap(bitmap, 0, 0,
              bitmap.getWidth(), bitmap.getHeight(), m, true);
          recycleBitmap(bitmap);
          return newBitmap;
        }
      }
    } catch (IOException e) {
      e.printStackTrace();
    }
    return bitmap;
  }
  /**
   * 回收位图对象
   * @param bitmap
   */
  public static void recycleBitmap(Bitmap bitmap) {
    if (bitmap != null && !bitmap.isRecycled()) {
      bitmap.recycle();
      System.gc();
      bitmap = null;
    }
  }
}

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。如果你想了解更多相关内容请查看下面相关链接

(0)

相关推荐

  • Android实现从本地图库/相机拍照后裁剪图片并设置头像

    玩qq或者是微信的盆友都知道,这些聊天工具里都要设置头像,一般情况下大家的解决办法是从本地图库选择图片或是从相机拍照,然后根据自己的喜爱截取图片.上述过程已经实现好了,最后一步我加上了把截取好的图片在保存到本地的操作,来保存头像.为了大家需要,下面我们小编把完整的代码贴出来供大家参考. 先给大家展示效果图: 代码部分: 布局代码(其实就是两个按钮和一个ImageView来显示头像) <LinearLayout xmlns:android="http://schemas.android.co

  • Android使用AsyncTask加载图片的操作流程

    加载图片基本操作 一.创建AsyncTask子类 将ImageView的弱引用设置为成员变量,创建构造函数传入ImageView对象. 调用指定大小解析Bitmap方法. 因为是弱引用,所以必须判断引用是否被回收.如果异步任务完成前,用户离开Activity或者设置发生改变,ImageView也可能不存在. class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> { private final WeakReference&

  • Android通过ExifInterface判断Camera图片方向的方法

    Android的Camera相关应用开发中,有一个必须搞清楚的知识点,就是Camera的预览方向和拍照方向 图像的Sensor方向:手机Camera的图像数据都是来自于摄像头硬件的图像传感器(Image Sensor),这个Sensor被固定到手机之后是有一个默认的取景方向的,这个方向如下图所示,坐标原点位于手机横放时的左上角: android应用里使用相机图片时必须要考虑的一个问题就是图片朝向,只有判断对朝向才能调整图片从而更好的展现.本文将介绍一种通过ExifInterface判断图片朝向的

  • Android开发从相机或相册获取图片裁剪

    废话不多说了,直接给大家贴代码了. package com.only.android.app; import java.io.File; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.graphics.Bitmap; import android.gr

  • Android启动相机拍照并返回图片

    具体实现过程请看下面代码: 简单的调用了一下系统的拍照功能 代码如下所示: //拍照的方法 private void openTakePhoto(){ /** * 在启动拍照之前最好先判断一下sdcard是否可用 */ String state = Environment.getExternalStorageState(); //拿到sdcard是否可用的状态码 if (state.equals(Environment.MEDIA_MOUNTED)){ //如果可用 Intent intent

  • Android实现读取相机(相册)图片并进行剪裁

    我们先说一下思路,在android系统中就自带了图片剪切的应用,所以,我们只需要将我们获取到的相片传给图片剪切应用,再将剪切好的相片返回到我们自己的界面显示就ok了 在开发一些APP的过程中,我们可能涉及到头像的处理,比如从手机或者相册获取头像,剪裁成自己需要的头像,设置或上传头像等.网上一些相关的资料也是多不胜数,但在实际应用中往往会存在各种问题,没有一个完美的解决方案.由于近期项目的需求,就研究了一下,目前看来还没有什么问题. 这里我们只讨论获取.剪裁与设置,上传流程根据自己的业务需求添加.

  • Android自定义组件获取本地图片和相机拍照图片

    iOS中有封装好的选择图片后长按出现动画删除效果,效果如下 而Android找了很久都没有找到有这样效果的第三方组件,最后懒得找了还是自己实现这效果吧 选择图片后还可对图片进行剪裁 当然,代码中还有很多不完善的地方,我接下来会继续完善这个组件的 已经上传到开源社区,欢迎大家来Star啊~ Demo源码:传送门 设计中的碰到的一些问题和解决思路 1.如何让加号图片显示在GridView最后面 首先在调用GridAdapter构造方法时就加载加号图片 /** * 图片适配器 * @param con

  • android中打开相机、打开相册进行图片的获取示例

    这里介绍在Android中实现相机调取.拍照片.获取照片.存储新路径等已经打开相册.选择照片等功能 首先看一下界面,很简单 配置读取内存卡和调用照相头的功能 <!-- 使用网络权限 --> <uses-permission android:name="android.permission.INTERNET"/> <!-- 写sd卡的权限 --> <uses-permission android:name="android.permis

  • Android基于OkHttp实现下载和上传图片

    本文实例为大家分享了OkHttp实现下载图片和上传图片的具体代码,供大家参考,具体内容如下 MainActivity.java public class MainActivity extends AppCompatActivity { private String Path = "https://10.url.cn/eth/ajNVdqHZLLAxibwnrOxXSzIxA76ichutwMCcOpA45xjiapneMZsib7eY4wUxF6XDmL2FmZEVYsf86iaw/"

  • Android实现相机拍摄、选择、图片裁剪功能

    最近的一些学习心得: 功能实现:点击圆形头像之后可以实现相册上传或者开启相机,然后把得到的图片经过剪裁,把剪裁过的图片设置为头像的背景图 步骤:第一步:自定义一个类,继承ImageView,重写draw方法,实现外观为圆形 第二步:在xml文件中引用该控件 第三步:实现圆形头像的点击事件,点击后显示对话框界面,询问你是打开相册还是相机(自动省略显示对话框的代码) 第四步:根据用户选择情况,打开相册或者相机 第五步:将拍摄的图片或者相册选中的图片进行剪裁,将结果保存在指定内存区域 第六步:更新头像

随机推荐