Android Q / Bitmap

HEIF Images

One of the new features in Android Q is support for High Efficiency Image Format (HEIF) images, but why is this important? In this post we’ll take a look at what HEIF actually is, and understand a little about the benefits that it might offer.

HEIF was developed by the Moving Picture Experts Group (MPEG) and is a container format with compression that is claimed to be more efficient than JPEG while offering better image quality. The claim is that HEIF images will typically be half the size of the JPEG equivalent, while being of superior quality.

To actually use HEIF images in Android Q requires no effort whatsoever as you can include HEIF images in your drawables resources in exactly the same way as you can with JPEG images. Moreover BitmapFactory will inflate HEIF images in exactly the same way as it does JPEG images. But there is currently no backwards compatibility possibly because of hardware and licensing requirements. There was limited support included in Pie in ImageDecoder (see this article for details of how to use ImageDecoder), but this was device dependent which somewhat suggests that there are hardware requirements.

Although there is currently no backwards compatibility for reading HEIF images, there is a support library for writing them. It can write Bitmap, Surface, or a YUV byte buffer. We can read a Bitmap from an asset file and write it to the local cache directory as a HEIF using HeifWriter:

suspend fun convertToHeif(assetName: String): Long {
    return withContext(Dispatchers.IO) {
        val bitmap = readBitmapAsset(assetName)
        val file = File(context.cacheDir, "beach_huts.heif")
        HeifWriter.Builder(
            file.canonicalPath,
            bitmap.width,
            bitmap.height,
            HeifWriter.INPUT_MODE_BITMAP
        )
            .setQuality(quality)
            .build().apply {
                start()
                addBitmap(bitmap)
                stop(0)
                close()
            }
        file.length()
    }
}

private fun readBitmapAsset(assetName: String): Bitmap {
    return context.assets.open(assetName).use { inputStream ->
        BitmapFactory.decodeStream(inputStream)
    }
}

While it may feel like we should not be using HEIF images until we reach minSdkVersion = 29 there is actually a way that we can benefit before then. If you are using Android App Bundles, and are using dynamic delivery from the Play Store then including HEIF images in your res/drawables-*-v29 folders will allow dynamic delivery to bundle HEIF images in the APK delivered to Q and later devices, so there will be tangible benefits from beginning to include then now. These benefits will only increase over time as the number of HEIF capable devices increases.

To get an idea of how HEIF compares with JPEG, the sample app for this post reads an image and saves it as both a JPEG and HEIF image to ensure that we’re comparing like for like as both images are generated by the Android framework image codecs. Both JPEG and HEIF use a lossy compression algorithm which use a quality value to determine how lossy the compression actually is. A quality of 100 for either is actually lossless compression.

The app has a SeekBar which allows different quality values to be applied to the image conversion. At lossless compression (quality = 100) the HEIF image (the top one) is 3.72 MB compared to the JPEG one (the bottom one) which is 5.85 MB. This is fairly close to the half size claim, and I cannot see any difference in image quality – but then there shouldn’t be if the compression is truly lossless:

Where things can get confusing is in the middle quality values. The JPEG image sizes drop quite sharply, whereas the HEIF sizes reduce rather more gradually. Please bear in mind that this is not a true like-for-like comparison because the quality value means different things for different compression algorithms.

At quality = 25 I can clearly see some artifacts appearing in the JPEG image, whereas the HEIF image still looks pretty good – as good as, if not better than the JPEG image at quality = 50.

It’s slightly more interesting if we compare the JPEG for quality = 25 in the image above, with the HEIF with quality = 15 in the image below. The file sizes are comparable, with JPEG quality = 25 being 814 kB, and HEIF quality = 15 being 891 kB.

However the quality of the HEIF is much better. Although some artifacts are beginning to appear they are nowhere near as pronounced as those on the JPEG image at quality = 25. So the quality for HEIF can be set much lower than for JPEG to achieve better quality at smaller image sizes.

Just to take things to the extreme, right at the bottom end of the quality scale we see some real differences:

The HEIF image is one third the size of the JPEG one, but the quality is much better. The JPEG image is both posterized and blocky, whereas the HEIF is just blocky. While neither is great and I really wouldn’t want to actually use either of them, the HEIF is significantly better quality than the JPEG while being a third of its’ size.

As I mentioned previously, we cannot compare the quality values directly, but instead we should look at the image quality for any given quality value. For lossless compression HEIF wins hands down, but we can use much lower quality values with HEIF still achieve high levels of compression while still maintaining good image quality.

It’s worth pointing out that different images will compress differently, so the results of what I’ve done here are far from conclusive evidence. That said, there is a clear size / quality benefit from using HEIF in this case. And I fully expect that general trend to extend to other images as well, and my experiences of HEIF thus far tend to support this view.

The source code for this article is available here.

© 2019, Mark Allison. All rights reserved.

Copyright © 2019 Styling Android. All Rights Reserved.
Information about how to reuse or republish this work may be available at http://blog.stylingandroid.com/license-information.

1 Comment

  1. What do you think about the .webp format? It’s backwards compatible and it weights even less than HEIF images?

    PD: Good article, thanks!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.