Android BitMap图片压缩

本文介绍了Android中Bitmap图片压缩的五种方法:质量压缩、采样率压缩、缩放法压缩、RGB_565格式压缩和使用createScaleBitmap压缩。通过调整位深、采样率、像素格式和期望尺寸来优化内存占用。同时,文章强调这些方法主要针对内存优化,压缩后的图片在SD卡上的存储大小可能不同。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

         最近在网上看了一些关于图片压缩的博客,自己也动手实验了一遍,也算事对图片压缩有了一个了解,打算写个博客记录一下。文末附上参考链接。

         Android中涉及到图片的话一般都会用到BitMap类和BitmapFactory类。而本文讲述的图片压缩也都是通过这两个类来实现的。Android中,图片占用内存大小计算公式:图片宽度 * 图片高度 * 图片每一个像素占用的字节数。所以图片占用内存的大小(或者说压缩),就是通过改变这三个值来改变的。

         1、质量压缩

              这种方法,它是通过改变图片的位深和透明度来实现图片压缩的。它不会改变图片的大小,也不会改变图片占用的内存空间。它改变的是图片对应的BitMap对象的length属性值。下面是实现代码:

    private Bitmap compressQuality(Bitmap bitmap){
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG,100,bos);
        byte bytes[] = bos.toByteArray();
        Log.d(TAG, "compressQuality: length = "+bytes.length);

        return BitmapFactory.decodeByteArray(bytes,0,bytes.length);
    }

        上述代码重点是compress方法的使用,下面是它的API的形式。

//按指定的图片格式以及画质,将图片转换为输出流。 
public boolean compress(CompressFormat format, int quality, OutputStream stream)

        这个方法接收一个图片格式参数(format),画质参数(quality)还有一个输出流(stream)。图片格式参数有JPEG、PNG和WEBP,画质参数是[0,100]区间。使用这个方法压缩图片的时候,我们主要是想把图片对应的BitMap对象的length属性变小,以应对一些对图片大小有限制的情况。而这里就需要注意,当图片格式参数为Bitmap.CompressFormat.PNG的时候,是无法改变这个length属性值的,因为PNG格式是无损的。画质参数为100的时候,length属性值也不变,表示不压缩。

         对于上面代码,还可以学习到的知识点是:BitMap转换成字节数组(使用ByteArrayOutputStream类)及字节数组转换成BitMap(使用decodeByteArray方法)

       2、采样率压缩

           这种方法是通过改变BitmapFactory.Options的inSampleSize属性值来改变图片的大小的。通过它的代码注释可以知道,它是用来记录图片压缩倍数的,如果它的值是4,那么它的宽高最后都变成原来的1/4,根据前面图片占用内存大小公式,最终它占用内存大小就变成原来的1/16。这里我设置它的值为2,则最后占用内存大小为原来的1/4。

    private Bitmap compressSampling(){
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = 2;
        return BitmapFactory.decodeResource(getResources(),R.mipmap.fengjing,options);
    }

/**
         * If set to a value > 1, requests the decoder to subsample the original
         * image, returning a smaller image to save memory. The sample size is
         * the number of pixels in either dimension that correspond to a single
         * pixel in the decoded bitmap. For example, inSampleSize == 4 returns
         * an image that is 1/4 the width/height of the original, and 1/16 the
         * number of pixels. Any value <= 1 is treated the same as 1. Note: the
         * decoder uses a final value based on powers of 2, any other value will
         * be rounded down to the nearest power of 2.
         */
        public int inSampleSize;

    3、缩放法压缩

        这种方法通过给给定一个矩阵来对图片进行压缩,通过查看createBitMap的源码发现,最终也是改变图片的宽高实现的。

    private Bitmap compressMatrix(Bitmap bitmap){
        Matrix matrix = new Matrix();
        matrix.setScale(0.5f,0.5f);
        return Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),matrix,true);
    }

  
  public static Bitmap createBitmap(@NonNull Bitmap source, int x, int y, int width, int height,
            @Nullable Matrix m, boolean filter) {

         //...

        if (m == null || m.isIdentity()) {
            bitmap = createBitmap(neww, newh, newConfig, source.hasAlpha());
            paint = null;   // not needed
        } else {
            final boolean transformed = !m.rectStaysRect();

            m.mapRect(deviceR, dstR);

            neww = Math.round(deviceR.width());
            newh = Math.round(deviceR.height());

            //...
            bitmap = createBitmap(neww, newh, transformedConfig, transformed || source.hasAlpha());

            //...
        }
         
        return bitmap;
    }

     4、RGB_565格式压缩

           前面说到,图片占用内存大小公式是:图片宽度 * 图片高度 * 图片每一个像素占用的字节数。而上面的两种方法都是通过改变图片的宽高来实现压缩的,接着讲解的这种方法就是通过改变图片每一个像素占用的字节数来改变图片占用内存空间。

          先来了解一下,图片常用的压缩格式:

