blob: de818cab7bed688a1a6cbe21ae0a7704210be7d7 [file] [log] [blame]
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;
}
}