preface

Images are an important part of every mobile application. However, processing them in Android is not an easy task. Images can come from a variety of sources, such as Assets, files, and the Web, and come in different formats, such as JPG, PNG, and so it’s no wonder that most developers are using Glide, Picasso, or other third-party libraries to simplify the display of images. And they can effectively reduce out of memory exceptions,

When it comes to parsing images, we often use BitmapFactory, but when we use Android P, we get a new thing called ImageDecoder, which can help us convert PNG, JPEG, etc. images into Drawables or Bitmaps, and a powerful class. AnimatedImageDrawable can process GIFs.

From this chapter, we can learn the following:

  • Load static images using ImageDecoder
  • Displays rounded corners
  • Load GIF and WEBP dynamic images

The old API

Before Android P, we needed to use static methods in the Drawable or BitmapFactory classes to load the Drawable and Bitmap, respectively.

// Load from the file
Drawable.createFromPath(pathName)
// Load from the asset
Drawable.createFromStream(context.assets.open(assetFileName), "")
// Load from the file
BitmapFactory.decodeFile(pathName)
// Load from the asset
BitmapFactory.decodeStream(context.assets.open(assetFileName))
// Load from a byte array
BitmapFactory.decodeByteArray(data, offset, length, opts)
Copy the code

It’s a little confusing, but it’s easy to show.

/ / show the Drawable
imageView.setImageDrawable(drawable)
/ / display bitmap
imageView.setImageBitmap(bitmap)
Copy the code

ImageDecoder

1. Load the image source

ImageDecoder abstracts the Source of an image into a uniform Source. To create a Source, use its static method createSource. The Source can be created on any thread, but it is recommended to decode it in a background thread.

For example, if we want to create an image source in the Drawable folder, we can use the following method.

 var source = ImageDecoder.createSource(resources, R.drawable.ic_launcher_background)
Copy the code

Create the source under Assets.

var source = ImageDecoder.createSource(assets, "")
Copy the code

2. Draw the source

With the source, we can parse the Drawable, Bitmap and draw it on the ImageView.

var decodeDrawable = ImageDecoder.decodeDrawable(source)
var decodeBitmap = ImageDecoder.decodeBitmap(source)

imageview.setImageBitmap(decodeBitmap);
imageview.setImageDrawable(decodeDrawable);
Copy the code

3. OnHeaderDecodedListener Changes the decoder default Settings

OnHeaderDecodedListener is an interface with only one method, onHeaderDecoded, and its three parameters are as follows:

  1. Decoder ImageDecoder: The object that performs decoding, used to change its default Settings.

  2. Info Imagedecoder. ImageInfo: Information about the encoded image.

  3. Source imagedecoder. source: Create object decoder.

Let’s do some examples

Get information about the image

var source = ImageDecoder.createSource(resources, R.drawable.abc_123)
var decodeDrawable =
    ImageDecoder.decodeDrawable(source, object : ImageDecoder.OnHeaderDecodedListener {
        override fun onHeaderDecoded( decoder: ImageDecoder, info: ImageDecoder.ImageInfo, source: ImageDecoder.Source ) {
            var size = info.size
            Log.i("TAG"."onHeaderDecoded: " + High "width =" + size.width + "" + size.height)
            Log.i("TAG"."onHeaderDecoded: " + "mimeType=" + info.mimeType)
            Log.i("TAG"."onHeaderDecoded: " + "Animate or not =" + info.isAnimated)
        }
    })
imageview.setImageDrawable(decodeDrawable);
Copy the code

Resize the image

 val source = ImageDecoder.createSource(resources, R.drawable.abc_123)
 val drawable = ImageDecoder.decodeDrawable(source) { decoder, info, source ->
     decoder.setTargetSize(100.100)
 }
 imageview.setImageDrawable(drawable)
Copy the code

The rounded picture

val source = ImageDecoder.createSource(resources, R.drawable.abc_123)
val drawable = ImageDecoder.decodeDrawable(source) { decoder, info, source ->
    val path = Path().apply {
        fillType = Path.FillType.INVERSE_EVEN_ODD
    }
    val paint = Paint().apply {
        isAntiAlias = true
        color = Color.TRANSPARENT
        xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC)
    }
    decoder.setPostProcessor { canvas ->
        val width = canvas.width.toFloat()
        val height = canvas.height.toFloat()
        val direction = Path.Direction.CW
        path.addRoundRect(0f.0f, width, height, 100f.100f, direction)
        canvas.drawPath(path, paint)
        PixelFormat.TRANSLUCENT
    }
}
imageview.setImageDrawable(drawable)
Copy the code

4. GIF and WEBP

Before Android P, loading an animation using the bitmapFactory.decode () or drawable.create () methods only resulted in the creation of a static image in the first frame of the animation, and the Glide library or Movie class was required to be able to display the GIF format.

In addition, WebP is an image file format provided by Google, which can provide JPG, PNG, but can provide better compression than JPG or PNG, can also be used to store animation.

But now, you can use the new AnimatedImageDrawable class, which can display animated GIFs in just two lines.

val source = ImageDecoder.createSource(resources,R.drawable.dog)
val drawable = ImageDecoder.decodeDrawable(source)
imageview.setImageDrawable(drawable)
if (drawable is AnimatedImageDrawable) {
    drawable.start()
}
Copy the code

conclusion

The advantages of ImageDecoder and AnimatedImageDrawable are obvious. They unify the API and make image conversion easier. Sadly, ImageDecoder and AnimatedImageDrawable are only available on Android P and higher, and no one is likely to use them yet, but this is a development.