diff --git a/core/java/com/android/internal/graphics/palette/Mean.java b/core/java/com/android/internal/graphics/palette/Mean.java index 894f91b6261c1..bde036349d3b9 100644 --- a/core/java/com/android/internal/graphics/palette/Mean.java +++ b/core/java/com/android/internal/graphics/palette/Mean.java @@ -22,20 +22,19 @@ import java.util.Random; * Represents a centroid in Kmeans algorithms. */ public class Mean { - private static final Random RANDOM = new Random(0); - public float[] center; /** * Constructor. * * @param upperBound maximum value of a dimension in the space Kmeans is optimizing in + * @param random used to generate a random center */ - Mean(int upperBound) { + Mean(int upperBound, Random random) { center = new float[]{ - RANDOM.nextInt(upperBound + 1), RANDOM.nextInt(upperBound + 1), - RANDOM.nextInt(upperBound + 1) + random.nextInt(upperBound + 1), random.nextInt(upperBound + 1), + random.nextInt(upperBound + 1) }; } diff --git a/core/java/com/android/internal/graphics/palette/WSMeansQuantizer.java b/core/java/com/android/internal/graphics/palette/WSMeansQuantizer.java index a87a34f4ae110..b4f216ba87fa6 100644 --- a/core/java/com/android/internal/graphics/palette/WSMeansQuantizer.java +++ b/core/java/com/android/internal/graphics/palette/WSMeansQuantizer.java @@ -22,6 +22,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Random; import java.util.Set; @@ -57,13 +58,27 @@ public class WSMeansQuantizer implements Quantizer { } if (maxColors > means.length) { + // Always initialize Random with the same seed. Ensures the results of quantization + // are consistent, even when random centroids are required. + Random random = new Random(0x42688); int randomMeansToCreate = maxColors - means.length; for (int i = 0; i < randomMeansToCreate; i++) { - mMeans[means.length + i] = new Mean(100); + mMeans[means.length + i] = new Mean(100, random); } } for (int pixel : pixels) { + // These are pixels from the bitmap that is being quantized. + // Depending on the bitmap & downscaling, it may have pixels that are less than opaque + // Ignore those pixels. + /// + // Note: they don't _have_ to be ignored, for example, we could instead turn them + // opaque. Traditionally, including outside Android, quantizers ignore transparent + // pixels, so that strategy was chosen. + int alpha = (pixel >> 24); + if (alpha < 255) { + continue; + } Integer currentCount = mCountByColor.get(pixel); if (currentCount == null) { currentCount = 0; @@ -105,8 +120,12 @@ public class WSMeansQuantizer implements Quantizer { /** Create random starting centroids for K-means. */ public static float[][] randomMeans(int maxColors, int upperBound) { float[][] means = new float[maxColors][]; + + // Always initialize Random with the same seed. Ensures the results of quantization + // are consistent, even when random centroids are required. + Random random = new Random(0x42688); for (int i = 0; i < maxColors; i++) { - means[i] = new Mean(upperBound).center; + means[i] = new Mean(upperBound, random).center; } return means; } diff --git a/core/java/com/android/internal/graphics/palette/WuQuantizer.java b/core/java/com/android/internal/graphics/palette/WuQuantizer.java index 66206bf8297a4..a2652ea6d5e1a 100644 --- a/core/java/com/android/internal/graphics/palette/WuQuantizer.java +++ b/core/java/com/android/internal/graphics/palette/WuQuantizer.java @@ -78,7 +78,12 @@ public class WuQuantizer implements Quantizer { // All of the sample Wu implementations are reimplementations of a snippet of C code from // the early 90s. They all cap the maximum # of colors at 256, and it is impossible to tell // if this is a requirement, a consequence of QUANT_SIZE, or arbitrary. - this.mMaxColors = Math.min(MAX_COLORS, maxColorCount); + // + // Also, the number of maximum colors should be capped at the number of pixels - otherwise, + // If extraction is run on a set of pixels whose count is less than max colors, + // then colors.length < max colors, and accesses to colors[index] throw an + // ArrayOutOfBoundsException. + this.mMaxColors = Math.min(Math.min(MAX_COLORS, maxColorCount), colors.length); Box[] cube = new Box[mMaxColors]; int red, green, blue; @@ -119,17 +124,13 @@ public class WuQuantizer implements Quantizer { } } - // If extraction is run on a set of pixels whose count is less than the - // number of max colors, then colors.length < max colors, and accesses - // to colors[index] inside the for loop throw an ArrayOutOfBoundsException. - int numColorsToCreate = (int) Math.min(mMaxColors, colors.length); - for (k = 0; k < numColorsToCreate; ++k) { + for (k = 0; k < mMaxColors; ++k) { weight = getVolume(cube[k], mWt); if (weight > 0) { red = (int) (getVolume(cube[k], mMr) / weight); green = (int) (getVolume(cube[k], mMg) / weight); blue = (int) (getVolume(cube[k], mMb) / weight); - colors[k] = ((red & 0x0ff) << 16) | ((green & 0x0ff) << 8) | (blue & 0x0ff); + colors[k] = (255 << 24) | (red << 16) | (green << 8) | blue; } else { colors[k] = 0; }