/*****************************************************************************
* BitmapUtil.java
*****************************************************************************
* Copyright © 2011-2014 VLC authors and VideoLAN
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
package org.videolan.vlc.util;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import org.videolan.libvlc.util.AndroidUtil;
import org.videolan.vlc.MediaDatabase;
import org.videolan.vlc.MediaWrapper;
import org.videolan.vlc.R;
import org.videolan.vlc.VLCApplication;
public class BitmapUtil {
public final static String TAG = "VLC/Util/BitmapUtil";
public static Bitmap cropBorders(Bitmap bitmap, int width, int height)
{
int top = 0;
for (int i = 0; i < height / 2; i++) {
int pixel1 = bitmap.getPixel(width / 2, i);
int pixel2 = bitmap.getPixel(width / 2, height - i - 1);
if ((pixel1 == 0 || pixel1 == -16777216) &&
(pixel2 == 0 || pixel2 == -16777216)) {
top = i;
} else {
break;
}
}
int left = 0;
for (int i = 0; i < width / 2; i++) {
int pixel1 = bitmap.getPixel(i, height / 2);
int pixel2 = bitmap.getPixel(width - i - 1, height / 2);
if ((pixel1 == 0 || pixel1 == -16777216) &&
(pixel2 == 0 || pixel2 == -16777216)) {
left = i;
} else {
break;
}
}
if (left >= width / 2 - 10 || top >= height / 2 - 10)
return bitmap;
// Cut off the transparency on the borders
return Bitmap.createBitmap(bitmap, left, top,
(width - (2 * left)), (height - (2 * top)));
}
public static Bitmap scaleDownBitmap(Context context, Bitmap bitmap, int width) {
/*
* This method can lead to OutOfMemoryError!
* If the source size is more than twice the target size use
* the optimized version available in AudioUtil::readCoverBitmap
*/
if (bitmap != null) {
final float densityMultiplier = context.getResources().getDisplayMetrics().density;
int w = (int) (width * densityMultiplier);
int h = (int) (w * bitmap.getHeight() / ((double) bitmap.getWidth()));
bitmap = Bitmap.createScaledBitmap(bitmap, w, h, true);
}
return bitmap;
}
public static Bitmap getPictureFromCache(MediaWrapper media) {
// mPicture is not null only if passed through
// the ctor which is deprecated by now.
Bitmap b = media.getPicture();
if (b == null) {
final BitmapCache cache = BitmapCache.getInstance();
return cache.getBitmapFromMemCache(media.getLocation());
} else {
return b;
}
}
public static Bitmap fetchPicture(MediaWrapper media) {
final BitmapCache cache = BitmapCache.getInstance();
Bitmap picture = readCoverBitmap(media.getArtworkURL());
if (picture == null) {
picture = MediaDatabase.getInstance().getPicture(media.getUri());
}
cache.addBitmapToMemCache(media.getLocation(), picture);
return picture;
}
public static Bitmap getPicture(MediaWrapper media) {
final Bitmap picture = getPictureFromCache(media);
if (picture != null)
return picture;
else
return fetchPicture(media);
}
private static Bitmap readCoverBitmap(String path) {
if (path == null)
return null;
Resources res = VLCApplication.getAppResources();
String uri = Uri.decode(path);
if (uri.startsWith("file://"))
uri = uri.substring(7);
Bitmap cover = null;
BitmapFactory.Options options = new BitmapFactory.Options();
int height = res.getDimensionPixelSize(R.dimen.grid_card_thumb_height);
int width = res.getDimensionPixelSize(R.dimen.grid_card_thumb_width);
/* Get the resolution of the bitmap without allocating the memory */
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(uri, options);
if (options.outWidth > 0 && options.outHeight > 0) {
if (options.outWidth > width){
options.outWidth = width;
options.outHeight = height;
}
options.inJustDecodeBounds = false;
// Decode the file (with memory allocation this time)
try {
cover = BitmapFactory.decodeFile(uri, options);
} catch (OutOfMemoryError e) {
cover = null;
}
}
return cover;
}
@TargetApi(Build.VERSION_CODES.KITKAT)
static boolean canUseForInBitmap(
Bitmap candidate, BitmapFactory.Options targetOptions) {
if (candidate == null)
return false;
if (AndroidUtil.isKitKatOrLater()) {
if (targetOptions.inSampleSize == 0)
return false;
// From Android 4.4 (KitKat) onward we can re-use if the byte size of
// the new bitmap is smaller than the reusable bitmap candidate
// allocation byte count.
int width = targetOptions.outWidth / targetOptions.inSampleSize;
int height = targetOptions.outHeight / targetOptions.inSampleSize;
int byteCount = width * height * getBytesPerPixel(candidate.getConfig());
return byteCount <= candidate.getAllocationByteCount();
}
// On earlier versions, the dimensions must match exactly and the inSampleSize must be 1
return candidate.getWidth() == targetOptions.outWidth
&& candidate.getHeight() == targetOptions.outHeight
&& targetOptions.inSampleSize == 1;
}
/**
* A helper function to return the byte usage per pixel of a bitmap based on its configuration.
*/
static int getBytesPerPixel(Bitmap.Config config) {
if (config == Bitmap.Config.ARGB_8888) {
return 4;
} else if (config == Bitmap.Config.RGB_565) {
return 2;
} else if (config == Bitmap.Config.ARGB_4444) {
return 2;
} else if (config == Bitmap.Config.ALPHA_8) {
return 1;
}
return 1;
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static void setInBitmap(BitmapFactory.Options options){
if (!AndroidUtil.isHoneycombOrLater())
return;
Bitmap inBitmap = BitmapCache.getInstance().getReusableBitmap(options);
if (inBitmap != null) {
options.inBitmap = inBitmap;
}
}
}