图片压缩CompressUtil解析
- 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解析的更多相关文章
- 好久没发贴了,最近捣鼓了个基于node的图片压缩小网站解析。
看了下,距离上次发帖都是去年10月份的事,忙于工作的我很少跑博客园里面来玩了. 做这个小网站的初衷是 https://tinypng.com/ 这个网站有时候访问很慢,然后自己去研究了下图片压缩. 网 ...
- Android 调用jepg库进行图片压缩,保持图片不失真
1. 浅谈为什么Android和iOS图片质量差距那么大? 首先来说,作为一个安卓狗,机器当然用的是安卓的手机.现在的安卓手机大多数都会以高清拍照,动不动就几千万柔光相机来吸引各种买家.买来后,拍照发 ...
- H5图片压缩上传
1.所用到技术 HTML5 API:filereader.canvas 以及 formdata 目前来说,HTML5的各种新API都在移动端的webkit上得到了较好的实现.本次使用到的FileRea ...
- android图片压缩总结
一.bitmap 图片格式介绍 android中图片是以bitmap形式存在的,那么bitmap所占内存,直接影响到了应用所占内存大小,首先要知道bitmap所占内存大小计算方式: bitmap内存大 ...
- springMVC多图片压缩上传的实现
首先需要在配置文件中添加配置: <!--配置文件的视图解析器,用于文件上传,其中ID是固定的:multipartResolver--> <bean id="multipar ...
- 基于vue + axios + lrz.js 微信端图片压缩上传
业务场景 微信端项目是基于Vux + Axios构建的,关于图片上传的业务场景有以下几点需求: 1.单张图片上传(如个人头像,实名认证等业务) 2.多张图片上传(如某类工单记录) 3.上传图片时期望能 ...
- 基于H5+ API手机相册图片压缩上传
// 母函数 function App(){} /** * 图片压缩,默认同比例压缩 * @param {Object} path * pc端传入的路径可以为相对路径,但是在移动端上必须传入的路径是照 ...
- 移动端 H5 拍照 从手机选择图片,移动端预览,图片压缩,图片预览,再上传服务器
前言:最近公司的项目在做全网营销,要做非微信浏览器的wap 站 的改版,其中涉及到的一点技术就是采用H5 选择手机相册中的图片,或者拍照,再将获取的图片进行压缩之后上传. 这个功能模块主要有这5点比较 ...
- 每个人都要学的图片压缩终极奥义,有效解决 Android 程序 OOM
# 由来 在我们编写 Android 程序的时候,几乎永远逃避不了图片压缩的难题.除了应用图标之外,我们所要显示的图片基本上只有两个来源: 来自网络下载 本地相册中加载 不管是网上下载下来的也好,还是 ...
随机推荐
- .bat 处理错误码
某些命令只会返回error level,而要添加互操作性,.bat文件的返回值,exit code应该最后指定,那么需要,在这个单行的命令后面单个添加处理error level 的语句,最后再做统一的 ...
- JSTL获取Session的ID与获取文件的真实路径与项目名称
今天在测试集群配置的时候想到session共享,因此想要获取sessionID,可以通过下面方法: ${pageContext.session.id} 获取文件的真实路径: <%=request ...
- 修复无法启动的mariadb
一直在用的数据库,今天无论如何启动不了了,最后在archlinux wiki上查到了解决方法: mysql_install_db --user=mysql --basedir=/usr --datad ...
- android init.rc命令快速对照表
注1:另外还讲述了怎样输出log: Debugging notes---------------By default, programs executed by init will drop stdo ...
- 转:C#制作ORM映射学习笔记二 配置类及Sql语句生成类
在正式开始实现ORM之前还有一点准备工作需要完成,第一是实现一个配置类,这个很简单的就是通过静态变量来保存数据库的一些连接信息,等同于.net项目中的web.config的功能:第二需要设计实现一个s ...
- hdu 3986(最短路变形好题)
Harry Potter and the Final Battle Time Limit: 5000/3000 MS (Java/Others) Memory Limit: 65536/6553 ...
- LeetCode OJ-- N-Queens **
https://oj.leetcode.com/problems/n-queens/ n皇后问题,1皇后有1个解,4皇后2个解,8皇后也有解…… 每个皇后不能在同一行上,同一列上,以及同一条45度线上 ...
- nodejs Centos环境搭建
使用二进制文件安装: node 环境下载 https://nodejs.org/en/download/ 下载里面的windows 安装包 和 linux 安装包 1)windows安装 window ...
- SDOI2017round1酱油记day0
嗯... 现在是21:12...准备睡了. 睡前写下day0一天如何过的: 早上5点起床到教室早自习,迷迷糊糊的宣誓,背东西,英语听写: 都停课了为什么还要上早自习! 我!想!去!机!房! OI才是我 ...
- Codeforces 906D Power Tower(欧拉函数 + 欧拉公式)
题目链接 Power Tower 题意 给定一个序列,每次给定$l, r$ 求$w_{l}^{w_{l+1}^{w_{l+2}^{...^{w_{r}}}}}$ 对m取模的值 根据这个公式 每次 ...