android图片压缩总结

一、bitmap 图片格式介绍

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

  bitmap内存大小 =  图片长度 x 图片宽度 x 一个像素点占用的字节数

以下是图片的压缩格式:

其中,A代表透明度;R代表红色;G代表绿色;B代表蓝色。  

  1. ALPHA_8         表示8位Alpha位图,即A=8,一个像素点占用1个字节,它没有颜色,只有透明度  
  2. ARGB_4444    表示16位ARGB位图,即A=4,R=4,G=4,B=4,一个像素点占4+4+4+4=16位,2个字节 
  3. ARGB_8888    表示32位ARGB位图,即A=8,R=8,G=8,B=8,一个像素点占8+8+8+8=32位,4个字节 
  4. RGB_565         表示16位RGB位图,即R=5,G=6,B=5,它没有透明度,一个像素点占5+6+5=16位,2个字节

内部相关函数介绍:http://blog.csdn.net/xxxzhi/article/details/51607765

显示bitmap: http://blog.csdn.net/ymangu666/article/details/37729109

二、生成Bitmap对象:

1. 从drawable资源文件中生成Bitmap对象:可以通过Option设置生成bitmap的属性

BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
options.inScaled  = false;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.kb455,options);

注: 如果资源只放在drawable目录下,没有在hdpi等文件夹中,获取的bitmap文件会非常大,超过原始图片的大小,很可能出现OOM。

一种办法是将资源文件放在各个 dpi目录下  二、可以设置为options.inscaled = false,生成的bitmap与图片大小一致。

  还可以通过其它渠道生成bitmap如inputstream,代码见“四”中的例子。

这里需要注意的是 Option.inJustDecodeBounds 这个变量,官方的解释:

If set to true, the decoder will return null (no bitmap), but the out… fields will still be set, allowing the caller to query the bitmap without having to allocate the memory for its pixels.

当只是需要来获取图片的宽高而不创建一个 bitmap对象时需要设置为 true,这时系统不会分配 bitmap的内存。如下是官方的例子:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;

三、图片压缩(不改变图片宽高)

  下面代码通过while循环将图片压缩到topLimit(KB)之下,但是该种方法有个缺点,如果topLimit很小,但是原始的Bitmap

