• CompressUtil 流程图:


CompressUtil 类 具体解释

public class CompressUtil {

/**
* 终于封装的压缩方法
* @param imgPath
* @return
*/
public static Bitmap process(String imgPath){
int degree = readPictureDegree(imgPath); //获取旋转角度
Bitmap bmp =getBmpByMaxSize(imgPath, 480); //获取当前路径图片的位图,最大尺寸180*1024
if (degree != 0) {
bmp = rotaingImageView(degree, bmp); //有旋转角度的旋转角度
}
return bmp;
}
/**
* 读取图片属性:旋转的角度
* @param path 图片绝对路径
* @return degree旋转的角度
*/
@SuppressLint("NewApi")
public static int readPictureDegree(String path){
int degree = 0; //设置默认图片角度为0度
try {
/**
* Exif: 图像信息
* Exif是一种图像文件格式。它的数据存储与JPEG格式是全然同样的。 * 实际上Exif格式就是在JPEG格式头部插入了数码照片的信息。包含
* 拍摄时的光圈、快门、白平衡、ISO、焦距、日期时间等各种和拍摄
* 条件以及相机品牌、型号、色彩编码、拍摄时录制的声音以及GPS全
* 球定位系统数据、缩略图等。 你能够利用不论什么能够查看JPEG文件的
* 看图软件浏览Exif格式的照片,但并非全部的图形程序都能处理
* Exif信息。
*
* ExifInterface: 图像信息接口类
*/ /**
* ExifInterface构造函数 ExifInterface(String filename)
* 从指定的JPEG文件里读取EXIF标签。 */ //获取指定图片的图片处理对象
ExifInterface exifInterface = new ExifInterface(path); /**
* int <- getAttributeInt(String tag, int defaultValue)
* 返回指定标记的整数值
*
* Attribute : 属性
*
* tag : 指标 (一共21个)
* ExifInterface.TAG_APERTURE => 光圈指标
* ExifInterface.TAG_DATETIME => 日期时间指标
* ExifInterface.TAG_EXPOSURE_TIME => 公布时间指标
* ExifInterface.TAG_FLASH => 闪光灯
* ExifInterface.TAG_FOCAL_LENGTH => 焦距指标
* ExifInterface.TAG_GPS_ALTITUDE => GPS海拔高度指标
* ExifInterface.TAG_GPS_ALTITUDE_REF => GPS海拔參考点指标
* ExifInterface.TAG_GPS_DATESTAMP => GPS日期戳指标
* ExifInterface.TAG_GPS_LATITUDE => GPS纬度指标
* ExifInterface.TAG_GPS_LATITUDE_REF => GPS纬度參考点指标
* ExifInterface.TAG_GPS_LONGITUDE => GPS经度指标
* ExifInterface.TAG_GPS_LONGITUDE_REF => GPS经度參考点指标
* ExifInterface.TAG_GPS_PROCESSING_METHOD => GPS加工指标
* ExifInterface.TAG_GPS_TIMESTAMP => GPS时间戳指标
* ExifInterface.TAG_IMAGE_LENGTH => 图像长度指标
* ExifInterface.TAG_IMAGE_WIDTH => 图像宽度指标
* ExifInterface.TAG_ISO => 标签
* ExifInterface.TAG_MAKE => 制作
* ExifInterface.TAG_MODEL => 模型
* ExifInterface.TAG_ORIENTATION => 定位指标
* ExifInterface.TAG_WHITE_BALANCE => 白平衡指标
*
* defaultValue : 默认值 (一共11个)
*
* ExifInterface.ORIENTATION_FLIP_HORIZONTAL => 水平翻转
* ExifInterface.ORIENTATION_FLIP_VERTICAL => 垂直翻转
* ExifInterface.ORIENTATION_NORMAL => 正常
* ExifInterface.ORIENTATION_ROTATE_180 => 旋转180度
* ExifInterface.ORIENTATION_ROTATE_270 => 旋转270度
* ExifInterface.ORIENTATION_ROTATE_90 => 旋转90度
* ExifInterface.ORIENTATION_TRANSPOSE => 取向的转置
* ExifInterface.ORIENTATION_TRANSVERSE => 方位横向
* ExifInterface.ORIENTATION_UNDEFINED => 方向没有定义
* ExifInterface.WHITEBALANCE_AUTO => 白平衡自己主动
* ExifInterface.WHITEBALANCE_MANUAL => 手动白平衡
*/ // 获取该图片的方向參数
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_ROTATE_90);
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;
} /**
* 旋转图片
* @param angle
* @param bitmap
* @return Bitmap
*
* Bitmap : 位图
* Bitmap是Android系统中的图像处理的最重要类之中的一个。
* 用它能够获取图像文件信息。进行图像剪切、旋转、缩
* 放等操作。并能够指定格式保存图像文件。
*
* Bitmap实如今android.graphics包中。 可是Bitmap
* 类的构造函数是私有的,外面并不能实例化。仅仅能是通
* 过JNI实例化。 这必定是 某个辅助类提供了创建Bitmap
* 的接口,而这个类的实现通过JNI接口来实例化Bitmap的,
* 这个类就是BitmapFactory。
*
* decode : 解码
*
* BitmapFactory.decodeFile(String pathName)
* BitmapFactory.decodeFile(String pathName,Options opts)
* BitmapFactory.decodeResource(Resource res,int id)
* BitmapFactory.decodeResource(Resource res,int id,Options opts)
*
* 利用BitmapFactory能够从一个指定文件里,利用decodeFile()解出Bitmap;
* 也能够定义的图片资源中,利用decodeResource()解出Bitmap
*
* 当中Options是decode时的选项
* 在用法decodeFile()/decodeResource()时。都能够指定一个BitmapFacotry.Options。
*
* 利用Options的下列属性,能够指定decode的选项
* inPreferredConfig => decode到内存中,手机中所採用的编码,可选值定义在Bitmap.Config中。缺省值是ARGB_8888
* inJustDecodeBounds => 假设设置为true,并不会把图像的数据全然解码,亦即decodeXyz()返回值为null,可是Options的outAbc中解出了图像的基本信息
* inSampleSize => 设置decode时的缩放比例
*
*/
public static Bitmap rotaingImageView(int angle , Bitmap bitmap) { // Bitmap能够和Matrix结合实现图像的剪切、旋转、缩放等操作 //获取Matrix对象
Matrix matrix = new Matrix();
//设置旋转角度
matrix.postRotate(angle);
// 创建新的图片
Bitmap resizedBitmap=bitmap; /**
* 用原Bitmap通过变换生成新的Bitmap的方法:
*
* public static Bitmap createBitmap(Bitmap source,int x,int y,int width,int height,Matrix m,boolean filter)
* 这样的方法是终于的实现,后两种仅仅是对这样的方法的封装
*
* public static Bitmap createBitmap(Bitmap source,int x,int y,int width,int height)
* 这样的方法能够从源Bitmap中指定区域(x,y, width, height)中挖出一块来实现剪切
*
* public static Bitmap createScaledBitmap(Bitmap src,int dstWidth,int dstHeight,boolean filter)
* 这样的方法能够把源Bitmap缩放为dstWidth x dstHeight的Bitmap
*
* filter => 设为true => 对Bitmap进行滤波处理,会有抗锯齿的效果
*/ try {
resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); /**
* Bitmap的recycle问题
* recycle : 回收
* 尽管Android有自己的垃圾回收机制,对于是不是要我们自己调用recycle。还的看情况而定。
* 假设仅仅是使用少量的几张图片,回收与否关系不大。可是若有大量bitmap须要垃圾回收处理,
* 那必定垃圾回收须要做的次数就很多其它也发生地更频繁。会对系统资源造成负荷。所以,这个时
* 候还是自己试用recycle来释放的比較好。
*
* 注意 => 仅仅有当你确认你不会在使用这个bitmap的时候。就能够选择调用recycle()方法释放它。
*
*/
bitmap.recycle(); //进行垃圾回收
System.gc();
}catch (OutOfMemoryError e){
e.printStackTrace();
}
return resizedBitmap;
} /**
* 降低图片质量压缩
* @param bmp
* @param maxSize
* @param fileSize
* @return
*/
public static Bitmap compressBmp(Bitmap bmp, int maxSize, long fileSize) {
Bitmap newBmp=bmp;
//ByteArrayOutputStream => 捕获内存缓冲区的数据,转换成字节数组。
ByteArrayOutputStream baos=null;
//ByteArrayInputStream => 将字节数组转化为输入流
ByteArrayInputStream bais=null; int quality = 100;
if(fileSize>4*1024*1024){
quality=40;
}else if(fileSize>2*1024*1024){
quality=50;
}else if(fileSize>800*1024){
quality=60;
}
try {
/**
* ByteArrayOutputStream类是在创建它的实例时,程序内部创建一个byte型别数组的缓冲区,
* 然后利用ByteArrayOutputStream和ByteArrayInputStream的实例向数组中写入或读出
* byte型数据。在网络传输中我们往往要传输非常多变量。我们能够利用ByteArrayOutputStream
* 把全部的变量收集到一起。然后一次性把数据发送出去。 */
baos = new ByteArrayOutputStream();
System.out.print("開始压缩: " + quality);
/**
* 图片压缩
* Bitmap.compress(CompressFormat format, int quality, OutputStream stream)
* 方法的參数format可设置JPEG或PNG格式;quality可选择压缩质量;fOut是输出流(OutputStream)
*/
bmp.compress(Bitmap.CompressFormat.JPEG, quality, baos);
float maxByte = maxSize * 1024;
baos.flush();
float scale = 1;
while (baos.size() > maxByte) {
System.out.print("压缩大小:" + baos.size() / 1024);
System.out.print("压缩大小2:" + baos.toByteArray().length / 1024);
scale = Math.round((float) baos.size() / maxByte);
if (scale < 1) scale = 1;
quality -= scale * 2;
baos.reset(); //重置流,使流计数=0。 重置该流丢弃全部当前累积输出。
bmp.compress(Bitmap.CompressFormat.JPEG, quality, baos);
baos.flush();
}

// File file=new File(FileUtil.getAudioPath()+File.separator+System.currentTimeMillis()+”.jpg”);

// BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(file));

// bos.write(baos.toByteArray());

// bos.flush();

// bos.close();

        System.out.print("压缩后大小:" + baos.size() / 1024);
bais = new ByteArrayInputStream(baos.toByteArray());
baos.flush();
newBmp = BitmapFactory.decodeStream(bais);
bmp.recycle();
System.gc();
}catch (OutOfMemoryError e){
e.printStackTrace();
//内存溢出则压缩很多其它
if(!bmp.isRecycled()) {
try {
quality=quality/2;
baos = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.JPEG, quality, baos);
bais = new ByteArrayInputStream(baos.toByteArray());
baos.flush();
newBmp = BitmapFactory.decodeStream(bais);
}catch (Exception ex){}
}
}catch (Exception e){
e.printStackTrace();
}finally{
try {
if (bais != null) {
bais.close();
}
if (baos != null) {
baos.close();
}
}catch (Exception e){}
}
return newBmp;
} public static Bitmap getBmpByMaxSize(String path, int maxSize){
/**
* Android使用BitmapFactory.Options解决载入大图片内存溢出问题
*
* 因为Android对图片使用内存有限制。若是载入几兆的大图片便内存溢出。
* Bitmap会将图片的全部像素(即长x宽)载入到内存中,假设图片分辨率
* 过大,会直接导致内存溢出(java.lang.OutOfMemoryError),仅仅有
* 在BitmapFactory载入图片时使用BitmapFactory.Options对相关參
* 数进行配置来降低载入的像素。
*
* BitmapFactory.Options这个类。有一个字段叫做 inJustDecodeBounds 。 * 假设我们把它设为true。那么BitmapFactory.decodeFile(String path,
* Options opt)并不会真的返回一个Bitmap给你,它仅仅会把它的宽。高取回
* 来给你,这样就不会占用太多的内存。也就不会那么频繁的发生OOM(Out Of
* Memory)了。 *
*/
BitmapFactory.Options options=new BitmapFactory.Options();
//使图片最小边框缩小到800像素
options.inJustDecodeBounds=true;
//这里返回的bitmap=null,但能够通过options.outWidth 和 options.outHeight就是我们想要的宽和高了
BitmapFactory.decodeFile(path, options);
//最短的永远都是宽度
double width=options.outWidth<options.outHeight? options.outWidth: options.outHeight;
//实际宽度/理想宽度 => 上传图片缩放比例
int sampleSize=(int)Math.round(width/480);
System.out.print("上传图片缩放比例:" + sampleSize);
if(sampleSize<1) sampleSize=1;
/**
* inSampleSize表示缩略图大小为原始图片大小的几分之中的一个,
* 即假设这个值为2,则取出的缩略图的宽和高都是原始图片的1/2,图片大小就为原始大小的1/4。
*/
options.inSampleSize = sampleSize;
options.inJustDecodeBounds=false;
options.inDither=false; /*不进行图片抖动处理*/
options.inPreferredConfig=null; /*设置让解码器以最佳方式解码*/
/**
* 以下两个字段须要组合使用 节约内存
*/
options.inPurgeable = true; // 同意可清除
options.inInputShareable = true; long length=new File(path).length();
if(length>(1.5*1024*1024)){ //大于1.5M时
options.inSampleSize+=(int)(length/1024/1024)*0.5; //当大于2M时为避免内存溢出缩小
} Bitmap bitmap=null;
try {
bitmap = BitmapFactory.decodeFile(path, options);
}catch (OutOfMemoryError e){
e.printStackTrace();
//内存溢出则将图片缩小一半
if(options.inSampleSize<1) options.inSampleSize=1;
options.inSampleSize=options.inSampleSize*2;
bitmap=BitmapFactory.decodeFile(path, options);
}
if(length>(800*1024)) { //大于20K字节压缩
bitmap = compressBmp(bitmap, maxSize, length);
} return bitmap;
}

}

