Understanding Image compression in Android

Whenever we make an Android application then our final goal is to put all the features in the application but at the same time, reduce the APK size also. It has two benefits, the user will tend to download your app because of the small APK size and the other benefit is that it provides a better user experience. When we are talking about reducing the APK size of an application, two different things are responsible for this. One is the code size, language, image resource, layouts, config data, etc. These things are zipped into the APK and the user downloads it and uses the APK. But on the other side, we have the Internet i.e. we download some images or data from the Internet and use it in our application. One thing that can be noticed here is the involvement of images on both sides. So, our image should be compressed to have a smaller APK size and to give a better user experience. And this is the reason why we are here to understand Image compression in Android. We will be covering the below points in this blog:

  • Why Image Compression?
  • PNG image
  • Vector image
  • JPEG image
  • WebP
  • Important tip
  • Closing notes

So, let's get started.

Why Image Compression?

Images are the best way to convey our message to our users. We can convey the information through images in a much much better way as compared to texts.

Images are Awesome.

But the problem with images is that images can be easily bloated. Images can be too big or can have too many pixels or resolutions and this, in turn, reduce your application's performance. For example, if a user is loading an image of 5MB over a 2G network, then you might end up losing one user of your application. Bigger images take longer to download and this also results in more data consumption and also more battery consumption of your users. So, it is always very important to make sure that the images used in your application are compressed to give a better experience to your users.

In Android, we generally deal with the below four image types:

  1. PNG
  2. Vector Drawable
  3. JPG
  4. WebP

Let's have a look at these image formats and how it works internally.

PNG

PNG or Portable Network Graphics is the most commonly used image file in Android these days. They provide a nice and high-resolution image format. But due to this, we need to apply some image compression techniques also. PNG compressions are lossless i.e. you can get back your original image from the compressed one. We take every row of pixels in a PNG image, one at a time, and process each row individually. We use two steps in PNG compression:

  1. Filtering: In the filtering process, the basic idea is to get the difference from the previous value. So, it will subtract the current pixel in the row with the previous pixel, or the one above it. The filtering process wants to produce the most number of zeros and duplicate values possible. Because when you are getting a zero value then it is clear that the current value and the value present in the previous pixel are same and the compression can be easy in this situation.
  2. Deflate: The output of the filtering process is put into an encoding system called deflate. There are two compression algorithms present in deflating i.e. LZ77 and Huffman encoder. LZ77 is a dictionary algorithm that finds the duplicate characters multiple times in a stream of data. The output of this LZ77 is then fed into the Huffman encoder which is almost identical to compressors like PKWARE, GZip, etc. The output of the deflate is then sent to the disk.

So, in summary, we can say this if some area in an image has similar or duplicate pixels then the filtering process will generate zeros and the LZ77 will make that spot disappear. So, the areas with similar pixel will have great compression. But the areas with dissimilar pixel pattern, the compression will be least. We can get rid of this by using images with less number of colours i.e. if an image is having lesser number of colours (maybe only black and white) then the filtering process will produce an output that can be highly compressed by the deflate.

But in Android, we have one tool called AAPT which does all the above things for us. So, why are we looking for filtering and deflating and all that stuff, if the AAPT is responsible for reducing the PNG image size for you? So, to understand the reason behind this, let's have a look at the working of AAPT. AAPT does the following three things:

  1. Analyse your PNG: The first thing that AAPT does is analyse your PNG to find whether or not you are only using Greyscale. It checks if it can convert the PNG into greyscale or not.
  2. Check for transparency channel: After analysing your PNG, AAPT checks if you are using your transparency channel or not. If you are not using any transparency channel i.e. your image is opaque then it will remove that channel and as a result of that, your image size will be reduced.
  3. Checks for 256 colours: The APPT scans your entire image and checks whether or not you are using 256 unique colours. If you are using 256 colours then the colours will be saved in a palleted format and it decreases the size.

So, if the AAPT is very good then why to use other compression techniques? Let's have one example:

In the image above, there three colours present. But the AAPT is trying to get values for the 256 unique colours. If we reduce the colours then there is no effect on the image quality but there is a drastic change in the image size. So, we have to perform PNG optimization. But don't worry, we have tools for PNG optimization. Some of the PNG optimization tools are PNGQuant, TinyPNG, PNGOut, CryoPNG, OptiPNG, PunyPNG, etc. The point to be noted here is that, if you are using any of the above tools then you must specify your app to disable the AAPT. If you are not doing this then you might end up getting a larger image size than the one that you got after applying some compression tool because the AAPT is unaware of the fact that you have done the compression already. So, to disable AAPT, you can use the below code:

aaptOptions {
    cruncherEnabled = False
}

