| package com.davemorrissey.labs.subscaleview; |
| |
| import android.graphics.Bitmap; |
| import android.graphics.Rect; |
| import android.net.Uri; |
| |
| import java.io.File; |
| import java.io.UnsupportedEncodingException; |
| import java.net.URLDecoder; |
| |
| /** |
| * Helper class used to set the source and additional attributes from a variety of sources. Supports |
| * use of a bitmap, asset, resource, external file or any other URI. |
| * |
| * When you are using a preview image, you must set the dimensions of the full size image on the |
| * ImageSource object for the full size image using the {@link #dimensions(int, int)} method. |
| */ |
| @SuppressWarnings({"unused", "WeakerAccess"}) |
| public final class ImageSource { |
| |
| static final String FILE_SCHEME = "file:///"; |
| static final String ASSET_SCHEME = "file:///android_asset/"; |
| |
| private final Uri uri; |
| private final Bitmap bitmap; |
| private final Integer resource; |
| private boolean tile; |
| private int sWidth; |
| private int sHeight; |
| private Rect sRegion; |
| private boolean cached; |
| |
| private ImageSource(Bitmap bitmap, boolean cached) { |
| this.bitmap = bitmap; |
| this.uri = null; |
| this.resource = null; |
| this.tile = false; |
| this.sWidth = bitmap.getWidth(); |
| this.sHeight = bitmap.getHeight(); |
| this.cached = cached; |
| } |
| |
| private ImageSource(Uri uri) { |
| // #114 If file doesn't exist, attempt to url decode the URI and try again |
| String uriString = uri.toString(); |
| if (uriString.startsWith(FILE_SCHEME)) { |
| File uriFile = new File(uriString.substring(FILE_SCHEME.length() - 1)); |
| if (!uriFile.exists()) { |
| try { |
| uri = Uri.parse(URLDecoder.decode(uriString, "UTF-8")); |
| } catch (UnsupportedEncodingException e) { |
| // Fallback to encoded URI. This exception is not expected. |
| } |
| } |
| } |
| this.bitmap = null; |
| this.uri = uri; |
| this.resource = null; |
| this.tile = true; |
| } |
| |
| private ImageSource(int resource) { |
| this.bitmap = null; |
| this.uri = null; |
| this.resource = resource; |
| this.tile = true; |
| } |
| |
| /** |
| * Create an instance from a resource. The correct resource for the device screen resolution will be used. |
| * @param resId resource ID. |
| * @return an {@link ImageSource} instance. |
| */ |
| public static ImageSource resource(int resId) { |
| return new ImageSource(resId); |
| } |
| |
| /** |
| * Create an instance from an asset name. |
| * @param assetName asset name. |
| * @return an {@link ImageSource} instance. |
| */ |
| public static ImageSource asset(String assetName) { |
| if (assetName == null) { |
| throw new NullPointerException("Asset name must not be null"); |
| } |
| return uri(ASSET_SCHEME + assetName); |
| } |
| |
| /** |
| * Create an instance from a URI. If the URI does not start with a scheme, it's assumed to be the URI |
| * of a file. |
| * @param uri image URI. |
| * @return an {@link ImageSource} instance. |
| */ |
| public static ImageSource uri(String uri) { |
| if (uri == null) { |
| throw new NullPointerException("Uri must not be null"); |
| } |
| if (!uri.contains("://")) { |
| if (uri.startsWith("/")) { |
| uri = uri.substring(1); |
| } |
| uri = FILE_SCHEME + uri; |
| } |
| return new ImageSource(Uri.parse(uri)); |
| } |
| |
| /** |
| * Create an instance from a URI. |
| * @param uri image URI. |
| * @return an {@link ImageSource} instance. |
| */ |
| public static ImageSource uri(Uri uri) { |
| if (uri == null) { |
| throw new NullPointerException("Uri must not be null"); |
| } |
| return new ImageSource(uri); |
| } |
| |
| /** |
| * Provide a loaded bitmap for display. |
| * @param bitmap bitmap to be displayed. |
| * @return an {@link ImageSource} instance. |
| */ |
| public static ImageSource bitmap(Bitmap bitmap) { |
| if (bitmap == null) { |
| throw new NullPointerException("Bitmap must not be null"); |
| } |
| return new ImageSource(bitmap, false); |
| } |
| |
| /** |
| * Provide a loaded and cached bitmap for display. This bitmap will not be recycled when it is no |
| * longer needed. Use this method if you loaded the bitmap with an image loader such as Picasso |
| * or Volley. |
| * @param bitmap bitmap to be displayed. |
| * @return an {@link ImageSource} instance. |
| */ |
| public static ImageSource cachedBitmap(Bitmap bitmap) { |
| if (bitmap == null) { |
| throw new NullPointerException("Bitmap must not be null"); |
| } |
| return new ImageSource(bitmap, true); |
| } |
| |
| /** |
| * Enable tiling of the image. This does not apply to preview images which are always loaded as a single bitmap., |
| * and tiling cannot be disabled when displaying a region of the source image. |
| * @return this instance for chaining. |
| */ |
| public ImageSource tilingEnabled() { |
| return tiling(true); |
| } |
| |
| /** |
| * Disable tiling of the image. This does not apply to preview images which are always loaded as a single bitmap, |
| * and tiling cannot be disabled when displaying a region of the source image. |
| * @return this instance for chaining. |
| */ |
| public ImageSource tilingDisabled() { |
| return tiling(false); |
| } |
| |
| /** |
| * Enable or disable tiling of the image. This does not apply to preview images which are always loaded as a single bitmap, |
| * and tiling cannot be disabled when displaying a region of the source image. |
| * @param tile whether tiling should be enabled. |
| * @return this instance for chaining. |
| */ |
| public ImageSource tiling(boolean tile) { |
| this.tile = tile; |
| return this; |
| } |
| |
| /** |
| * Use a region of the source image. Region must be set independently for the full size image and the preview if |
| * you are using one. |
| * @param sRegion the region of the source image to be displayed. |
| * @return this instance for chaining. |
| */ |
| public ImageSource region(Rect sRegion) { |
| this.sRegion = sRegion; |
| setInvariants(); |
| return this; |
| } |
| |
| /** |
| * Declare the dimensions of the image. This is only required for a full size image, when you are specifying a URI |
| * and also a preview image. When displaying a bitmap object, or not using a preview, you do not need to declare |
| * the image dimensions. Note if the declared dimensions are found to be incorrect, the view will reset. |
| * @param sWidth width of the source image. |
| * @param sHeight height of the source image. |
| * @return this instance for chaining. |
| */ |
| public ImageSource dimensions(int sWidth, int sHeight) { |
| if (bitmap == null) { |
| this.sWidth = sWidth; |
| this.sHeight = sHeight; |
| } |
| setInvariants(); |
| return this; |
| } |
| |
| private void setInvariants() { |
| if (this.sRegion != null) { |
| this.tile = true; |
| this.sWidth = this.sRegion.width(); |
| this.sHeight = this.sRegion.height(); |
| } |
| } |
| |
| protected final Uri getUri() { |
| return uri; |
| } |
| |
| protected final Bitmap getBitmap() { |
| return bitmap; |
| } |
| |
| protected final Integer getResource() { |
| return resource; |
| } |
| |
| protected final boolean getTile() { |
| return tile; |
| } |
| |
| protected final int getSWidth() { |
| return sWidth; |
| } |
| |
| protected final int getSHeight() { |
| return sHeight; |
| } |
| |
| protected final Rect getSRegion() { |
| return sRegion; |
| } |
| |
| protected final boolean isCached() { |
| return cached; |
| } |
| } |