图片压缩CompressUtil解析的更多相关文章

  1. 好久没发贴了,最近捣鼓了个基于node的图片压缩小网站解析。

    看了下,距离上次发帖都是去年10月份的事,忙于工作的我很少跑博客园里面来玩了. 做这个小网站的初衷是 https://tinypng.com/ 这个网站有时候访问很慢,然后自己去研究了下图片压缩. 网 ...

  2. Android 调用jepg库进行图片压缩,保持图片不失真

    1. 浅谈为什么Android和iOS图片质量差距那么大? 首先来说,作为一个安卓狗,机器当然用的是安卓的手机.现在的安卓手机大多数都会以高清拍照,动不动就几千万柔光相机来吸引各种买家.买来后,拍照发 ...

  3. H5图片压缩上传

    1.所用到技术 HTML5 API:filereader.canvas 以及 formdata 目前来说,HTML5的各种新API都在移动端的webkit上得到了较好的实现.本次使用到的FileRea ...

  4. android图片压缩总结

    一.bitmap 图片格式介绍 android中图片是以bitmap形式存在的,那么bitmap所占内存,直接影响到了应用所占内存大小,首先要知道bitmap所占内存大小计算方式: bitmap内存大 ...

  5. springMVC多图片压缩上传的实现

    首先需要在配置文件中添加配置: <!--配置文件的视图解析器,用于文件上传,其中ID是固定的:multipartResolver--> <bean id="multipar ...

  6. 基于vue + axios + lrz.js 微信端图片压缩上传

    业务场景 微信端项目是基于Vux + Axios构建的,关于图片上传的业务场景有以下几点需求: 1.单张图片上传(如个人头像,实名认证等业务) 2.多张图片上传(如某类工单记录) 3.上传图片时期望能 ...

  7. 基于H5+ API手机相册图片压缩上传

    // 母函数 function App(){} /** * 图片压缩,默认同比例压缩 * @param {Object} path * pc端传入的路径可以为相对路径,但是在移动端上必须传入的路径是照 ...

  8. 移动端 H5 拍照 从手机选择图片,移动端预览,图片压缩,图片预览,再上传服务器

    前言:最近公司的项目在做全网营销,要做非微信浏览器的wap 站 的改版,其中涉及到的一点技术就是采用H5 选择手机相册中的图片,或者拍照,再将获取的图片进行压缩之后上传. 这个功能模块主要有这5点比较 ...

  9. 每个人都要学的图片压缩终极奥义,有效解决 Android 程序 OOM

    # 由来 在我们编写 Android 程序的时候,几乎永远逃避不了图片压缩的难题.除了应用图标之外,我们所要显示的图片基本上只有两个来源: 来自网络下载 本地相册中加载 不管是网上下载下来的也好,还是 ...