又很大,当options减小到负值时任然不能达到目标大小之下。(http://www.jianshu.com/p/0ab8fde08bcf)

public static byte[] compressQualityBitmap(Bitmap bitmap, int topLimit) {
        if(bitmap != null && topLimit > 0) {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int options = 100;
            bitmap.compress(CompressFormat.JPEG, options, baos);

            while(baos.toByteArray().length > topLimit * 1024) {
                baos.reset();
                options -= 5;
                bitmap.compress(CompressFormat.JPEG, options, baos);
            }

            byte[] bitmapArray = baos.toByteArray();

            try {
                baos.close();
                baos = null;
            } catch (IOException var14) {
                ;
            } finally {
                if(baos != null) {
                    try {
                        baos.close();
                        baos = null;
                    } catch (IOException var13) {
                        ;
                    }
                }

                return bitmapArray;
            }
        } else {
            return null;
        }
    }

1、下面函数是在保持像素的前提下改变图片的位深及透明度等,来达到压缩图片的目的,这也是为什么该方法叫质量压缩方法。图片的长,宽,像素都不变,bitmap所占内存大小是不会变的,但是压缩到byte数组baos的长度会逐渐的变小。

     bitmap.compress(CompressFormat.JPEG, options, baos);

2、需要如果是bit.compress(CompressFormat.PNG, quality, baos);这样的png格式,quality就没有作用了,bytes.length不会变化,因为png图片是无损的,不能进行压缩。

3、该方法压缩并不能无限制的压缩,当压缩到一定程度后,baos的长度变不再变化。

改变图片的格式: 

  第一章中列出了四种格式的Config,可以将ARGB_8888格式转换为 RGB_565存储空间可以减少为原来的一半,而不改变图片的宽高。

四、图片缩放(改变图片宽高)

 1、bitmap采样率压缩:在BitmapFactory.decodexxxx() 设置 options.inSampleSize 大小来缩放图片例如: 为2时,缩放为原来宽高的一半。

public static Bitmap compressBoundsBitmap(Context context, Uri uri, int targetWidth, int targetHeight) {
        InputStream input = null;
        Bitmap bitmap = null;

        try {
            input = context.getContentResolver().openInputStream(uri);
            Options options = new Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(input, (Rect)null, options);
            input.close();
            int originalWidth = options.outWidth;
            int originalHeight = options.outHeight;
            if(originalWidth != -1 && originalHeight != -1) {
                boolean be1 = true;
                int widthBe = 1;
                if(originalWidth > targetWidth) {
                    widthBe = originalWidth / targetWidth;
                }

                int heightBe = 1;
                if(originalHeight > targetHeight) {
                    heightBe = originalHeight / targetHeight;
                }

                int be2 = widthBe > heightBe?heightBe:widthBe;
                if(be2 <= 0) {
                    be2 = 1;
                }

                options.inJustDecodeBounds = false;
                options.inSampleSize = be2;
                input = context.getContentResolver().openInputStream(uri);
                bitmap = BitmapFactory.decodeStream(input, (Rect)null, options);
                input.close();
                input = null;
            } else {
                Object be = null;
            }
        } catch (FileNotFoundException var23) {
            ;
        } catch (IOException var24) {
            ;
        } finally {
            if(input != null) {
                try {
                    input.close();
                } catch (IOException var22) {
                    ;
                }
            }

            return bitmap;
        }
    }

优点:效率较高,解析速度快

缺点:采样率inSampleSize的取值只能是2的次方数(例如:inSampleSize=15,实际取值为8;inSampleSize=17,实际取值为16;实际取值会往2的次方结算),因此该方法不能精确的指定图片的大小

2.通过Matrix缩放图片(不推荐)

/**
 * 图片的缩放方法
 *
 * @param bitmap  :源图片资源
 * @param maxSize :图片允许最大空间  单位:KB
 * @return
 */
public static Bitmap getZoomImage(Bitmap bitmap, double maxSize) {
    if (null == bitmap) {
        return null;
    }
    if (bitmap.isRecycled()) {
        return null;
    }

    // 单位:从 Byte 换算成 KB
    double currentSize = bitmapToByteArray(bitmap, false).length / 1024;
    // 判断bitmap占用空间是否大于允许最大空间,如果大于则压缩,小于则不压缩
    while (currentSize > maxSize) {
        // 计算bitmap的大小是maxSize的多少倍
        double multiple = currentSize / maxSize;
        // 开始压缩:将宽带和高度压缩掉对应的平方根倍
        // 1.保持新的宽度和高度,与bitmap原来的宽高比率一致
        // 2.压缩后达到了最大大小对应的新bitmap,显示效果最好
        bitmap = getZoomImage(bitmap, bitmap.getWidth() / Math.sqrt(multiple), bitmap.getHeight() / Math.sqrt(multiple));
        currentSize = bitmapToByteArray(bitmap, false).length / 1024;
    }
    return bitmap;
}

/**
 * 图片的缩放方法
 *
 * @param orgBitmap :源图片资源
 * @param newWidth  :缩放后宽度
 * @param newHeight :缩放后高度
 * @return
 */
public static Bitmap getZoomImage(Bitmap orgBitmap, double newWidth, double newHeight) {
    if (null == orgBitmap) {
        return null;
    }
    if (orgBitmap.isRecycled()) {
        return null;
    }
    if (newWidth <= 0 || newHeight <= 0) {
        return null;
    }

    // 获取图片的宽和高
    float width = orgBitmap.getWidth();
    float height = orgBitmap.getHeight();
    // 创建操作图片的matrix对象
    Matrix matrix = new Matrix();
    // 计算宽高缩放率
    float scaleWidth = ((float) newWidth) / width;
    float scaleHeight = ((float) newHeight) / height;
    // 缩放图片动作
    matrix.postScale(scaleWidth, scaleHeight);
    Bitmap bitmap = Bitmap.createBitmap(orgBitmap, 0, 0, (int) width, (int) height, matrix, true);
    return bitmap;
}

/**
 * bitmap转换成byte数组
 *
 * @param bitmap
 * @param needRecycle
 * @return
 */
public static byte[] bitmapToByteArray(Bitmap bitmap, boolean needRecycle) {
    if (null == bitmap) {
        return null;
    }
    if (bitmap.isRecycled()) {
        return null;
    }

    ByteArrayOutputStream output = new ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.PNG, 100, output);
    if (needRecycle) {
        bitmap.recycle();
    }

    byte[] result = output.toByteArray();
    try {
        output.close();
    } catch (Exception e) {
        Log.e(TAG, e.toString());
    }
    return result;
}
View Code

优点:可以精确地指定图片的缩放大小

缺点:是在原bitmap的基础之上生成的,占内存,效率低.

3/ThumbnailUtils 类进行

 将bitmap转换为byte方法:

public static byte[] BitmapToByte(Bitmap bitmap) {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    bitmap.compress(CompressFormat.PNG, 80, baos);//其中80参数表示要压缩的比例
    return baos.toByteArray();
}

 参考:http://blog.csdn.net/harryweasley/article/details/51955467

 

原文地址:https://www.cnblogs.com/NeilZhang/p/7763206.html