package it.sephiroth.android.library.imagezoom.test.utils;
import android.content.ContentResolver;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
public class DecodeUtils {
/**
* Try to load a {@link Bitmap} from the passed {@link Uri} ( a file, a content or an url )
*
* @param context the current app context
* @param uri the image source
* @param maxW the final image maximum width
* @param maxH the final image maximum height
* @return the loaded and resized bitmap, if success, or null if load was unsuccesful
*/
public static Bitmap decode(Context context, Uri uri, int maxW, int maxH) {
InputStream stream = openInputStream(context, uri);
if (null == stream) {
return null;
}
int orientation = ExifUtils.getExifOrientation(context, uri);
Bitmap bitmap = null;
int[] imageSize = new int[2];
final boolean decoded = decodeImageBounds(stream, imageSize);
IOUtils.closeSilently(stream);
if (decoded) {
int sampleSize;
if (maxW < 0 || maxH < 0) {
sampleSize = 1;
} else {
sampleSize = computeSampleSize(imageSize[0], imageSize[1], (int) (maxW * 1.2), (int) (maxH * 1.2), orientation);
}
BitmapFactory.Options options = getDefaultOptions();
options.inSampleSize = sampleSize;
bitmap = decodeBitmap(context, uri, options, maxW, maxH, orientation, 0);
}
return bitmap;
}
static Bitmap decodeBitmap(Context context, Uri uri, BitmapFactory.Options options, int maxW, int maxH,
int orientation, int pass) {
Bitmap bitmap = null;
Bitmap newBitmap = null;
if (pass > 20) {
return null;
}
InputStream stream = openInputStream(context, uri);
if (null == stream) return null;
try {
// decode the bitmap via android BitmapFactory
bitmap = BitmapFactory.decodeStream(stream, null, options);
IOUtils.closeSilently(stream);
if (bitmap != null) {
if (maxW > 0 && maxH > 0) {
newBitmap = BitmapUtils.resizeBitmap(bitmap, maxW, maxH, orientation);
if (bitmap != newBitmap) {
bitmap.recycle();
}
bitmap = newBitmap;
}
}
} catch (OutOfMemoryError error) {
IOUtils.closeSilently(stream);
if (null != bitmap) {
bitmap.recycle();
}
options.inSampleSize += 1;
bitmap = decodeBitmap(context, uri, options, maxW, maxH, orientation, pass + 1);
}
return bitmap;
}
/**
* Return an {@link InputStream} from the given uri. ( can be a local content, a file path or an http url )
*
* @param context
* @param uri
* @return the {@link InputStream} from the given uri, null if uri cannot be opened
*/
public static InputStream openInputStream(Context context, Uri uri) {
if (null == uri) return null;
final String scheme = uri.getScheme();
InputStream stream = null;
if (scheme == null || ContentResolver.SCHEME_FILE.equals(scheme)) {
// from file
stream = openFileInputStream(uri.getPath());
} else if (ContentResolver.SCHEME_CONTENT.equals(scheme)) {
// from content
stream = openContentInputStream(context, uri);
} else if ("http".equals(scheme) || "https".equals(scheme)) {
// from remote uri
stream = openRemoteInputStream(uri);
}
return stream;
}
public static boolean decodeImageBounds(final InputStream stream, int[] outSize) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(stream, null, options);
if (options.outHeight > 0 && options.outWidth > 0) {
outSize[0] = options.outWidth;
outSize[1] = options.outHeight;
return true;
}
return false;
}
private static int computeSampleSize(final int bitmapW, final int bitmapH, final int maxW, final int maxH,
final int orientation) {
double w, h;
if (orientation == 0 || orientation == 180) {
w = bitmapW;
h = bitmapH;
} else {
w = bitmapH;
h = bitmapW;
}
return (int) Math.ceil(Math.max(w / maxW, h / maxH));
}
/**
* Return a {@link FileInputStream} from the given path or null if file not found
*
* @param path the file path
* @return the {@link FileInputStream} of the given path, null if {@link FileNotFoundException} is thrown
*/
static InputStream openFileInputStream(String path) {
try {
return new FileInputStream(path);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return null;
}
/**
* Return a {@link BufferedInputStream} from the given uri or null if an exception is thrown
*
* @param context
* @param uri
* @return the {@link InputStream} of the given path. null if file is not found
*/
static InputStream openContentInputStream(Context context, Uri uri) {
try {
return context.getContentResolver().openInputStream(uri);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return null;
}
/**
* Return an {@link InputStream} from the given url or null if failed to retrieve the content
*
* @param uri
* @return
*/
static InputStream openRemoteInputStream(Uri uri) {
java.net.URL finalUrl;
try {
finalUrl = new java.net.URL(uri.toString());
} catch (MalformedURLException e) {
e.printStackTrace();
return null;
}
HttpURLConnection connection;
try {
connection = (HttpURLConnection) finalUrl.openConnection();
} catch (IOException e) {
e.printStackTrace();
return null;
}
connection.setInstanceFollowRedirects(false);
int code;
try {
code = connection.getResponseCode();
} catch (IOException e) {
e.printStackTrace();
return null;
}
// permanent redirection
if (code == HttpURLConnection.HTTP_MOVED_PERM || code == HttpURLConnection.HTTP_MOVED_TEMP
|| code == HttpURLConnection.HTTP_SEE_OTHER) {
String newLocation = connection.getHeaderField("Location");
return openRemoteInputStream(Uri.parse(newLocation));
}
try {
return (InputStream) finalUrl.getContent();
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
static BitmapFactory.Options getDefaultOptions() {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
options.inDither = false;
options.inJustDecodeBounds = false;
options.inPurgeable = true;
options.inInputShareable = true;
options.inTempStorage = new byte[16 * 1024];
return options;
}
}