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