Merge "Add filter API to Palette" into lmp-mr1-ub-dev
diff --git a/v7/palette/api/current.txt b/v7/palette/api/current.txt
index d92c0dd..1b6c745 100644
--- a/v7/palette/api/current.txt
+++ b/v7/palette/api/current.txt
@@ -25,12 +25,18 @@
public static final class Palette.Builder {
ctor public Palette.Builder(android.graphics.Bitmap);
ctor public Palette.Builder(java.util.List<android.support.v7.graphics.Palette.Swatch>);
+ method public android.support.v7.graphics.Palette.Builder addFilter(android.support.v7.graphics.Palette.Filter);
+ method public android.support.v7.graphics.Palette.Builder clearFilters();
method public android.support.v7.graphics.Palette generate();
method public android.os.AsyncTask<android.graphics.Bitmap, java.lang.Void, android.support.v7.graphics.Palette> generate(android.support.v7.graphics.Palette.PaletteAsyncListener);
method public android.support.v7.graphics.Palette.Builder maximumColorCount(int);
method public android.support.v7.graphics.Palette.Builder resizeBitmapSize(int);
}
+ public static abstract interface Palette.Filter {
+ method public abstract boolean isAllowed(int, float[]);
+ }
+
public static abstract interface Palette.PaletteAsyncListener {
method public abstract void onGenerated(android.support.v7.graphics.Palette);
}
diff --git a/v7/palette/src/main/java/android/support/v7/graphics/ColorCutQuantizer.java b/v7/palette/src/main/java/android/support/v7/graphics/ColorCutQuantizer.java
index 9355502..3b89748 100644
--- a/v7/palette/src/main/java/android/support/v7/graphics/ColorCutQuantizer.java
+++ b/v7/palette/src/main/java/android/support/v7/graphics/ColorCutQuantizer.java
@@ -16,7 +16,6 @@
package android.support.v7.graphics;
-import android.graphics.Bitmap;
import android.graphics.Color;
import android.support.v4.graphics.ColorUtils;
import android.support.v7.graphics.Palette.Swatch;
@@ -47,9 +46,6 @@
private static final String LOG_TAG = "ColorCutQuantizer";
private static final boolean LOG_TIMINGS = false;
- private static final float BLACK_MAX_LIGHTNESS = 0.05f;
- private static final float WHITE_MIN_LIGHTNESS = 0.95f;
-
private static final int COMPONENT_RED = -3;
private static final int COMPONENT_GREEN = -2;
private static final int COMPONENT_BLUE = -1;
@@ -61,33 +57,20 @@
final int[] mHistogram;
final List<Swatch> mQuantizedColors;
final TimingLogger mTimingLogger;
+ final Palette.Filter[] mFilters;
private final float[] mTempHsl = new float[3];
/**
- * Factory-method to generate a {@link ColorCutQuantizer} from a {@link Bitmap} object.
- *
- * @param bitmap Bitmap to extract the pixel data from
- * @param maxColors The maximum number of colors that should be in the result palette.
- */
- static ColorCutQuantizer fromBitmap(Bitmap bitmap, int maxColors) {
- final int width = bitmap.getWidth();
- final int height = bitmap.getHeight();
-
- final int[] pixels = new int[width * height];
- bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
-
- return new ColorCutQuantizer(pixels, maxColors);
- }
-
- /**
- * Private constructor.
+ * Constructor.
*
* @param pixels histogram representing an image's pixel data
* @param maxColors The maximum number of colors that should be in the result palette.
+ * @param filters Set of filters to use in the quantization stage
*/
- private ColorCutQuantizer(final int[] pixels, final int maxColors) {
+ ColorCutQuantizer(final int[] pixels, final int maxColors, final Palette.Filter[] filters) {
mTimingLogger = LOG_TIMINGS ? new TimingLogger(LOG_TAG, "Creation") : null;
+ mFilters = filters;
final int[] hist = mHistogram = new int[1 << (QUANTIZE_WORD_WIDTH * 3)];
for (int i = 0; i < pixels.length; i++) {
@@ -443,37 +426,24 @@
}
private boolean shouldIgnoreColor(int color565) {
- ColorUtils.colorToHSL(approximateToRgb888(color565), mTempHsl);
- return shouldIgnoreColor(mTempHsl);
+ final int rgb = approximateToRgb888(color565);
+ ColorUtils.colorToHSL(rgb, mTempHsl);
+ return shouldIgnoreColor(rgb, mTempHsl);
}
- private static boolean shouldIgnoreColor(Swatch color) {
- return shouldIgnoreColor(color.getHsl());
+ private boolean shouldIgnoreColor(Swatch color) {
+ return shouldIgnoreColor(color.getRgb(), color.getHsl());
}
- private static boolean shouldIgnoreColor(float[] hslColor) {
- return isWhite(hslColor) || isBlack(hslColor) || isNearRedILine(hslColor);
- }
-
- /**
- * @return true if the color represents a color which is close to black.
- */
- private static boolean isBlack(float[] hslColor) {
- return hslColor[2] <= BLACK_MAX_LIGHTNESS;
- }
-
- /**
- * @return true if the color represents a color which is close to white.
- */
- private static boolean isWhite(float[] hslColor) {
- return hslColor[2] >= WHITE_MIN_LIGHTNESS;
- }
-
- /**
- * @return true if the color lies close to the red side of the I line.
- */
- private static boolean isNearRedILine(float[] hslColor) {
- return hslColor[0] >= 10f && hslColor[0] <= 37f && hslColor[1] <= 0.82f;
+ private boolean shouldIgnoreColor(int rgb, float[] hsl) {
+ if (mFilters != null && mFilters.length > 0) {
+ for (int i = 0, count = mFilters.length; i < count; i++) {
+ if (!mFilters[i].isAllowed(rgb, hsl)) {
+ return true;
+ }
+ }
+ }
+ return false;
}
/**
diff --git a/v7/palette/src/main/java/android/support/v7/graphics/Palette.java b/v7/palette/src/main/java/android/support/v7/graphics/Palette.java
index 7a4e7ee..c3f3e78 100644
--- a/v7/palette/src/main/java/android/support/v7/graphics/Palette.java
+++ b/v7/palette/src/main/java/android/support/v7/graphics/Palette.java
@@ -23,6 +23,7 @@
import android.support.v4.os.AsyncTaskCompat;
import android.util.TimingLogger;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -427,6 +428,7 @@
private Bitmap mBitmap;
private int mMaxColors = DEFAULT_CALCULATE_NUMBER_COLORS;
private int mResizeMaxDimension = DEFAULT_RESIZE_BITMAP_MAX_DIMENSION;
+ private final List<Filter> mFilters = new ArrayList<>();
private Generator mGenerator;
@@ -434,6 +436,7 @@
* Construct a new {@link Builder} using a source {@link Bitmap}
*/
public Builder(Bitmap bitmap) {
+ this();
if (bitmap == null || bitmap.isRecycled()) {
throw new IllegalArgumentException("Bitmap is not valid");
}
@@ -445,12 +448,17 @@
* Typically only used for testing.
*/
public Builder(List<Swatch> swatches) {
+ this();
if (swatches == null || swatches.isEmpty()) {
throw new IllegalArgumentException("List of Swatches is not valid");
}
mSwatches = swatches;
}
+ private Builder() {
+ mFilters.add(DEFAULT_FILTER);
+ }
+
/**
* Set the {@link Generator} to use when generating the {@link Palette}. If this is called
* with {@code null} then the default generator will be used.
@@ -489,6 +497,28 @@
}
/**
+ * Clear all added filters. This includes any default filters added automatically by
+ * {@link Palette}.
+ */
+ public Builder clearFilters() {
+ mFilters.clear();
+ return this;
+ }
+
+ /**
+ * Add a filter to be able to have fine grained controlled over the colors which are
+ * allowed in the resulting palette.
+ *
+ * @param filter filter to add.
+ */
+ public Builder addFilter(Filter filter) {
+ if (filter != null) {
+ mFilters.add(filter);
+ }
+ return this;
+ }
+
+ /**
* Generate and return the {@link Palette} synchronously.
*/
public Palette generate() {
@@ -514,8 +544,13 @@
}
// Now generate a quantizer from the Bitmap
- ColorCutQuantizer quantizer = ColorCutQuantizer
- .fromBitmap(scaledBitmap, mMaxColors);
+ final int width = scaledBitmap.getWidth();
+ final int height = scaledBitmap.getHeight();
+ final int[] pixels = new int[width * height];
+ scaledBitmap.getPixels(pixels, 0, width, 0, 0, width, height);
+
+ final ColorCutQuantizer quantizer = new ColorCutQuantizer(pixels, mMaxColors,
+ mFilters.isEmpty() ? null : mFilters.toArray(new Filter[mFilters.size()]));
// If created a new bitmap, recycle it
if (scaledBitmap != mBitmap) {
@@ -633,4 +668,55 @@
}
}
+ /**
+ * A Filter provides a mechanism for exercising fine-grained control over which colors
+ * are valid within a resulting {@link Palette}.
+ */
+ public interface Filter {
+ /**
+ * Hook to allow clients to be able filter colors from resulting palette.
+ *
+ * @param rgb the color in RGB888.
+ * @param hsl HSL representation of the color.
+ *
+ * @return true if the color is allowed, false if not.
+ *
+ * @see Builder#addFilter(Filter)
+ */
+ boolean isAllowed(int rgb, float[] hsl);
+ }
+
+ /**
+ * The default filter.
+ */
+ private static final Filter DEFAULT_FILTER = new Filter() {
+ private static final float BLACK_MAX_LIGHTNESS = 0.05f;
+ private static final float WHITE_MIN_LIGHTNESS = 0.95f;
+
+ @Override
+ public boolean isAllowed(int rgb, float[] hsl) {
+ return !isWhite(hsl) && !isBlack(hsl) && !isNearRedILine(hsl);
+ }
+
+ /**
+ * @return true if the color represents a color which is close to black.
+ */
+ private boolean isBlack(float[] hslColor) {
+ return hslColor[2] <= BLACK_MAX_LIGHTNESS;
+ }
+
+ /**
+ * @return true if the color represents a color which is close to white.
+ */
+ private boolean isWhite(float[] hslColor) {
+ return hslColor[2] >= WHITE_MIN_LIGHTNESS;
+ }
+
+ /**
+ * @return true if the color lies close to the red side of the I line.
+ */
+ private boolean isNearRedILine(float[] hslColor) {
+ return hslColor[0] >= 10f && hslColor[0] <= 37f && hslColor[1] <= 0.82f;
+ }
+ };
}