/* * 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 de.geeksfactory.opacclient.ui; import android.graphics.Bitmap; import android.graphics.Color; /** * Utility class for determining whether Bitmaps contain a lot of white pixels in locations where * QuickContactActivity will want to place white text or buttons. * <p/> * 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) { 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; } 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); } }