ALPHA_8一个像素点占用1个字节,它没有颜色,只有透明度
ARGB_4444一个像素点占用2个字节
ARGB_8888一个像素点占用4个字节
RGB_565一个像素点占用2个字节,它没有透明度

代码如下:

    private Bitmap compressRGB565(){
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inPreferredConfig = Bitmap.Config.ALPHA_8;
        Log.d(TAG, "compressRGB565: "+options.inSampleSize);
        Log.d(TAG, "compressRGB565: "+options.inPreferredConfig);
        Log.d(TAG, "compressRGB565: "+options.inDensity);
        Log.d(TAG, "compressRGB565: "+options.outWidth);
        Log.d(TAG, "compressRGB565: "+options.outHeight);
        Bitmap bitmap =  BitmapFactory.decodeResource(getResources(),R.mipmap.fengjing,options);
        Log.d(TAG, "compressRGB565: -----------------");
        Log.d(TAG, "compressRGB565: "+options.inSampleSize);
        Log.d(TAG, "compressRGB565: "+options.inPreferredConfig);
        Log.d(TAG, "compressRGB565: "+options.inDensity);
        Log.d(TAG, "compressRGB565: "+options.outWidth);
        Log.d(TAG, "compressRGB565: "+options.outHeight);
        return bitmap;
    }

        实现这种方式的方法是通过更改BitmapFactory.Options的inPreferredConfig值。默认情况下,Android使用ARGB_8888格式。实验中,除了ARGB_4444格式,看到的现象是一个黑色的图片区域,没有显示外,其他格式图片正常显示,内存大小以ARGB_8888格式为准的话,其他格式都缩小相应倍数。

        注意:由于ARGB_4444的画质惨不忍睹,一般假如对图片没有透明度要求的话,可以改成RGB_565,相比ARGB_8888将节省一半的内存开销。

       上面的代码我加了一些日志打印,主要是为了验证,执行完BitmapFactory.decodeResource方法之后,会对options的一些属性进行赋值,所以在某些情况下,会使用这种方式来获取图片的options信息。

       5、使用createScaleBitMap压缩

    private Bitmap compressScaleBitMap(Bitmap bitmap){

        int w = bitmap.getWidth();
        int h = bitmap.getHeight();

        return Bitmap.createScaledBitmap(bitmap, (int) (w*0.8), (int) (h*0.7),true);
    }

             这种方法通过给定期望的图片宽高来进行图片的压缩。注意图片大小改动太大会导致图片的画质变得很差。

 

      总结

           第一种方法,质量压缩。不改变图片的大小,不改变内存占用空间。但会改变图片对于的Bitmap对象的字节length值。

           第二种方法,采样率压缩。通过改变图片的宽高来改变图片大小及占用的内存空间。使用BitmapFactory类来实现。

           第三种方法,缩放法压缩。通过给定一个具体的矩阵来改变图片大小及占用的内存空间。使用BitMap类实现。

           第四种方法,RGB_565格式压缩。通过改变图片每一个像素占用的字节数来改变图片大小及占用内存空间。

           第五种方法,createScaleBitMap压缩。通过给定期望的图片宽高来改变图片的大小及占用内存空间。

          以上五种方法只是针对Android运行加载的Bitmap占用内存来说,压缩后的Bitmap存储到SD卡中,占用的内存空间并不一样。App开发过程中,如果需要对内存做优化,可以从这方面入手。

 

参考链接:

               bitmap的六种压缩方式,Android图片压缩

               Android Bitmap的常用压缩方式

              Android图片缓存之Bitmap详解

            

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值