Bitmap,jpg,png区别以及在Android上实现不载入内存压缩图片

来源:互联网 发布:淘宝售后服务内容 编辑:程序博客网 时间:2024/05/22 13:42

图片有两种使用的场景:一种是在硬盘上的存储格式,一个是在内存的展开格式。

一、在内存中的图片

         因为需要知道图片的所有信息,所有在内存中,图片一般是展开的。那以带透明的Bitmap来说。这里有一些概念。

        1.像素点组成:颜色有R(red红色)、G (green绿色)、B (Blue蓝色) 三色组成,再考虑到透明值的问题会有一个A(alpha阿尔法值)。

        2.位深度:你需要用多少Bit来表示一个像素点。如果是位深度是32,则每八位分别表示R,G,B,A

如果在内存中完全展开,其所占内存大小为:宽像素点数  X   高像素点数 X 位深度 /  8  ,单位是字节

        Android中的在内存中完全展开就是Bitmap的格式,Bitmap是最原始的保存着所有的信息,(一般不在硬盘上这么保存)

        图片中所指的分辨率与打印扫描有关,一般不关注。

        在日常交流的过程中所指的分辨率一般指的是其宽和高的像素点个数。

二、在硬盘上的图片

        图片如果按照内存那样的方式来进行存储太浪费空间了。举个例子,如果有一张图片全部都是红色,有必要存储每个像素点吗?其只需要记录下其红色和大小就好了,在内存中可以重新还原。一般在传输和存储的过程中都对图片进行压缩。

        1.PNG 是一种无损压缩。并且带有透明度值。压缩的实在有限!

        2.JPG是一种有损压缩,不带透明值(这就是为什么上图的位深度为24了)。在不影响使用的情况下回丢弃一部分信息,肉眼一般区分不出来。

        对同一张Bitmap图片保存为JPG,比保存为PNG小的多,这就是为什么网络上使用最多是JPG格式的图片了


三、以上是摘自网上的一些基本知识点,对于我们通常说的jpg和png他们的展现形式就是在电脑或手机设备上的展现,比如1MB就是实际空间的1MB

Bitmap是他们的展现表示,比如刚才的1MB的jpg图片分辨率是1920*1080,如果是以Bitmap展示在手机上所占内存就是1920*1080*4~=8MB。


四、项目中有这样的需求,就是想尽量让用户传自己的高清图片,但是为了防止部分图片太大,规定,小于3MB的直接传,大于3MB的先比例无损压缩然后再质量压缩知道大小小于3MB,这里的3MB就是jpg和png在硬件上的存储大小了;所以我们首先要获取他们在硬件媒介上的大小后才开始压缩。


大概思路如下:

首先使用BitmapFactory来加载图片,通过OptionConfig的inJustDecodeBounds参数来进行无加载内存先获取图片的宽高像素点大小,bitmap的大小计算公式就是w*h*4这个4是一个通用的图片格式位数,计算出大小后如果大于3MB,先循环比例压缩,还大就质量压缩了,知道小于3MB。



    //获取Bitmap的Base64编码的String值;    //1.首先不加载内存粗略获取Bitmap大小,如果大于3MB    //2.循环3次缩放比例压缩,如果3次比例压缩后还大于3MB,采用质量压缩知道小于3MB    //3.如果Bitmap小于3MB,根据图片类型采取相应的无损压缩    //4.最后对Bitmap Base64    public static BitmapString getBitmapString(String srcPath){        BitmapFactory.Options newOpts = new BitmapFactory.Options();        BitmapString bitmapString = new BitmapString();        //开始读入图片,此时把options.inJustDecodeBounds 设回true了        newOpts.inJustDecodeBounds = true;        BitmapFactory.decodeFile(srcPath,newOpts);//此时返回bm为空        int w = newOpts.outWidth;        int h = newOpts.outHeight;        String type = newOpts.outMimeType;        bitmapString.setMimeType(type);        LogUtil.w("w:"+w+",h:"+h);        //图片大于3MB        if(w*h*4/1024/1024/8 > 3){            Bitmap bitmap = compressImageWithWH(newOpts,srcPath,newOpts.outWidth,newOpts.outHeight,1);            if(bitmap != null){                ByteArrayOutputStream baos = new ByteArrayOutputStream();                bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);                bitmapString.setBitmapString(Base64Util.encode(baos.toByteArray()));                return bitmapString;            }else{                LogUtil.w("bitmap is null");                return null;            }        }else{            newOpts.inJustDecodeBounds = false;            Bitmap bitmap = BitmapFactory.decodeFile(srcPath, newOpts);            if(type.contains("jpeg")){                ByteArrayOutputStream baos = new ByteArrayOutputStream();                bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);                bitmapString.setBitmapString(Base64Util.encode(baos.toByteArray()));                return bitmapString;            }else if(type.contains("png")){                ByteArrayOutputStream baos = new ByteArrayOutputStream();                bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);                bitmapString.setBitmapString(Base64Util.encode(baos.toByteArray()));                return bitmapString;            }else {                ByteArrayOutputStream baos = new ByteArrayOutputStream();                bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);                bitmapString.setBitmapString(Base64Util.encode(baos.toByteArray()));                return bitmapString;            }        }    }
    //循环比例压缩图片
    private static Bitmap compressImageWithWH(BitmapFactory.Options newOpts,String srcPath,int w,int h,int times){        LogUtil.w("compressImageWithWH"+times);        int be = 0;        if(1 == times)            be = getBitmapInSampleSize(1920f,1080f,w,h);        else if(2 == times)            be = getBitmapInSampleSize(1280f,720f,w,h);        else if(3 == times)            be = getBitmapInSampleSize(800f,480f,w,h);        LogUtil.w("be:"+be);        newOpts.inSampleSize = be;//设置缩放比例        newOpts.inJustDecodeBounds = true;        //重新读入图片        BitmapFactory.decodeFile(srcPath, newOpts);        int mW = newOpts.outWidth;        int mH = newOpts.outHeight;        LogUtil.w("mW:"+mW+",mH:"+mH);        if(mW*mH*4/1024/1024/8 > 3){            if(1 == times)                compressImageWithWH(newOpts,srcPath,newOpts.outWidth,newOpts.outHeight,2);            else if(2 == times)                compressImageWithWH(newOpts,srcPath,newOpts.outWidth,newOpts.outHeight,3);            else if(3 == times){                newOpts.inJustDecodeBounds = false;                Bitmap bitmap =  BitmapFactory.decodeFile(srcPath, newOpts);                return compressImage(bitmap);            }        }else{            newOpts.inJustDecodeBounds = false;            Bitmap bitmap =  BitmapFactory.decodeFile(srcPath, newOpts);            return bitmap;        }        return null;    }
//获取压缩比例值
private static int getBitmapInSampleSize(float ww,float hh,int w,int h){        //缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可        int be = 1;//be=1表示不缩放        if (w > h && w > ww) {//如果宽度大的话根据宽度固定大小缩放            be = (int) (w / ww);        } else if (w < h && h > hh) {//如果高度高的话根据高度固定大小缩放            be = (int) (h / hh);        }        if (be <= 0)            be = 1;        return be;    }
//质量压缩
public static Bitmap compressImage(Bitmap image) {        Bitmap c_bitmap = null ;        try {            ByteArrayOutputStream baos = new ByteArrayOutputStream();            image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中            int options = 100;            while ( baos.toByteArray().length / 1024/1024>3) {  //循环判断如果压缩后图片是否大于3mb,大于继续压缩                LogUtil.w("baos.toByteArray().length:"+baos.toByteArray().length);                baos.reset();//重置baos即清空baos                options -= 10;//每次都减少10                image.compress(Bitmap.CompressFormat.JPEG, options, baos);//这里压缩options%,把压缩后的数据存放到baos中            }            ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把压缩后的数据baos存放到ByteArrayInputStream中            c_bitmap = BitmapFactory.decodeStream(isBm, null, null);            return c_bitmap;        } catch (Exception e) {            return c_bitmap;        }    }

注意在上面做大小比较的时候有个除以8的操作,因为宽高乘以4算出的是位除以8才是byte字节。







0 0