随机推荐

  1. 关于UITextView的限制字数显示,以及emjor表情占用字节处理,复制粘贴字节处理~优化

    //限制字数 #define MAX_LIMIT_NUMS 30 1 #pragma mark -- textview的代理事件 - (BOOL)textView:(UITextView *)text ...

  2. Linux服务器之SSH

    SSH 1.ssh是安全的加密协议,用于远程连接linux服务器. 2.ssh默认端口是22,安全协议版本ssh2. 3.ssh服务端主要包含两个服务功能ssh远程连接,sftp服务. 4.linux ...

  3. 【CF1068C】Colored Rooks(构造)

    题意: 思路: #include<cstdio> #include<cstring> #include<string> #include<cmath> ...

  4. 让你的man手册显示与众不同

    在~/.bashrc中加入如下代码: export LESS_TERMCAP_mb=$'\E[01;31m' export LESS_TERMCAP_md=$'\E[01;31m' export LE ...

  5. linux下终端录制

    主要是以下三步: 一.安装软件:curl -sL https://asciinema.org/install | sh 二.录制终端:asciinema rec filename 三.回放终端:asc ...

  6. 【linux高级程序设计】(第八章)进程管理与程序开发 5

    守候进程 启动方式: 在系统启动时由/etc/rd.d目录下的启动脚本启动 利用inetd超级服务器启动 有cron命令定时启动,以及在终端用nohup命令启动 守护进程编程要点 (1)屏蔽有关控制终 ...

  7. 记录: 百度webuploader 分片文件上传java服务器端(spring mvc)示例的优化

    最近项目上用到文件分片上传,于是找到了百度的一个开源前端控件webuploader. 于是尝试使用. 下载下来后,它提供的服务器端示例代码是php版的,那么Java版的呢? 其实,上传文件都是按照rf ...

  8. C# ASP.NET中Process.Start没有反应也没有报错的解决方法

    最近有一个很坑的需求,在ASP.NET中打开一个access,还要用process.start打开,调试时一切正常,到了发布后就没有反应,找了一下午,各种设文件夹权限也不行,最后把应用程序池改成管理员 ...

  9. Vscode 小白使用介绍

    前言   现在使用Vscode编码的人越来越多,凭借着免费,开源,轻量,跨平台的特点收货了一大批忠实粉丝 最近因项目需要开始使用Vscode,但不知为何,感觉有点力不从心,不知道该怎么用 首先想到去官 ...

  10. Cat Snuke and a Voyage --AtCoder

    题目描述 In Takahashi Kingdom, there is an archipelago of N islands, called Takahashi Islands. For conve ...