/*
* Copyright 2012 Kevin Sawicki <kevinsawicki@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.kevinsawicki.wishlist;
import static android.graphics.Bitmap.Config.ARGB_8888;
import static android.util.Log.DEBUG;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.os.AsyncTask;
import android.util.Log;
import java.io.File;
/**
* Task to decode a bitmap from a file path
*/
public class DecodeBitmapTask extends AsyncTask<Void, Void, Bitmap> {
private static final String TAG = "DecodeBitmapTask";
/**
* Get byte count
*
* @param bitmap
* @return byte count
*/
public static final int getByteCount(final Bitmap bitmap) {
return bitmap.getRowBytes() * bitmap.getHeight();
}
private static final byte[] BUFFER = new byte[16 * 1024];
/**
* Maximum width of decoded bitmap
*/
protected final int maxWidth;
/**
* Maximum height of decoded bitmap
*/
protected final int maxHeight;
/**
* Path to decoded bitmap from
*/
protected final String path;
/**
* Create task to decode the bitmap at the specified path to the specified
* maximum width and height
*
* @param maxWidth
* @param maxHeight
* @param path
*/
public DecodeBitmapTask(final int maxWidth, final int maxHeight,
final String path) {
this.maxWidth = maxWidth;
this.maxHeight = maxHeight;
this.path = path;
}
/**
* Decode {@link Bitmap} at given path
*
* @return bitmap
*/
protected Bitmap decode() {
final Options options = new Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
if (options.outWidth <= 0 || options.outHeight <= 0) {
Log.d(TAG, "Decoding bounds of " + path + " failed");
new File(path).delete();
return null;
}
if (isCancelled())
return null;
int scale = 1;
if (options.outWidth > maxWidth || options.outHeight > maxHeight)
scale = Math.max(
Math.round((float) options.outHeight / (float) maxHeight),
Math.round((float) options.outWidth / (float) maxWidth));
options.inJustDecodeBounds = false;
options.inSampleSize = scale;
options.inPreferredConfig = ARGB_8888;
options.inPurgeable = true;
Bitmap decoded;
synchronized (BUFFER) {
options.inTempStorage = BUFFER;
decoded = BitmapFactory.decodeFile(path, options);
}
if (Log.isLoggable(TAG, DEBUG)) {
if (decoded == null) {
Log.d(TAG, "Decoding " + path + " failed");
new File(path).delete();
} else
Log.d(TAG,
"Decoded to " + decoded.getWidth() + "x" + decoded.getHeight()
+ " from max size: " + maxWidth + "x" + maxHeight
+ " using scale:" + scale + " and byte count:"
+ getByteCount(decoded));
}
return decoded;
}
/**
* Does the given path exist?
*
* @param path
* @return true if exists and non-empty, false otherwise
*/
protected boolean pathExists(final String path) {
File file = new File(path);
return file.exists() && file.length() > 0;
}
/**
* Load bitmap
*
* @return bitmap
*/
protected Bitmap load() {
if (pathExists(path))
return decode();
else
return null;
}
@Override
protected Bitmap doInBackground(final Void... params) {
if (!isCancelled())
return load();
else
return null;
}
/**
* Get path being decoded
*
* @return path
*/
public String getPath() {
return path;
}
}