package co.mwater.clientapp.db;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.UUID;
import co.mwater.clientapp.ui.petrifilm.PetrifilmCameraActivity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Environment;
import android.util.Log;
public class ImageStorage {
private static final String TAG = ImageStorage.class.getCanonicalName();
private final static String FOLDER_DATA_ROOT = "Android/data";
private final static String IMAGES_FOLDER = "images";
private final static String IMAGE_EXTENSION = ".jpg";
private final static String TEMP_FOLDER = "temp";
private final static String PENDING_FOLDER = "pending";
private final static String CACHED_FOLDER = "cached";
private final static String ORIGINAL_FOLDER = "original";
private final static String THUMBNAIL_FOLDER = "thumbnail";
public static String createUid() {
UUID uuid = UUID.randomUUID();
return uuid.toString().replace("-", "").toLowerCase(Locale.US);
}
public static String getTempImagePath(Context context, String uid) throws IOException {
File tempFile = new File(buildExternalPath(context, IMAGES_FOLDER + File.separator + TEMP_FOLDER + File.separator + uid + IMAGE_EXTENSION));
tempFile.getParentFile().mkdirs();
return tempFile.getAbsolutePath();
}
public static String getPendingImagePath(Context context, String uid) throws IOException {
File pendingFile = new File(
buildExternalPath(context, IMAGES_FOLDER + File.separator + PENDING_FOLDER
+ File.separator + ORIGINAL_FOLDER + File.separator + uid + IMAGE_EXTENSION));
pendingFile.getParentFile().mkdirs();
return pendingFile.getAbsolutePath();
}
public static String getPendingThumbnailImagePath(Context context, String uid) throws IOException {
File pendingFile = new File(
buildExternalPath(context, IMAGES_FOLDER + File.separator + PENDING_FOLDER
+ File.separator + THUMBNAIL_FOLDER + File.separator + uid + IMAGE_EXTENSION));
pendingFile.getParentFile().mkdirs();
return pendingFile.getAbsolutePath();
}
public static String getCachedImagePath(Context context, String uid) throws IOException {
File cachedFile = new File(
buildExternalPath(context, IMAGES_FOLDER + File.separator + CACHED_FOLDER
+ File.separator + ORIGINAL_FOLDER + File.separator + uid + IMAGE_EXTENSION));
cachedFile.getParentFile().mkdirs();
return cachedFile.getAbsolutePath();
}
public static String getCachedThumbnailImagePath(Context context, String uid) throws IOException {
File cachedFile = new File(
buildExternalPath(context, IMAGES_FOLDER + File.separator + CACHED_FOLDER
+ File.separator + THUMBNAIL_FOLDER + File.separator + uid + IMAGE_EXTENSION));
cachedFile.getParentFile().mkdirs();
return cachedFile.getAbsolutePath();
}
public static void moveTempImageFileToPending(Context context, String uid) throws IOException {
File tempFile = new File(getTempImagePath(context, uid));
File pendingFile = new File(getPendingImagePath(context, uid));
// Delete if already exists
if (pendingFile.exists())
pendingFile.delete();
if (!tempFile.renameTo(pendingFile))
throw new IOException("Unable to move " + tempFile.getAbsolutePath() + " to " + pendingFile.getAbsolutePath());
createThumbnail(context, pendingFile.getAbsolutePath(), getPendingThumbnailImagePath(context, uid));
}
public static void movePendingImageFileToCached(Context context, String uid) throws IOException {
File pendingFile = new File(getPendingImagePath(context, uid));
File cachedFile = new File(getCachedImagePath(context, uid));
File pendingThumbnailFile = new File(getPendingThumbnailImagePath(context, uid));
File cachedThumbnailFile = new File(getCachedThumbnailImagePath(context, uid));
// Delete if already exists
if (cachedFile.exists())
cachedFile.delete();
if (cachedThumbnailFile.exists())
cachedThumbnailFile.delete();
if (!pendingFile.renameTo(cachedFile))
throw new IOException("Unable to move " + pendingFile.getAbsolutePath() + " to " + cachedFile.getAbsolutePath());
if (!pendingThumbnailFile.renameTo(cachedThumbnailFile))
{
// Simply regenerate thumbnail
createThumbnail(context, cachedFile.getAbsolutePath(), getCachedThumbnailImagePath(context, uid));
}
}
public static String[] getPendingUids(Context context) throws IOException {
// For each pending file
File dir = new File(buildExternalPath(context, IMAGES_FOLDER + File.separator + PENDING_FOLDER
+ File.separator + ORIGINAL_FOLDER));
ArrayList<String> uids = new ArrayList<String>();
String[] files = dir.list();
if (files == null)
return new String[0];
for (String filename : dir.list()) {
uids.add(filename.split("\\.")[0]);
}
String[] arr = new String[uids.size()];
uids.toArray(arr);
return arr;
}
public static void recreateThumbnails(Context context) throws IOException {
for (String uid : getPendingUids(context))
{
Log.d(TAG, "Recreating " + uid);
createThumbnail(context, getPendingImagePath(context, uid), getPendingThumbnailImagePath(context, uid));
}
}
/**
* This static function provides a string to the external storage desired
* file.
*
* @param context
* Android Context.
* @param fileName
* File or directory name.
* @return
* @throws IOException
* Thrown if the external storage is not available or not
* writeable.
*/
public static String buildExternalPath(Context context, String fileName) throws IOException {
// The following code has been taken from the Android dev guide:
// http://developer.android.com/guide/topics/data/data-storage.html#filesExternal
boolean mExternalStorageAvailable = false;
boolean mExternalStorageWriteable = false;
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
// We can read and write the media
mExternalStorageAvailable = mExternalStorageWriteable = true;
} else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
// We can only read the media
mExternalStorageAvailable = true;
mExternalStorageWriteable = false;
} else {
// Something else is wrong. It may be one of many other states, but
// all we need
// to know is we can neither read nor write
mExternalStorageAvailable = mExternalStorageWriteable = false;
}
if (mExternalStorageAvailable == false) {
throw new IOException("The external storage is not available");
}
if (mExternalStorageWriteable == false) {
throw new IOException("The external storage is not writeable");
}
File extPath = Environment.getExternalStorageDirectory();
String fullPath = extPath.getAbsolutePath() + File.separator + FOLDER_DATA_ROOT + File.separator + context.getPackageName() + File.separator + fileName;
return fullPath;
}
private static void createThumbnail(Context context, String imagePath, String thumbnailPath) throws IOException {
Bitmap b = createThumbnail(context, imagePath);
FileOutputStream fos = new FileOutputStream(thumbnailPath);
b.compress(CompressFormat.JPEG, 90, fos);
fos.close();
}
private static Bitmap createThumbnail(Context context, String imagePath) throws IOException {
Uri uri = Uri.fromFile(new File(imagePath));
InputStream in = null;
final int IMAGE_MAX_SIZE = 200 * 200;
in = context.getContentResolver().openInputStream(uri);
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(in, null, o);
in.close();
int scale = 1;
while ((o.outWidth * o.outHeight) * (1 / Math.pow(scale, 2)) > IMAGE_MAX_SIZE) {
scale++;
}
Log.d(TAG, "scale = " + scale + ", orig-width: " + o.outWidth + ", orig-height: " + o.outHeight);
Bitmap b = null;
in = context.getContentResolver().openInputStream(uri);
if (scale > 1) {
scale--;
// scale to max possible inSampleSize that still yields an image
// larger than target
o = new BitmapFactory.Options();
o.inSampleSize = scale;
b = BitmapFactory.decodeStream(in, null, o);
// resize to desired dimensions
int height = b.getHeight();
int width = b.getWidth();
Log.d(TAG, "1th scale operation dimenions - width: " + width + ", height: " + height);
double y = Math.sqrt(IMAGE_MAX_SIZE
/ (((double) width) / height));
double x = (y / height) * width;
Bitmap scaledBitmap = Bitmap.createScaledBitmap(b, (int) x, (int) y, true);
b.recycle();
b = scaledBitmap;
System.gc();
} else {
b = BitmapFactory.decodeStream(in);
}
in.close();
Log.d(TAG, "bitmap size - width: " + b.getWidth() + ", height: " + b.getHeight());
return b;
}
}