安卓图片的压缩,尺寸,质量,采样率和微信压缩

来源:互联网 发布:淘宝网,挂烫机加热器 编辑:程序博客网 时间:2024/05/20 04:30

我叫小马,我在坚持写一些东西,希望互相学习.我的博客是http://blog.csdn.NET/maqianli23

本博客地址:http://blog.csdn.net/maqianli23/article/details/53980798

---------------------------------------------------------------------------------------------------------------------------------------------------



今天写这个图片压缩,喜欢的就看一下。

先介绍一下图片存在的几种形式:

1.file文件 

2.流的形式

3.字符串(base64,便于加密)

4.bitmap---内存的形式


---------------------------------------------------------------------------------------------------------------------------------------------------


图片压缩:分为质量压缩,尺寸压缩,采样率压缩,微信压缩(哈夫曼编码)(前三个不是重点,重点是第四种)

一.质量压缩:设置bitmap options属性,降低图片的质量,像素不会减少

/** * 1. 质量压缩   设置bitmap options属性,降低图片的质量,像素不会减少   第一个参数为需要压缩的bitmap图片对象,第二个参数为压缩后图片保存的位置   设置options 属性0-100,来实现压缩 * @param bmp * @param file */public static void compressImageToFile(Bitmap bmp,File file) {    // 0-100 100为不压缩    int options = 20;    ByteArrayOutputStream baos = new ByteArrayOutputStream();    // 把压缩后的数据存放到baos中    bmp.compress(Bitmap.CompressFormat.JPEG, options, baos);    try {        FileOutputStream fos = new FileOutputStream(file);        fos.write(baos.toByteArray());        fos.flush();        fos.close();    } catch (Exception e) {        e.printStackTrace();    }}

二.尺寸压缩:通过缩放像素减少图片的大小。

/** * * 2. 尺寸压缩 通过缩放图片像素来减少图片占用内存大小 * @param bmp * @param file */public static void compressBitmapToFile(Bitmap bmp, File file){    // 尺寸压缩倍数,值越大,图片尺寸越小    int ratio = 4;    // 压缩Bitmap到对应尺寸    Bitmap result = Bitmap.createBitmap(bmp.getWidth() / ratio, bmp.getHeight() / ratio, Config.ARGB_8888);    Canvas canvas = new Canvas(result);    Rect rect = new Rect(0, 0, bmp.getWidth() / ratio, bmp.getHeight() / ratio);    canvas.drawBitmap(bmp, null, rect, null);    ByteArrayOutputStream baos = new ByteArrayOutputStream();    // 把压缩后的数据存放到baos中    result.compress(Bitmap.CompressFormat.JPEG, 100 ,baos);    try {        FileOutputStream fos = new FileOutputStream(file);        fos.write(baos.toByteArray());        fos.flush();        fos.close();    } catch (Exception e) {        e.printStackTrace();    }}

三.采样率压缩:通过降低图片像素来减小图片的大小

  /**        * 设置图片的采样率,降低图片像素        * @param filePath        * @param file        */       public static void compressBitmap1(InputStream filePath, File file){           // 数值越高,图片像素越低           int inSampleSize = 4;           BitmapFactory.Options options = new BitmapFactory.Options();//         options.inJustDecodeBounds = false;           options.inJustDecodeBounds = true;//为true的时候不会真正加载图片,而是得到图片的宽高信息。           //采样率           options.inSampleSize = inSampleSize;           Bitmap bitmap = BitmapFactory.decodeStream(filePath,null ,options);           ByteArrayOutputStream baos = new ByteArrayOutputStream();           // 把压缩后的数据存放到baos中           bitmap.compress(Bitmap.CompressFormat.JPEG, 100 ,baos);           try {               if(file.exists())               {                   file.delete();               }               else {                   file.createNewFile();               }               FileOutputStream fos = new FileOutputStream(file);               fos.write(baos.toByteArray());               fos.flush();               fos.close();           } catch (Exception e) {               e.printStackTrace();           }       }

四.微信压缩(华为EMUI5.0已经将定常编码改为了哈夫曼编码(猜测,没有看过源码),但是微信是这样子做的)


现在来想一下,IOS拍照1M的图片要比安卓拍照排出来的5M的图片还要清晰(同情景下)?

这就要说到安卓的图片处理引擎了。

95年 JPEG处理引擎,用于最初的在PC上面处理图片的引擎。

05年  skia开源的引擎, 开发了一套基于JPEG处理引擎的第二次开发,便于浏览器的使用。

07年, 安卓诞生,安卓上面用的什么引擎呢?答案是:skia引擎,阉割版。

谷歌拿了skia 思考了半天做了一个决定,去掉一个编码算法---哈夫曼算法。采用定长编码算法。但是解码还是保留了哈夫曼算法。这就导致了图片处理后文件变大了。

而他选择这样做的理由是什么呢?当时由于CPU和内存在手机上都非常吃紧 ,性能差,由于哈夫曼算法非常吃CPU,被迫用了其他的算法。

解释一下:每一个像素包含着ARGB四个信息,即alpha,red,green,blue

现在我们将这四个信息抽象出来,用abcde这五个字母表示一段复杂度为5的信息。在计算机中的表达方式必须按照二进制编码的形式表示。

1.如果通常情况下a,b,c,d,e用以下的方式表达

a:0001

b:0010

c:0011

d:0100

e:0101

大家可以看到,最前面的一位数字都是0,其实是被浪费掉了,

2.所以在定常编码算法下最优的表达方式为:

a:001

b:010

c:011

d:100

e:101

这样做的话就可以节省一位的损耗。(安卓图片处理引擎目前就是使用定常编码算法实现的)

以上是定常编码算法给出的解决方法

3.现在 接下来我们继续进行优化,在哈夫曼算法中我们可以给我们的信息赋予权重。(为信息编码加权)

假设a占据了80%,b占据了10%,c占据了10%,d和e都是0,

a:001(80%)

b:010(10%)

c:011(10%)

d:100

e:101

在这种栗子下,我们可以使用哈夫曼算法进行再次优化为

a:01

b:10

c:11

加权后的abcde:01    10    11 (哈夫曼编码)

定常编码下的abcde:   001  010  011 100 101

加权后的abcde的de呢 当然是没有了,权重为0嘛。

但是问题就在这里了,如何得到每一个字母出现权重呢?如果能够知道每一个权重,那么我们就能够动态的使用最优的编码了。

这里也就是为什么当初谷歌的工程师不使用哈夫曼编码的理由了。

那么如何得到呢?需要去扫描整个信息(即整张图片的信息---每一个像素包括ARGB),要大量的进行计算,非常吃CPU。(可以想象一下,07年你所使用的安卓只能手机)。。。。

一个栗子:1280*720的一张图片需要计算的次数为 720*1280*4(ARGB),这对于当时的安卓手机来说可以是一个灾难。。


以上均是第四种压缩的原理

-------------------如何实现----------=-----------


下载JPEG引擎使用的库---libjpeg库:http://www.ijg.org/


基于该引擎来做一定的开发----自己实现编码。

 NDK编写流程:
1.导入库文件libjpegbither.so
2.导入头文件
3.写mk文件
Android.mk
Applicatoin.mk
4.写代码
C++: XX.cpp
C:   XX.c



编码思维:
1.将android的bitmap解码,并转换成RGB数据
一个图片信息---像素点(argb)
alpha去掉
2.JPEG对象分配空间以及初始化
3.指定压缩数据源
4.获取文件信息
5.为压缩设置参数,比如图像大小、类型、颜色空间
  boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */
6.开始压缩
jpeg_start_compress()
7.压缩结束
jpeg_finish_compress()

目前 ,已经把项目生成了.so文件 可以直接使用,注意NativeUtil(你使用的)所在包名必须和我的项目NativeUtil所在的包名相同。

传送门:https://github.com/yuyunhai/weixinyasuo

0 0
原创粉丝点击