package cc.shinichi.library.view.subsampling.decoder; import android.content.ContentResolver; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.AssetManager; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.BitmapRegionDecoder; import android.graphics.Point; import android.graphics.Rect; import android.net.Uri; import android.text.TextUtils; import androidx.annotation.Keep; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import java.io.InputStream; import java.util.List; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import cc.shinichi.library.view.subsampling.SubsamplingScaleImageView; /** * Default implementation of {@link cc.shinichi.library.view.subsampling.decoder.ImageRegionDecoder} * using Android's {@link BitmapRegionDecoder}, based on the Skia library. This * works well in most circumstances and has reasonable performance due to the cached decoder instance, * however it has some problems with grayscale, indexed and CMYK images. *
 * A {@link ReadWriteLock} is used to delegate responsibility for multi threading behaviour to the
 * {@link BitmapRegionDecoder} instance on SDK >= 21, whilst allowing this class to block until no
 * tiles are being loaded before recycling the decoder. In practice, {@link BitmapRegionDecoder} is
 * synchronized internally so this has no real impact on performance.
 */
public class SkiaImageRegionDecoder implements ImageRegionDecoder {
    private static final String FILE_PREFIX = "file://";
    private static final String ASSET_PREFIX = FILE_PREFIX + "/android_asset/";
    private static final String RESOURCE_PREFIX = ContentResolver.SCHEME_ANDROID_RESOURCE + "://";
    private final ReadWriteLock decoderLock = new ReentrantReadWriteLock(true);
    private final Bitmap.Config bitmapConfig;
    private BitmapRegionDecoder decoder;
    @Keep
    @SuppressWarnings("unused")
    public SkiaImageRegionDecoder() {
        this(null);
    }
    @SuppressWarnings({"WeakerAccess", "SameParameterValue"})
    public SkiaImageRegionDecoder(@Nullable Bitmap.Config bitmapConfig) {
        Bitmap.Config globalBitmapConfig = SubsamplingScaleImageView.getPreferredBitmapConfig();
        if (bitmapConfig != null) {
            this.bitmapConfig = bitmapConfig;
        } else if (globalBitmapConfig != null) {
            this.bitmapConfig = globalBitmapConfig;
        } else {
            this.bitmapConfig = Bitmap.Config.RGB_565;
        }
    }
    @Override
    @NonNull
    public Point init(Context context, @NonNull Uri uri) throws Exception {
        String uriString = uri.toString();
        if (uriString.startsWith(RESOURCE_PREFIX)) {
            Resources res;
            String packageName = uri.getAuthority();
            if (context.getPackageName().equals(packageName)) {
                res = context.getResources();
            } else {
                PackageManager pm = context.getPackageManager();
                res = pm.getResourcesForApplication(packageName);
            }
            int id = 0;
            List