Home | History | Annotate | Download | only in decoder
      1 package com.davemorrissey.labs.subscaleview.decoder;
      2 
      3 import android.content.ContentResolver;
      4 import android.content.Context;
      5 import android.content.pm.PackageManager;
      6 import android.content.res.Resources;
      7 import android.graphics.Bitmap;
      8 import android.graphics.BitmapFactory;
      9 import android.net.Uri;
     10 import android.support.annotation.Keep;
     11 import android.text.TextUtils;
     12 
     13 import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView;
     14 
     15 import java.io.InputStream;
     16 import java.util.List;
     17 
     18 /**
     19  * Default implementation of {@link com.davemorrissey.labs.subscaleview.decoder.ImageDecoder}
     20  * using Android's {@link android.graphics.BitmapFactory}, based on the Skia library. This
     21  * works well in most circumstances and has reasonable performance, however it has some problems
     22  * with grayscale, indexed and CMYK images.
     23  */
     24 public class SkiaImageDecoder implements ImageDecoder {
     25 
     26     private static final String FILE_PREFIX = "file://";
     27     private static final String ASSET_PREFIX = FILE_PREFIX + "/android_asset/";
     28     private static final String RESOURCE_PREFIX = ContentResolver.SCHEME_ANDROID_RESOURCE + "://";
     29 
     30     private final Bitmap.Config bitmapConfig;
     31 
     32     @Keep
     33     @SuppressWarnings("unused")
     34     public SkiaImageDecoder() {
     35         this(null);
     36     }
     37 
     38     @SuppressWarnings({"WeakerAccess", "SameParameterValue"})
     39     public SkiaImageDecoder(Bitmap.Config bitmapConfig) {
     40         Bitmap.Config globalBitmapConfig = SubsamplingScaleImageView.getPreferredBitmapConfig();
     41         if (bitmapConfig != null) {
     42             this.bitmapConfig = bitmapConfig;
     43         } else if (globalBitmapConfig != null) {
     44             this.bitmapConfig = globalBitmapConfig;
     45         } else {
     46             this.bitmapConfig = Bitmap.Config.RGB_565;
     47         }
     48     }
     49 
     50     @Override
     51     public Bitmap decode(Context context, Uri uri) throws Exception {
     52         String uriString = uri.toString();
     53         BitmapFactory.Options options = new BitmapFactory.Options();
     54         Bitmap bitmap;
     55         options.inPreferredConfig = bitmapConfig;
     56         if (uriString.startsWith(RESOURCE_PREFIX)) {
     57             Resources res;
     58             String packageName = uri.getAuthority();
     59             if (context.getPackageName().equals(packageName)) {
     60                 res = context.getResources();
     61             } else {
     62                 PackageManager pm = context.getPackageManager();
     63                 res = pm.getResourcesForApplication(packageName);
     64             }
     65 
     66             int id = 0;
     67             List<String> segments = uri.getPathSegments();
     68             int size = segments.size();
     69             if (size == 2 && segments.get(0).equals("drawable")) {
     70                 String resName = segments.get(1);
     71                 id = res.getIdentifier(resName, "drawable", packageName);
     72             } else if (size == 1 && TextUtils.isDigitsOnly(segments.get(0))) {
     73                 try {
     74                     id = Integer.parseInt(segments.get(0));
     75                 } catch (NumberFormatException ignored) {
     76                 }
     77             }
     78 
     79             bitmap = BitmapFactory.decodeResource(context.getResources(), id, options);
     80         } else if (uriString.startsWith(ASSET_PREFIX)) {
     81             String assetName = uriString.substring(ASSET_PREFIX.length());
     82             bitmap = BitmapFactory.decodeStream(context.getAssets().open(assetName), null, options);
     83         } else if (uriString.startsWith(FILE_PREFIX)) {
     84             bitmap = BitmapFactory.decodeFile(uriString.substring(FILE_PREFIX.length()), options);
     85         } else {
     86             InputStream inputStream = null;
     87             try {
     88                 ContentResolver contentResolver = context.getContentResolver();
     89                 inputStream = contentResolver.openInputStream(uri);
     90                 bitmap = BitmapFactory.decodeStream(inputStream, null, options);
     91             } finally {
     92                 if (inputStream != null) {
     93                     try { inputStream.close(); } catch (Exception e) { /* Ignore */ }
     94                 }
     95             }
     96         }
     97         if (bitmap == null) {
     98             throw new RuntimeException("Skia image region decoder returned null bitmap - image format may not be supported");
     99         }
    100         return bitmap;
    101     }
    102 }
    103