Four image compression methods based on Android bitmap

Time:2021-8-30
catalogue
  • Introduction to knowledge points
  • text
    • 1. Mass compression
    • 2. Sample rate compression
    • 3. Scaling compression
    • 4、RGB_ 565 compression is achieved by changing the picture format
    • summary

Introduction to knowledge points

Pictures in Android mainly exist in the form of bitmap, so compressing pictures is mainly to reduce the size of bitmap. The size of bitmap can be calculated by the following formula: size = width * height * bytes occupied by a single pixel. Therefore, the compressed picture can be realized by changing the three variables in the formula.

There are many kinds of space occupied by a single pixel in Android, as shown below

format Space occupied explain
Bitmap.Config.ALPHA_8 1B This format means that the picture has only transparency and no color, and one pixel occupies 8 bits
Bitmap.Config.ARGB_4444 2B This format indicates that the picture transparent channel A and colors R, G and B occupy 4 bits respectively, a total of 16 bits
Bitmap.Config.ARGB_8888 4B This format indicates that the picture transparent channel A and colors R, G and B occupy 8 bits respectively, a total of 32 bits
Bitmap.Config.RGB_565 2B This format means that the picture has no transparent channel, and the colors R, G and B occupy 5, 6 and 6 bits respectively, a total of 16 bits

Loading pictures in Android uses ARGB by default_ 8888 format, so the default space occupied by loading a 3000 * 4000 image is about 45Mb, which is still a large value

Test code

fun showBitmapInfo(bitmap: Bitmap){
        Log. D ("tag", "compressed image size: ${bitmap. ByteCount / 1024 / 1024} MB, width: ${bitmap. Width}, height: ${bitmap. Height}")
}

result

text

Next, four compression methods are introduced

1. Mass compression

Quality compression is mainly realized through bitmap. Compress(). The method is introduced

/**
*
*@ param format format format of compressed image
*@ param quality prompt compressor, 0-100. This value is interpreted differently according to bitmap.compressformat.
*@ param stream – output stream that writes compressed data.
*@ return: true if the specified stream is successfully compressed
*/
public boolean compress(CompressFormat format, int quality, OutputStream stream) {
}

Compressformat represents the image compression format. There are five formats in the Android source code

Format name explain
CompressFormat.JPEG Compressed to JPEG format. Quality 0 means compressed to the minimum size. 100 indicates compression for maximum visual quality.
CompressFormat.PNG Compressed to PNG format. PNG is lossless, so quality is ignored.
CompressFormat.WEBP Compressed to webp format. Quality 0 means compressed to the minimum size. 100 indicates compression for maximum visual quality. From build.version_ Codes. Q, a value of 100 causes the file to adopt lossless webp format. Otherwise, the file will be in lossy webp format
CompressFormat.WEBP_LOSSY Compressed to webp lossy format. Quality 0 means compressed to the minimum size. 100 indicates compression for maximum visual quality.
CompressFormat.WEBP_LOSSLESS Compressed to webp lossless format. Quality is how much effort is put into compression. A value of 0 indicates fast compression, resulting in a relatively large file size. 100 means it takes more time to compress, making the file smaller.

Test code

/**
 *Compressed picture quality
*/
fun getCompressBitmap(bitmap: Bitmap,quality:Int): Bitmap {
    val baos = ByteArrayOutputStream()
    bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos)
    val byte = baos.toByteArray()
    val ins = ByteArrayInputStream(byte)
    val bm = BitmapFactory.decodeStream(ins)
    ins.close()
    baos.close()
    return bm
}

effect

According to the above log, you will see that quality compression does not change the size of the picture in memory, because quality compression can neither change the resolution of the picture nor the size of a single pixel of the picture.

Then you may have some questions: since you can’t change the size, why does it take so much effort to transform and distort the picture?

A: the explanation of the compress method in the source code is to write the compressed version of the bitmap to the specified output stream. Therefore, it should have an impact on the number of bytes in the output stream

verification


val baos = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos)
val byte = baos.toByteArray()
Log.d("Tag","quality=$quality,byte-size=${byte.size}")

The result really has an impact on the number of bytes of the output stream

2. Sample rate compression

Bitmapfactory.options has an attribute insamplesize, which is used for sample rate compression in the system

/**
*If it is set to a value greater than 1, the decoder is requested to resample the original image and return a smaller image to save memory.
*The sample size is the number of pixels in any dimension corresponding to a single pixel in the decoded bitmap. For example, insamplesize = = 4
*The returned image is 1 / 4 of the original width / height and 1 / 16 of the number of pixels. Any value less than or equal to 1 is the same as 1.
*Note: the decoder uses the final value based on the power of 2, and any other value will be rounded to the nearest power of 2.
**/
 public int inSampleSize;

Direct code

/**
     *Calculates the zoom ratio based on the set width and height
     */
    fun calculateInSampleSize(options: BitmapFactory.Options, reqWidth: Int, reqHeight: Int): Int {
        val height = options.outHeight
        val width = options.outWidth
        var inSampleSize = 1
        if (height > reqHeight || width > reqWidth) {
            val heightRatio = round(height.toFloat() / reqHeight.toFloat()).toInt()
            val widthRatio = round(width.toFloat() / reqWidth.toFloat()).toInt()
            inSampleSize = if (heightRatio < widthRatio) heightRatio else widthRatio
        }
        return inSampleSize
    }

    /**
     *Get the scaled picture
     */
    fun getSmallBitmap(filePath: String,reqWidth: Int,reqHeight: Int): Bitmap {
        val options = BitmapFactory.Options()
        Options.injustdecodebounds = true // do not load bitmap into memory, only get its basic information
        BitmapFactory.decodeFile(filePath, options)
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight)
        options.inJustDecodeBounds = false
        return BitmapFactory.decodeFile(filePath, options)
    }

result

The sampling rate compression method is still used a lot, because the size of the image we get may be very large, but the image we display on the mobile phone may not need to be so large, so we will scale the image to the size we need.

3. Scaling compression

This method mainly relies on matrix transformation to process images. There are many APIs for image transformation in the matrix. Here, only its zoom function is used, and other functions can be understood by yourself

code

/**
     *Scaling by matrix
     */
    fun matrixBitmap(bitmap: Bitmap,scale:Float):Bitmap{
        val matrix = Matrix()
        matrix.setScale(scale,scale)
        var bm = Bitmap.createBitmap(bitmap,0,0,bitmap.width,bitmap.height,matrix,true)
        return bm
    }

When the zoom ratio is set to 0.5, the whole picture will be scaled to the original 1 / 4

4、RGB_ 565 compression is achieved by changing the picture format

ARGB is used by default_ 8888 format, so we can just change the options value


fun rgb565Bitmap(filePath: String):Bitmap{
        val options = BitmapFactory.Options()
        options.inPreferredConfig = Bitmap.Config.RGB_565
        var bitmap = BitmapFactory.decodeFile(filePath,options)
        return bitmap
}

As a result, the picture becomes half of the original picture

summary

For image compression, you can first change the image format to RGB_ 565. In this way, the picture is reduced by half, and then the resolution of the picture can be changed to the size of our display by using sampling rate compression or scaling compression. If the picture is to be uploaded to the server, the quality compression method can be used, but this method does not support png format pictures.

The above is the details of the four image compression methods based on Android bitmap. For more information about Android bitmap image compression, please pay attention to other relevant articles of developeppaer!