package com.tencent.tws.assistant.utils;
import java.lang.ref.WeakReference;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.WindowManager;
public class BitmapUtil {
private static final String TAG = "BitmapUtil";
// synchronization lock
private static final byte[] mPixelsLock = new byte[0];
private static final int MIN_VALID_ALPHA = 28;
private static WeakReference<int[]> mRefPixels = null;
public static final int DEFAULT_PAINT_FLAGS = Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG;
public static final float DENSITY_H = 1.5f;
public static final float DENSITY_XH = 2f;
public static final float DENSITY_XXH = 3f;
public static final float WIDTH_H = 480f;
public static final float WIDTH_XH = 720f;
public static final float WIDTH_XXH = 1080f;
private static Rect mRect = new Rect();
public static final String THEME_ICON_MASK = "launcher_theme_icon_mask";
public static final String THEME_ICON_SHADOW = "launcher_theme_icon_shadow";
public static final int TWS_ICON_SIZE_FRAME = 192;
public static final int TWS_ICON_SIZE_SQUARE = 156;
public static final int TWS_ICON_SIZE_NOT_SQUARE = 168;
public static IconAnalyzedResult analyzeBitmap1(Bitmap srcBmp) {
// long beforeTime = System.currentTimeMillis();
final IconAnalyzedResult result = new IconAnalyzedResult();
final int width = srcBmp.getWidth();
final int height = srcBmp.getHeight();
int pixelColor;
synchronized (mPixelsLock) {
int len = width * height;
int[] pixels;
if (mRefPixels == null || mRefPixels.get() == null
|| mRefPixels.get().length < len) {
pixels = new int[len];
mRefPixels = new WeakReference<int[]>(pixels);
} else {
pixels = mRefPixels.get();
}
srcBmp.getPixels(pixels, 0, width, 0, 0, width, height);
// according alpha filter pixels
boolean flag1 = false;
boolean flag2 = false;
// or so close to
for (int i = 0; i < width / 2; i++) {
for (int j = 0; j < height; j++) {
int alpha;
if (!flag1) { // left edge
pixelColor = pixels[j * width + i];
alpha = Color.alpha(pixelColor);
if (alpha > MIN_VALID_ALPHA) {
result.rect.left = i;
flag1 = true;
}
}
if (!flag2) { // right edge
pixelColor = pixels[j * width + width - 1 - i];
alpha = Color.alpha(pixelColor);
if (alpha > MIN_VALID_ALPHA) {
// -1: in pure color round picture is cut
result.rect.right = width - i;
flag2 = true;
}
}
}
if (flag1 && flag2) {
break;
}
}
flag1 = false;
flag2 = false;
// upper and lower approximation
for (int j = 0; j < height / 2; j++) {
for (int i = 0; i < width; i++) {
int alpha;
if (!flag1) { // top edge
pixelColor = pixels[j * width + i];
alpha = Color.alpha(pixelColor);
if (alpha > MIN_VALID_ALPHA) {
result.rect.top = j;
flag1 = true;
}
}
if (!flag2) { // bottom edge
pixelColor = pixels[(height - j - 1) * width + i];
alpha = Color.alpha(pixelColor);
if (alpha > MIN_VALID_ALPHA) {
result.rect.bottom = height - j;
flag2 = true;
}
}
}
if (flag1 && flag2) {
break;
}
}
int pixelNum = 0;
int rectWidth = result.rect.width();
// int rectHeight = result.rect.height();
// Log.e("hlx", "rectWidth = " + rectWidth + "; rectHeight = " + rectHeight);
for (int j = result.rect.top; j < result.rect.bottom; j++) {
for (int i = result.rect.left; i < result.rect.right; i++) {
pixelColor = pixels[j * rectWidth + i];
if (pixelColor != 0) {
int alpha = Color.alpha(pixelColor);
pixels[j * rectWidth + i] = alpha;
if (pixels[j * rectWidth + i] > 178) {
pixelNum++;
}
}
}
}
float scale = (float) result.rect.width() / result.rect.height();
float availability = (float) pixelNum
/ (result.rect.width() * result.rect.height());
result.isSquare = (scale >= 0.8f && scale <= 1.25f)
&& availability >= 0.93f;
}
// long afterTime = System.currentTimeMillis();
// Log.e("hlx", "intervelTime two = " + (afterTime - beforeTime));
return result;
}
public static IconAnalyzedResult analyzeBitmap2(Bitmap srcBmp) {
final IconAnalyzedResult result = new IconAnalyzedResult();
final int width = srcBmp.getWidth();
final int height = srcBmp.getHeight();
int pixelColor;
synchronized (mPixelsLock) {
int len = width * height;
int[] pixels;
if (mRefPixels == null || mRefPixels.get() == null
|| mRefPixels.get().length < len) {
pixels = new int[len];
mRefPixels = new WeakReference<int[]>(pixels);
} else {
pixels = mRefPixels.get();
}
srcBmp.getPixels(pixels, 0, width, 0, 0, width, height);
// according alpha filter pixels
boolean flag1 = false;
boolean flag2 = false;
// or so close to
for (int i = 0; i < width / 2; i++) {
for (int j = 0; j < height; j++) {
int alpha;
if (!flag1) { // left edge
pixelColor = pixels[j * width + i];
alpha = Color.alpha(pixelColor);
if (alpha > MIN_VALID_ALPHA) {
result.rect.left = i;
flag1 = true;
}
}
if (!flag2) { // right edge
pixelColor = pixels[j * width + width - 1 - i];
alpha = Color.alpha(pixelColor);
if (alpha > MIN_VALID_ALPHA) {
// -1: in pure color round picture is cut
result.rect.right = width - i;
flag2 = true;
}
}
}
if (flag1 && flag2) {
break;
}
}
flag1 = false;
flag2 = false;
// upper and lower approximation
for (int j = 0; j < height / 2; j++) {
for (int i = 0; i < width; i++) {
int alpha;
if (!flag1) { // top edge
pixelColor = pixels[j * width + i];
alpha = Color.alpha(pixelColor);
if (alpha > MIN_VALID_ALPHA) {
result.rect.top = j;
flag1 = true;
}
}
if (!flag2) { // bottom edge
pixelColor = pixels[(height - j - 1) * width + i];
alpha = Color.alpha(pixelColor);
if (alpha > MIN_VALID_ALPHA) {
result.rect.bottom = height - j;
flag2 = true;
}
}
}
if (flag1 && flag2) {
break;
}
}
}
return result;
}
public static Bitmap processOrdinaryIcon(Context context, Bitmap src, Bitmap dst,
boolean preprocess, IconAnalyzedResult analyzedResult,
boolean needIconLayer, BitmapFactory.Options options) {
if (src == null || src.isRecycled()) {
return null;
}
// check input dst bitmap whether we can reuse
Bitmap res = null;
// reuse the bitmap must be app_icon_content_size
// 204px
int outerSize = TWS_ICON_SIZE_FRAME;
int iconSize = outerSize;
if (options != null && options.inSampleSize > 1) {
iconSize = outerSize / options.inSampleSize;
}
if (dst != null && dst.isMutable() && !dst.isRecycled() && dst.getWidth() == outerSize) {
dst.eraseColor(Color.TRANSPARENT);
res = dst;
} else {
if (iconSize != 0) {
res = createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
// return res;
}
}
if (outerSize != 0 && res != null) {
int shadowHeight = (int) (0 * iconSize / (float) outerSize);
// analysis of srcBitmap(background,shape)
Canvas canvas = new Canvas(res);
Paint paint = new Paint(DEFAULT_PAINT_FLAGS);
int innerSize = TWS_ICON_SIZE_SQUARE;
if (analyzedResult.isSquare && preprocess) {
float a = getScreenDensity(context);
// innerSize = innerSize + (int) (2 * getScreenDensity());
innerSize = (int) (innerSize * iconSize / (float) outerSize);
RectF desRect = scaleInnerIcon(innerSize, analyzedResult);
float width = desRect.width();
float height = desRect.height();
desRect.offset((iconSize - desRect.width()) / 2,
(iconSize - desRect.height() - shadowHeight) / 2);
canvas.drawBitmap(src, analyzedResult.rect, desRect, paint);
} else {
// old drawable is not a rectangle need add mask
// first to draw the base of color(on the basis of BitmapAnalyzedResult)
// this num order to random get background drawable
int num = 6;
mRect.set(0, 0, iconSize, iconSize);
// bruce modify if (num > 0) to false
if (num > 0) {
// get icon the background
// Bitmap bg = getIconBackground(key, num);
// if (bg != null) {
// canvas.drawBitmap(bg, null, mRect, paint);
// }
}
// picture drawing draw the inner box,auto adapt the innersize
int scale = 100;
int dy = 0;
innerSize = TWS_ICON_SIZE_NOT_SQUARE;
innerSize = (int) (innerSize * ((float) scale) / 100 * iconSize / outerSize);
RectF desRect = scaleInnerIcon(innerSize, analyzedResult);
float width1 = desRect.width();
float height1 = desRect.height();
desRect.offset((iconSize - desRect.width()) / 2,
(iconSize - desRect.height() - shadowHeight) / 2 - dy);
canvas.drawBitmap(src, analyzedResult.rect, desRect, paint);
}
}
return res;
}
public static Bitmap createBitmap(int width, int height, Config config) {
if (width <= 0 || height <= 0) {
return null;
}
try {
if (config != null) {
return Bitmap.createBitmap(width, height, config);
} else {
return Bitmap.createBitmap(width, height, Config.ARGB_8888);
}
} catch (OutOfMemoryError ex) {
return null;
}
}
public static float getScreenDensity(Context context) {
int widthPixels = 0;
android.view.WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
if (manager != null) {
DisplayMetrics dm = new DisplayMetrics();
Display display = manager.getDefaultDisplay();
if (display != null) {
manager.getDefaultDisplay().getMetrics(dm);
widthPixels = dm.widthPixels;
float originDensity = dm.density;
float adaptDensity = 0;
if(widthPixels >= WIDTH_XXH) {
adaptDensity = DENSITY_XXH;
} else if(widthPixels >= WIDTH_XH) {
adaptDensity = DENSITY_XH;
} else if(widthPixels >= WIDTH_H) {
adaptDensity = DENSITY_H;
}
return originDensity > adaptDensity ? originDensity : adaptDensity;
}
}
return 0;
}
public static RectF scaleInnerIcon(int size, IconAnalyzedResult result) {
RectF rect;
// calculate
float scale = (float) result.rect.width() / result.rect.height();
scale = scale > 1 ? 1 / scale : scale;
if (result.isSquare) {
// create rect
if (result.rect.width() > result.rect.height()) {
rect = new RectF(0, 0, size / scale, size);
} else {
rect = new RectF(0, 0, size, size / scale);
}
} else {
// create rect
if (result.rect.width() > result.rect.height()) {
rect = new RectF(0, 0, size, size*scale);
} else {
rect = new RectF(0, 0, size * scale, size);
}
}
return rect;
}
public static void blendIconLayer(Canvas canvas, Rect desRect, Paint paint,
Bitmap mask, Bitmap shadow) {
if (mask != null) {
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
canvas.drawBitmap(mask, null, desRect, paint);
paint.setXfermode(null);
}
if (shadow != null) {
canvas.drawBitmap(shadow, null, desRect, paint);
}
}
public static class IconAnalyzedResult {
public Rect rect = new Rect(0, 0, 0, 0);
public boolean isSquare = false;
}
}