|
| 1 | +package com.bumptech.glide.integration.avif; |
| 2 | + |
| 3 | +import android.graphics.Bitmap; |
| 4 | +import android.util.Log; |
| 5 | +import com.bumptech.glide.load.Options; |
| 6 | +import com.bumptech.glide.load.ResourceDecoder; |
| 7 | +import com.bumptech.glide.load.engine.Resource; |
| 8 | +import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; |
| 9 | +import com.bumptech.glide.load.resource.bitmap.BitmapResource; |
| 10 | +import com.bumptech.glide.util.Preconditions; |
| 11 | +import java.nio.ByteBuffer; |
| 12 | +import javax.annotation.Nullable; |
| 13 | +import org.aomedia.avif.android.AvifDecoder; |
| 14 | +import org.aomedia.avif.android.AvifDecoder.Info; |
| 15 | + |
| 16 | +/** A Glide {@link ResourceDecoder} capable of decoding Avif images. */ |
| 17 | +public final class AvifByteBufferBitmapDecoder implements ResourceDecoder<ByteBuffer, Bitmap> { |
| 18 | + private static final String TAG = "AvifBitmapDecoder"; |
| 19 | + |
| 20 | + private final BitmapPool bitmapPool; |
| 21 | + |
| 22 | + public AvifByteBufferBitmapDecoder(BitmapPool bitmapPool) { |
| 23 | + this.bitmapPool = Preconditions.checkNotNull(bitmapPool); |
| 24 | + } |
| 25 | + |
| 26 | + private ByteBuffer maybeCopyBuffer(ByteBuffer source) { |
| 27 | + // Native calls can only access ByteBuffer if isDirect() is true. Otherwise, we would have to |
| 28 | + // make a copy into a direct ByteBuffer. |
| 29 | + if (source.isDirect()) { |
| 30 | + return source; |
| 31 | + } |
| 32 | + ByteBuffer sourceCopy = ByteBuffer.allocateDirect(source.remaining()); |
| 33 | + sourceCopy.put(source); |
| 34 | + sourceCopy.flip(); |
| 35 | + return sourceCopy; |
| 36 | + } |
| 37 | + |
| 38 | + @Override |
| 39 | + @Nullable |
| 40 | + public Resource<Bitmap> decode(ByteBuffer source, int width, int height, Options options) { |
| 41 | + ByteBuffer sourceCopy = maybeCopyBuffer(source); |
| 42 | + Info info = new Info(); |
| 43 | + if (!AvifDecoder.getInfo(sourceCopy, sourceCopy.remaining(), info)) { |
| 44 | + if (Log.isLoggable(TAG, Log.ERROR)) { |
| 45 | + Log.e(TAG, "Requested to decode byte buffer which cannot be handled by AvifDecoder"); |
| 46 | + } |
| 47 | + return null; |
| 48 | + } |
| 49 | + Bitmap bitmap = |
| 50 | + bitmapPool.get( |
| 51 | + info.width, |
| 52 | + info.height, |
| 53 | + (info.depth == 8) ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGBA_F16); |
| 54 | + if (!AvifDecoder.decode(sourceCopy, sourceCopy.remaining(), bitmap)) { |
| 55 | + if (Log.isLoggable(TAG, Log.ERROR)) { |
| 56 | + Log.e(TAG, "Failed to decode ByteBuffer as Avif."); |
| 57 | + } |
| 58 | + bitmapPool.put(bitmap); |
| 59 | + return null; |
| 60 | + } |
| 61 | + return BitmapResource.obtain(bitmap, bitmapPool); |
| 62 | + } |
| 63 | + |
| 64 | + @Override |
| 65 | + public boolean handles(ByteBuffer source, Options options) { |
| 66 | + return AvifDecoder.isAvifImage(maybeCopyBuffer(source)); |
| 67 | + } |
| 68 | +} |
0 commit comments