After that, you must have to make sure that all the images that you are using are fully compressed because now there is no AAPT for image compression.

Vector Drawable

As we all know that PNG files are raster files in nature. So, if you are making an application for different device sizes then you have to use different resolution size images for different devices and this, in turn, increases your application size. So, what we are having is different copies of the same images in our application, which is not a good thing to have. Yeah, we can use split APK or upsampling or other methods to avoid this problem but in all these cases at least you have to make images for all those devices. What if one image can be used in all the devices with different resolutions? Yeah, we can do this with the help of Vector Drawables.

Vector Drawable is a concept of drawing images with code. The benefit of using this is we can use the same drawable image for different resolution devices and this, in turn, reduces the APK size because we are using only one image for all the devices. What we do here is we write the code for the image, execute that or rasterize those to a bitmap in CPU memory and then we upload that in the GPU and finally the image is drawn on the screen of the device. By doing so, you will get a much smaller image file but it takes time in the rasterization process.

To convert your PNG image into vector drawable, you can use a tool named POTrace. But this is just an automated tool. So, you will not get the desired image all the time. Also, you have to compromise with the colours present in your image. To get the desired images every time, you have to code for it.

JPG

Till now we have seen PNGs and Vector Drawables and now its time for the big images, the very big images i.e. the JPEGs. So, whenever we want to use a good quality image, we tend to use JPEGs and this is the reason why we are concerned about the compression of the JPEGs.

When we take our source RGB image, the first things that happen is we convert it to a separate colourspace. This is done because the human eyes tend to see more differences in RGBs, than in the YCbCr colourspace or the chroma luminance colourspace. The next thing that we do is we reduce the size of CB and CR channels i.e. the chroma channels because the human eye does not notice as many changes in that spectrum. After downsampling i.e. reducing the size of CB and CR, we go for blockup and apply the discrete Cosine Transform. So, what is does is it converts or represents any signals as a sum of cosine. The output of this cosine transform is run into a quantization phase which quantize the output of cosine transform to integers and after that the statistical encoding is done which may be Huffman or arithmetic or any other encoding and finally, you get the JPG file. Phew, so many steps :(

Whenever we upload a JPG file then we saw one option to select the quality of image i.e. we can select the image quality from 0% to 100% where 0 is the lowest quality image and 100 is the best quality image. But the problem is that how can you choose the percentage i.e. how will you get to know which quality image should be shown to your users? For this, you can use Butteraugli.

Butteraugli is a way to compare the psycho-visual similarity of two images.

It is just a way to take a source image and compress the image to find how the human eye sees the difference between various qualities of the image. So, if you want to compress your image and at the same time you want to know how much you can compress an image so that the human eye can't notice a change, then you can use Butteraugli for this. Want to use a high-resolution image? Cool, use Butteraugli to find the percentage up to which you can compress your image and then compress that image. That's it. At the same time, if the quality of the image is not a concern for you then you can further compress your image to get a smaller image file.

So, do we need to perform all those steps mentioned above to compress the JPG image? No. Not necessarily. There are several tools available that will do the JPG compression for you like JPEGMini, MozJPEG, cJPEG, packJPG, etc.

WebP

WebP is an image format that allows us to do lossless and lossy compression for images on the web. The lossless images of WebP are almost 26% smaller than that of PNGs. While the lossy images are 25-34% smaller than that of JPEGs file.

The lossy WebP uses predictive coding to encode an image. So, to predict the value in a pixel, WebP uses the values present in the neighbouring blocks and then encodes the difference only.

While the lossless WebP compression uses image fragments that are already seen to reconstruct new pixel. If no match is found, then it uses a local palette.

Important tip

So, we have seen all the image compression that we come across daily. When you are about to choose the type of image that you are going to use in your application then you should first go for the Vector drawable. If vector drawable is there with you, then use it. If you are not having vector drawable and you need the support of WebP then make your image as WebP. If you don't need WebP then do you need transparency? If yes, then go with PNG. If no, then find, if it is simple or complex. If it is simple then stick with PNG otherwise if it is complex then go with JPG.

Image Source: Google I/O

Closing notes

In this blog, we learned various techniques used for image compressions like PNG, JPEG, Vector Drawable and WebP. We also saw how to decide which image format should we use in our application. But remember one thing, before using any type of image compression, do research to find who are your users, what do they want? Perform good research on that because in some cases JPEGs can be better than PNGs and vice-versa.

Hope you learned something new today.

Have a look at our Android tutorials here.

Do share this blog with your fellow developers to spread the knowledge. You can read more blogs on Android on our blogging website.

Apply Now: MindOrks Android Online Course and Learn Advanced Android

Happy Learning :)

Team MindOrks!