图片压缩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;
}

}

原文地址:https://www.cnblogs.com/llguanli/p/8617998.html

时间: 2024-11-09 03:38:02

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

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

看了下,距离上次发帖都是去年10月份的事,忙于工作的我很少跑博客园里面来玩了. 做这个小网站的初衷是 https://tinypng.com/ 这个网站有时候访问很慢,然后自己去研究了下图片压缩. 网上有看到 https://tinypng.com/ 中使用的 pngquant , 我去下载了pngquant的cli看了下,然后就开始了这个小网站的基础. 先看看前端页面: 这个功能还会扩建,所以现在界面只有简洁的一部分. 现在的功能基本上只有图片压缩和打包下载, 前端页面用到的: vue.web

spring mvc 图片上传,图片压缩、跨域解决、 按天生成目录 ,删除,限制为图片代码等相关配置

spring mvc 图片上传,跨域解决 按天生成目录 ,删除,限制为图片代码,等相关配置 fs.root=data/ #fs.root=/home/dev/fs/ #fs.root=D:/fs/ #fs.domains=182=http://172.16.100.182:18080,localhost=http://localhost:8080 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE be

Android图片压缩技巧

请尊重他人的劳动成果,转载请注明出处:Android图片压缩技巧 http://blog.csdn.net/fengyuzhengfan/article/details/41759835 当需要将Android客户端的图片上传到服务器时,往往需要将图片进行压缩,关于图片的压缩方法,小编分享几种常用的方式: 第一种方式:裁切以达到压缩的目的 我曾在<Android开发之裁剪照片>一文中详细介绍过如何裁切照片,感兴趣的朋友可以去看一下. 第二种方式:将图片进行降质处理(即降低图片的质量)以达到压缩

功能这么齐全的图片压缩类,还有谁?

效果图: 压缩日志 com.pengkv.moon I/--->: 原尺寸:1215*1080 com.pengkv.moon I/--->: 最终压缩比例:3倍/新尺寸:405*360 工具特点 * 可以解析单张图片 * 可以解析多张图片 * 处理了压缩过程中OOM * 处理了部分手机照片旋转问题 * 压缩后存储在缓存中,并可以清理 * 压缩后返回缓存路径,方便上传 * 可以从缓存路径读取出Bitmap,方便展示 * 封装在2个类里,方便调用 使用方法 ImageCompressUtil.c

Android之图片压缩

1. 引子 前几天跟服务端的一个妹子联调接口,服务器配置一张图片,几十KB就行,她问我图片从哪里找,我告诉她先随便在网上找个图片链接就行了.结果一运行程序,就崩溃了,出现了下面的异常. java.lang.OutofMemoryError 内存溢出OOM,我当时一脸懵逼. 图-1 一脸懵逼 于是拿着后台返回的链接去查看了一下图片,是一张6M的壁纸. 图-2 我内心几乎是崩溃的 这只是一个简单的联调,而在联调过程中操作不当导致出现OOM问题,大家就当是个玩笑.其实在Android中很容易出现OOM

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

// 母函数 function App(){} /** * 图片压缩,默认同比例压缩 * @param {Object} path * pc端传入的路径可以为相对路径,但是在移动端上必须传入的路径是照相图片储存的绝对路径 * @param {Object} obj * obj 对象 有 width, height, quality(0-1) * @param {Object} callback * 回调函数有一个参数,base64的字符串数据 */ App.prototype.dealImage

每个人都要懂的图片压缩,有效解决 Android 程序 OOM

# 由来 在我们编写 Android 程序的时候,几乎永远逃避不了图片压缩的难题.除了应用图标之外,我们所要显示的图片基本上只有两个来源: 来自网络下载 本地相册中加载 不管是网上下载下来的也好,还是从系统图片库中读取的图片,都有一个相同的特点:像素一帮较高.同时我们都知道,Android 系统分配给我们每个应用的内存是有限的,由于解析.加载一张图片,需要占用的内存大小,是远大于图片自身大小的.所以,这时程序就可能因为占用了过多的内存,从而出现OOM 现象.那么什么是 OOM 呢? Except

java 图片压缩变色问题

java图片压缩,有时由于图片自身的原因,如透明的PNG图.改alpha通道或四色图等. 压缩完了,会出现图片变色的情况. 如: 原图 压缩完: 尝试了很多方法,如JDK原生的方式及第三方组件java-image-scaling或thumbnailator都不解决问题. 后来采用阿里的SimpleImage解决.记录一下 SimpleImage github地址:https://github.com/alibaba/simpleimage依赖jar:commons-io-2.4.jarcommo

Html5+asp.net mvc 图片压缩上传

在做图片上传时,大图片如果没有压缩直接上传时间会非常长,因为有的图片太大,传到服务器上再压缩太慢了,而且损耗流量. 思路是将图片抽样显示在canvas上,然后用通过canvas.toDataURL方法得到base64字符串来实现压缩. 废话不多少不多说直接看代码: 本次测试使用了 zepto.min.js 插件,更新版本的下载请点击这里 主要js代码: //图片压缩处理 ; (function () { /** * 加载的时候进行抽样检测 * 在iOS中,大于2M的图片会抽样渲染 */ func