Reusing the same bitmap and pixel array for shape detection
Bug: 76162466 Change-Id: I785d9b8673b2b8b0a56a146143b375c412e9322a
This commit is contained in:
parent
c2c907edec
commit
2e4596a448
|
@ -780,7 +780,7 @@ public class IconCache {
|
|||
}
|
||||
|
||||
private static final class IconDB extends SQLiteCacheHelper {
|
||||
private final static int RELEASE_VERSION = 21;
|
||||
private final static int RELEASE_VERSION = 22;
|
||||
|
||||
private final static String TABLE_NAME = "icons";
|
||||
private final static String COLUMN_ROWID = "rowid";
|
||||
|
|
|
@ -24,6 +24,7 @@ import android.graphics.Matrix;
|
|||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuff.Mode;
|
||||
import android.graphics.PorterDuffXfermode;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
|
@ -66,12 +67,10 @@ public class IconNormalizer {
|
|||
|
||||
private final int mMaxSize;
|
||||
private final Bitmap mBitmap;
|
||||
private final Bitmap mBitmapARGB;
|
||||
private final Canvas mCanvas;
|
||||
private final Paint mPaintMaskShape;
|
||||
private final Paint mPaintMaskShapeOutline;
|
||||
private final byte[] mPixels;
|
||||
private final int[] mPixelsARGB;
|
||||
|
||||
private final Rect mAdaptiveIconBounds;
|
||||
private float mAdaptiveIconScale;
|
||||
|
@ -83,9 +82,6 @@ public class IconNormalizer {
|
|||
private final Path mShapePath;
|
||||
private final Matrix mMatrix;
|
||||
|
||||
private final Paint mPaintIcon;
|
||||
private final Canvas mCanvasARGB;
|
||||
|
||||
/** package private **/
|
||||
IconNormalizer(Context context) {
|
||||
// Use twice the icon size as maximum size to avoid scaling down twice.
|
||||
|
@ -93,19 +89,11 @@ public class IconNormalizer {
|
|||
mBitmap = Bitmap.createBitmap(mMaxSize, mMaxSize, Bitmap.Config.ALPHA_8);
|
||||
mCanvas = new Canvas(mBitmap);
|
||||
mPixels = new byte[mMaxSize * mMaxSize];
|
||||
mPixelsARGB = new int[mMaxSize * mMaxSize];
|
||||
mLeftBorder = new float[mMaxSize];
|
||||
mRightBorder = new float[mMaxSize];
|
||||
mBounds = new Rect();
|
||||
mAdaptiveIconBounds = new Rect();
|
||||
|
||||
// Needed for isShape() method
|
||||
mBitmapARGB = Bitmap.createBitmap(mMaxSize, mMaxSize, Bitmap.Config.ARGB_8888);
|
||||
mCanvasARGB = new Canvas(mBitmapARGB);
|
||||
|
||||
mPaintIcon = new Paint();
|
||||
mPaintIcon.setColor(Color.WHITE);
|
||||
|
||||
mPaintMaskShape = new Paint();
|
||||
mPaintMaskShape.setColor(Color.RED);
|
||||
mPaintMaskShape.setStyle(Paint.Style.FILL);
|
||||
|
@ -115,7 +103,7 @@ public class IconNormalizer {
|
|||
mPaintMaskShapeOutline.setStrokeWidth(2 * context.getResources().getDisplayMetrics().density);
|
||||
mPaintMaskShapeOutline.setStyle(Paint.Style.STROKE);
|
||||
mPaintMaskShapeOutline.setColor(Color.BLACK);
|
||||
mPaintMaskShapeOutline.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
|
||||
mPaintMaskShapeOutline.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
|
||||
|
||||
mShapePath = new Path();
|
||||
mMatrix = new Matrix();
|
||||
|
@ -141,8 +129,6 @@ public class IconNormalizer {
|
|||
// Condition 2:
|
||||
// Actual icon (white) and the fitted shape (e.g., circle)(red) XOR operation
|
||||
// should generate transparent image, if the actual icon is equivalent to the shape.
|
||||
mBitmapARGB.eraseColor(Color.TRANSPARENT);
|
||||
mCanvasARGB.drawBitmap(mBitmap, 0, 0, mPaintIcon);
|
||||
|
||||
// Fit the shape within the icon's bounding box
|
||||
mMatrix.reset();
|
||||
|
@ -151,31 +137,41 @@ public class IconNormalizer {
|
|||
maskPath.transform(mMatrix, mShapePath);
|
||||
|
||||
// XOR operation
|
||||
mCanvasARGB.drawPath(mShapePath, mPaintMaskShape);
|
||||
mCanvas.drawPath(mShapePath, mPaintMaskShape);
|
||||
|
||||
// DST_OUT operation around the mask path outline
|
||||
mCanvasARGB.drawPath(mShapePath, mPaintMaskShapeOutline);
|
||||
mCanvas.drawPath(mShapePath, mPaintMaskShapeOutline);
|
||||
|
||||
// Check if the result is almost transparent
|
||||
return isTransparentBitmap(mBitmapARGB);
|
||||
return isTransparentBitmap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to determine if certain the bitmap is transparent.
|
||||
*/
|
||||
private boolean isTransparentBitmap(Bitmap bitmap) {
|
||||
int w = mBounds.width();
|
||||
int h = mBounds.height();
|
||||
bitmap.getPixels(mPixelsARGB, 0 /* the first index to write into the array */,
|
||||
w /* stride */,
|
||||
mBounds.left, mBounds.top,
|
||||
w, h);
|
||||
private boolean isTransparentBitmap() {
|
||||
ByteBuffer buffer = ByteBuffer.wrap(mPixels);
|
||||
buffer.rewind();
|
||||
mBitmap.copyPixelsToBuffer(buffer);
|
||||
|
||||
int y = mBounds.top;
|
||||
// buffer position
|
||||
int index = y * mMaxSize;
|
||||
// buffer shift after every row, width of buffer = mMaxSize
|
||||
int rowSizeDiff = mMaxSize - mBounds.right;
|
||||
|
||||
int sum = 0;
|
||||
for (int i = w * h - 1; i >= 0; i--) {
|
||||
if(Color.alpha(mPixelsARGB[i]) > MIN_VISIBLE_ALPHA) {
|
||||
for (; y < mBounds.bottom; y++) {
|
||||
index += mBounds.left;
|
||||
for (int x = mBounds.left; x < mBounds.right; x++) {
|
||||
if ((mPixels[index] & 0xFF) > MIN_VISIBLE_ALPHA) {
|
||||
sum++;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
index += rowSizeDiff;
|
||||
}
|
||||
|
||||
float percentageDiffPixels = ((float) sum) / (mBounds.width() * mBounds.height());
|
||||
return percentageDiffPixels < PIXEL_DIFF_PERCENTAGE_THRESHOLD;
|
||||
}
|
||||
|
@ -306,7 +302,7 @@ public class IconNormalizer {
|
|||
mBounds.bottom = bottomY;
|
||||
|
||||
if (outBounds != null) {
|
||||
outBounds.set(((float) mBounds.left) / width, ((float) mBounds.top),
|
||||
outBounds.set(((float) mBounds.left) / width, ((float) mBounds.top) / height,
|
||||
1 - ((float) mBounds.right) / width,
|
||||
1 - ((float) mBounds.bottom) / height);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue