package com.vaguehope.onosendai.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.graphics.BitmapRegionDecoder;
import android.graphics.Rect;
import android.net.Uri;
import android.provider.MediaStore.MediaColumns;
public class ImageMetadata implements Titleable {
private static final String SCHEME_FILE = "file";
private static final String SCHEME_CONTENT = "content";
private static final LogWrapper LOG = new LogWrapper("IM");
private final Context context;
private final Uri uri;
private final long size;
private final String name;
private final Object[] bitmapLock = new Object[0];
private volatile AssetFileDescriptor fileDescriptor;
private volatile SoftReference<Bitmap> cacheBitmap;
private volatile int cacheScale = -1;
private volatile int cachedWidth = -1;
private volatile int cachedHeight = -1;
public ImageMetadata (final Context context, final Uri uri) {
this.context = context;
this.uri = uri;
if (uri == null) {
this.size = 0;
this.name = null;
}
else if (SCHEME_CONTENT.equals(uri.getScheme())) {
final Cursor cursor = context.getContentResolver().query(uri, new String[] {
MediaColumns.SIZE, MediaColumns.DISPLAY_NAME
}, null, null, null);
try {
if (cursor != null) {
cursor.moveToFirst();
final int colSize = cursor.getColumnIndex(MediaColumns.SIZE);
final int colDisplayName = cursor.getColumnIndex(MediaColumns.DISPLAY_NAME); // Filename with extension.
this.size = cursor.getLong(colSize);
this.name = cursor.getString(colDisplayName);
}
else {
throw new IllegalArgumentException("Resource not found: " + uri);
}
}
finally {
IoHelper.closeQuietly(cursor);
}
}
else if (SCHEME_FILE.equals(uri.getScheme())) {
this.size = new File(uri.getPath()).length();
this.name = uri.getLastPathSegment();
}
else {
throw new IllegalArgumentException("Unknown resource type: " + uri);
}
}
public boolean exists () {
return this.uri != null;
}
/**
* With file extension.
*/
public String getName () {
return this.name;
}
public long getSize () {
return this.size;
}
@Override
public String getUiTitle () {
if (this.name == null) return "(empty)";
return String.format("%s (%s)", this.name, IoHelper.readableFileSize(this.size));
}
public InputStream open () throws IOException {
if (this.uri == null) return null;
if (SCHEME_FILE.equals(this.uri.getScheme())) return new FileInputStream(new File(this.uri.getPath()));
if (SCHEME_CONTENT.equals(this.uri.getScheme())) return this.context.getContentResolver().openInputStream(this.uri);
throw new IllegalArgumentException("Unknown resource type: " + this.uri);
}
private AssetFileDescriptor openFileDescriptor () throws IOException {
if (this.uri == null) return null;
synchronized (this.bitmapLock) {
if (this.fileDescriptor == null) {
if (SCHEME_FILE.equals(this.uri.getScheme()) || SCHEME_CONTENT.equals(this.uri.getScheme())) {
this.fileDescriptor = this.context.getContentResolver().openAssetFileDescriptor(this.uri, "r");
}
else {
throw new IllegalArgumentException("Unknown resource type: " + this.uri);
}
}
return this.fileDescriptor;
}
}
public int getWidth () throws IOException {
if (this.cachedWidth < 1) readDimentions();
return this.cachedWidth;
}
public int getHeight () throws IOException {
if (this.cachedHeight < 1) readDimentions();
return this.cachedHeight;
}
private void readDimentions () throws IOException {
synchronized (this.bitmapLock) {
final Options opts = new Options();
opts.inJustDecodeBounds = true;
BitmapFactory.decodeFileDescriptor(openFileDescriptor().getFileDescriptor(), null, opts);
this.cachedWidth = opts.outWidth;
this.cachedHeight = opts.outHeight;
}
}
public Bitmap getBitmap (final int scalePercentage) throws IOException {
return getBitmap(scalePercentage, null);
}
public Bitmap getBitmap (final int scalePercentage, final Rect cropRect) throws IOException {
synchronized (this.bitmapLock) {
final Bitmap cached = this.cacheBitmap == null ? null : this.cacheBitmap.get();
if (cached != null && scalePercentage != this.cacheScale) {
this.cacheBitmap = null;
cached.recycle();
}
if (cached == null || scalePercentage != this.cacheScale) {
final Bitmap fresh = readBitmap(scalePercentage, cropRect);
this.cacheScale = scalePercentage;
this.cacheBitmap = new SoftReference<Bitmap>(fresh);
return fresh;
}
return cached;
}
}
private Bitmap readBitmap (final int scalePercentage, final Rect cropRect) throws IOException {
if (100 % scalePercentage != 0) throw new IllegalArgumentException("scalePercentage " + scalePercentage + " is not a int ratio.");
final Options opts = new Options();
opts.inPurgeable = true;
opts.inInputShareable = true;
opts.inSampleSize = 100 / scalePercentage;
if (cropRect != null) {
final BitmapRegionDecoder dec = BitmapRegionDecoder.newInstance(openFileDescriptor().getFileDescriptor(), true);
try {
return dec.decodeRegion(cropRect, opts);
}
finally {
dec.recycle();
}
}
return BitmapFactory.decodeFileDescriptor(openFileDescriptor().getFileDescriptor(), null, opts);
}
public void recycle () {
synchronized (this.bitmapLock) {
if (this.cacheBitmap != null) {
final Bitmap cached = this.cacheBitmap.get();
if (cached != null) cached.recycle();
this.cacheBitmap = null;
}
if (this.fileDescriptor != null) {
try {
this.fileDescriptor.close();
}
catch (final IOException e) {
LOG.w("Failed to dispose of fileDescriptor.", e);
}
this.fileDescriptor = null;
}
}
}
@Override
public String toString () {
return new StringBuilder(getClass().getSimpleName()).append("{").append(this.uri)
.append(",").append(this.name)
.append(",").append(this.size)
.append("}").toString();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
public static boolean isUnderstoodResource (final Uri uri) {
if (uri == null) return false;
return SCHEME_CONTENT.equals(uri.getScheme()) || SCHEME_FILE.equals(uri.getScheme());
}
public static boolean isRemoteResource (final Uri uri) {
if (uri == null) return false;
return SCHEME_CONTENT.equals(uri.getScheme());
}
}