blob: 0d2f2e2245b19a0695a89578f56758a14469a5d2 [file] [log] [blame]
/*
* Copyright (C) 2014 The Android Open Source Project
*
* 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.android.contacts.quickcontact;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.Trace;
/**
* Utility class for determining whether Bitmaps contain a lot of white pixels in locations
* where QuickContactActivity will want to place white text or buttons.
*
* This class liberally considers bitmaps white. All constants are chosen with a small amount of
* experimentation. Despite a lack of rigour, this class successfully allows QuickContactsActivity
* to detect when Bitmap are obviously *not* white. Therefore, it is better than nothing.
*/
public class WhitenessUtils {
/**
* Analyze this amount of the top and bottom of the bitmap.
*/
private static final float HEIGHT_PERCENT_ANALYZED = 0.2f;
/**
* An image with more than this amount white, is considered to be a whitish image.
*/
private static final float PROPORTION_WHITE_CUTOFF = 0.1f;
private static final float THIRD = 0.33f;
/**
* Colors with luma greater than this are considered close to white. This value is lower than
* the value used in Palette's ColorUtils, since we want to liberally declare images white.
*/
private static final float LUMINANCE_OF_WHITE = 0.90f;
/**
* Returns true if 20% of the image's top right corner is white, or 20% of the bottom
* of the image is white.
*/
public static boolean isBitmapWhiteAtTopOrBottom(Bitmap largeBitmap) {
Trace.beginSection("isBitmapWhiteAtTopOrBottom");
try {
final Bitmap smallBitmap = scaleBitmapDown(largeBitmap);
final int[] rgbPixels = new int[smallBitmap.getWidth() * smallBitmap.getHeight()];
smallBitmap.getPixels(rgbPixels, 0, smallBitmap.getWidth(), 0, 0,
smallBitmap.getWidth(), smallBitmap.getHeight());
// look at top right corner of the bitmap
int whiteCount = 0;
for (int y = 0; y < smallBitmap.getHeight() * HEIGHT_PERCENT_ANALYZED; y++) {
for (int x = (int) (smallBitmap.getWidth() * (1 - THIRD));
x < smallBitmap.getWidth(); x++) {
final int rgb = rgbPixels[y * smallBitmap.getWidth() + x];
if (isWhite(rgb)) {
whiteCount ++;
}
}
}
int totalPixels = (int) (smallBitmap.getHeight() * smallBitmap.getWidth()
* THIRD * HEIGHT_PERCENT_ANALYZED);
if (whiteCount / (float) totalPixels > PROPORTION_WHITE_CUTOFF) {
return true;
}
// look at bottom portion of bitmap
whiteCount = 0;
for (int y = (int) (smallBitmap.getHeight() * (1 - HEIGHT_PERCENT_ANALYZED));
y < smallBitmap.getHeight(); y++) {
for (int x = 0; x < smallBitmap.getWidth(); x++) {
final int rgb = rgbPixels[y * smallBitmap.getWidth() + x];
if (isWhite(rgb)) {
whiteCount ++;
}
}
}
totalPixels = (int) (smallBitmap.getHeight()
* smallBitmap.getWidth() * HEIGHT_PERCENT_ANALYZED);
return whiteCount / (float) totalPixels > PROPORTION_WHITE_CUTOFF;
} finally {
Trace.endSection();
}
}
private static boolean isWhite(int rgb) {
return calculateXyzLuma(rgb) > LUMINANCE_OF_WHITE;
}
private static float calculateXyzLuma(int rgb) {
return (0.2126f * Color.red(rgb) +
0.7152f * Color.green(rgb) +
0.0722f * Color.blue(rgb)) / 255f;
}
/**
* Scale down the bitmap in order to make color analysis faster. Taken from Palette.
*/
private static Bitmap scaleBitmapDown(Bitmap bitmap) {
final int CALCULATE_BITMAP_MIN_DIMENSION = 100;
final int minDimension = Math.min(bitmap.getWidth(), bitmap.getHeight());
if (minDimension <= CALCULATE_BITMAP_MIN_DIMENSION) {
// If the bitmap is small enough already, just return it
return bitmap;
}
final float scaleRatio = CALCULATE_BITMAP_MIN_DIMENSION / (float) minDimension;
return Bitmap.createScaledBitmap(bitmap,
Math.round(bitmap.getWidth() * scaleRatio),
Math.round(bitmap.getHeight() * scaleRatio),
false);
}
}