• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ImageSource(Bitmap bitmap, boolean cached)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 
ImageSource(Uri uri)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 
ImageSource(int resource)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      */
resource(int resId)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      */
asset(String assetName)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      */
uri(String uri)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      */
uri(Uri uri)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      */
bitmap(Bitmap bitmap)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      */
cachedBitmap(Bitmap bitmap)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      */
tilingEnabled()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      */
tilingDisabled()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      */
tiling(boolean tile)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      */
region(Rect sRegion)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      */
dimensions(int sWidth, int sHeight)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 
setInvariants()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 
getUri()213     protected final Uri getUri() {
214         return uri;
215     }
216 
getBitmap()217     protected final Bitmap getBitmap() {
218         return bitmap;
219     }
220 
getResource()221     protected final Integer getResource() {
222         return resource;
223     }
224 
getTile()225     protected final boolean getTile() {
226         return tile;
227     }
228 
getSWidth()229     protected final int getSWidth() {
230         return sWidth;
231     }
232 
getSHeight()233     protected final int getSHeight() {
234         return sHeight;
235     }
236 
getSRegion()237     protected final Rect getSRegion() {
238         return sRegion;
239     }
240 
isCached()241     protected final boolean isCached() {
242         return cached;
243     }
244 }
245