Home | History | Annotate | Download | only in subscaleview
      1 package com.davemorrissey.labs.subscaleview;
      2 
      3 import android.graphics.Bitmap;
      4 import android.graphics.Rect;
      5 import android.net.Uri;
      6 
      7 import java.io.File;
      8 import java.io.UnsupportedEncodingException;
      9 import java.net.URLDecoder;
     10 
     11 /**
     12  * Helper class used to set the source and additional attributes from a variety of sources. Supports
     13  * use of a bitmap, asset, resource, external file or any other URI.
     14  *
     15  * When you are using a preview image, you must set the dimensions of the full size image on the
     16  * ImageSource object for the full size image using the {@link #dimensions(int, int)} method.
     17  */
     18 @SuppressWarnings({"unused", "WeakerAccess"})
     19 public final class ImageSource {
     20 
     21     static final String FILE_SCHEME = "file:///";
     22     static final String ASSET_SCHEME = "file:///android_asset/";
     23 
     24     private final Uri uri;
     25     private final Bitmap bitmap;
     26     private final Integer resource;
     27     private boolean tile;
     28     private int sWidth;
     29     private int sHeight;
     30     private Rect sRegion;
     31     private boolean cached;
     32 
     33     private ImageSource(Bitmap bitmap, boolean cached) {
     34         this.bitmap = bitmap;
     35         this.uri = null;
     36         this.resource = null;
     37         this.tile = false;
     38         this.sWidth = bitmap.getWidth();
     39         this.sHeight = bitmap.getHeight();
     40         this.cached = cached;
     41     }
     42 
     43     private ImageSource(Uri uri) {
     44         // #114 If file doesn't exist, attempt to url decode the URI and try again
     45         String uriString = uri.toString();
     46         if (uriString.startsWith(FILE_SCHEME)) {
     47             File uriFile = new File(uriString.substring(FILE_SCHEME.length() - 1));
     48             if (!uriFile.exists()) {
     49                 try {
     50                     uri = Uri.parse(URLDecoder.decode(uriString, "UTF-8"));
     51                 } catch (UnsupportedEncodingException e) {
     52                     // Fallback to encoded URI. This exception is not expected.
     53                 }
     54             }
     55         }
     56         this.bitmap = null;
     57         this.uri = uri;
     58         this.resource = null;
     59         this.tile = true;
     60     }
     61 
     62     private ImageSource(int resource) {
     63         this.bitmap = null;
     64         this.uri = null;
     65         this.resource = resource;
     66         this.tile = true;
     67     }
     68 
     69     /**
     70      * Create an instance from a resource. The correct resource for the device screen resolution will be used.
     71      * @param resId resource ID.
     72      * @return an {@link ImageSource} instance.
     73      */
     74     public static ImageSource resource(int resId) {
     75         return new ImageSource(resId);
     76     }
     77 
     78     /**
     79      * Create an instance from an asset name.
     80      * @param assetName asset name.
     81      * @return an {@link ImageSource} instance.
     82      */
     83     public static ImageSource asset(String assetName) {
     84         if (assetName == null) {
     85             throw new NullPointerException("Asset name must not be null");
     86         }
     87         return uri(ASSET_SCHEME + assetName);
     88     }
     89 
     90     /**
     91      * Create an instance from a URI. If the URI does not start with a scheme, it's assumed to be the URI
     92      * of a file.
     93      * @param uri image URI.
     94      * @return an {@link ImageSource} instance.
     95      */
     96     public static ImageSource uri(String uri) {
     97         if (uri == null) {
     98             throw new NullPointerException("Uri must not be null");
     99         }
    100         if (!uri.contains("://")) {
    101             if (uri.startsWith("/")) {
    102                 uri = uri.substring(1);
    103             }
    104             uri = FILE_SCHEME + uri;
    105         }
    106         return new ImageSource(Uri.parse(uri));
    107     }
    108 
    109     /**
    110      * Create an instance from a URI.
    111      * @param uri image URI.
    112      * @return an {@link ImageSource} instance.
    113      */
    114     public static ImageSource uri(Uri uri) {
    115         if (uri == null) {
    116             throw new NullPointerException("Uri must not be null");
    117         }
    118         return new ImageSource(uri);
    119     }
    120 
    121     /**
    122      * Provide a loaded bitmap for display.
    123      * @param bitmap bitmap to be displayed.
    124      * @return an {@link ImageSource} instance.
    125      */
    126     public static ImageSource bitmap(Bitmap bitmap) {
    127         if (bitmap == null) {
    128             throw new NullPointerException("Bitmap must not be null");
    129         }
    130         return new ImageSource(bitmap, false);
    131     }
    132 
    133     /**
    134      * Provide a loaded and cached bitmap for display. This bitmap will not be recycled when it is no
    135      * longer needed. Use this method if you loaded the bitmap with an image loader such as Picasso
    136      * or Volley.
    137      * @param bitmap bitmap to be displayed.
    138      * @return an {@link ImageSource} instance.
    139      */
    140     public static ImageSource cachedBitmap(Bitmap bitmap) {
    141         if (bitmap == null) {
    142             throw new NullPointerException("Bitmap must not be null");
    143         }
    144         return new ImageSource(bitmap, true);
    145     }
    146 
    147     /**
    148      * Enable tiling of the image. This does not apply to preview images which are always loaded as a single bitmap.,
    149      * and tiling cannot be disabled when displaying a region of the source image.
    150      * @return this instance for chaining.
    151      */
    152     public ImageSource tilingEnabled() {
    153         return tiling(true);
    154     }
    155 
    156     /**
    157      * Disable tiling of the image. This does not apply to preview images which are always loaded as a single bitmap,
    158      * and tiling cannot be disabled when displaying a region of the source image.
    159      * @return this instance for chaining.
    160      */
    161     public ImageSource tilingDisabled() {
    162         return tiling(false);
    163     }
    164 
    165     /**
    166      * Enable or disable tiling of the image. This does not apply to preview images which are always loaded as a single bitmap,
    167      * and tiling cannot be disabled when displaying a region of the source image.
    168      * @param tile whether tiling should be enabled.
    169      * @return this instance for chaining.
    170      */
    171     public ImageSource tiling(boolean tile) {
    172         this.tile = tile;
    173         return this;
    174     }
    175 
    176     /**
    177      * Use a region of the source image. Region must be set independently for the full size image and the preview if
    178      * you are using one.
    179      * @param sRegion the region of the source image to be displayed.
    180      * @return this instance for chaining.
    181      */
    182     public ImageSource region(Rect sRegion) {
    183         this.sRegion = sRegion;
    184         setInvariants();
    185         return this;
    186     }
    187 
    188     /**
    189      * Declare the dimensions of the image. This is only required for a full size image, when you are specifying a URI
    190      * and also a preview image. When displaying a bitmap object, or not using a preview, you do not need to declare
    191      * the image dimensions. Note if the declared dimensions are found to be incorrect, the view will reset.
    192      * @param sWidth width of the source image.
    193      * @param sHeight height of the source image.
    194      * @return this instance for chaining.
    195      */
    196     public ImageSource dimensions(int sWidth, int sHeight) {
    197         if (bitmap == null) {
    198             this.sWidth = sWidth;
    199             this.sHeight = sHeight;
    200         }
    201         setInvariants();
    202         return this;
    203     }
    204 
    205     private void setInvariants() {
    206         if (this.sRegion != null) {
    207             this.tile = true;
    208             this.sWidth = this.sRegion.width();
    209             this.sHeight = this.sRegion.height();
    210         }
    211     }
    212 
    213     protected final Uri getUri() {
    214         return uri;
    215     }
    216 
    217     protected final Bitmap getBitmap() {
    218         return bitmap;
    219     }
    220 
    221     protected final Integer getResource() {
    222         return resource;
    223     }
    224 
    225     protected final boolean getTile() {
    226         return tile;
    227     }
    228 
    229     protected final int getSWidth() {
    230         return sWidth;
    231     }
    232 
    233     protected final int getSHeight() {
    234         return sHeight;
    235     }
    236 
    237     protected final Rect getSRegion() {
    238         return sRegion;
    239     }
    240 
    241     protected final boolean isCached() {
    242         return cached;
    243     }
    244 }
    245