功能描述:制作一个应用列表,每个元素如下,内圈是应用的图标,外圈大的圆角长方形作为背景。需要根据应用图标,获取主要的颜色来设置背景色。
获取图标主要颜色的算法,网上很多,获取图标的bitmap,遍历统计数量,如下:
private static int getMainColor(Drawable dra) throws IOException {
Bitmap bitmap = drawable2Bitmap(dra);
int dominantColor;
int maxCount = 0;
// 用于存储颜色计数
HashMap<Integer, Integer> colorCount = new HashMap<>();
// 遍历图片中的每个像素
for (int y = 0; y < bitmap.getHeight(); y++) {
for (int x = 0; x < bitmap.getWidth(); x++) {
int pixelColor = bitmap.getPixel(x, y);
int red = Color.red(pixelColor);
int green = Color.green(pixelColor);
int blue = Color.blue(pixelColor);
// 将颜色转换为一个整数
int color = Color.argb(255, red, green, blue);
// 更新颜色计数
//noinspection DataFlowIssue
int count = colorCount.containsKey(color) ? colorCount.get(color) + 1 : 1;
colorCount.put(color, count);
}
}
// 保存最大的staticCnt个计数
for (Map.Entry<Integer, Integer> entry : colorCount.entrySet()) {
int color = entry.getKey();
int count = entry.getValue();
// Log.d(TAG, "---color = " + color + ", count = " + count);
if (maxCount < count) {
maxCount = count;
dominantColor = color;
}
}
return dominantColor;
}
但这样的算法会出现非预期的白色或黑色背景:
原因是这些图标统计下来,白色或黑色就是最多的颜色。通过分析数据,可以看到第二多的颜色与最多的颜色在数量上相差不大。所以需要增加些处理场景。
制定几个基本原则,一般白色不作为背景色,其次是黑色也不太会考虑,对于多种颜色在数量上相近的情况(非白黑),取一个平均值。
算法调整如下:
1、统计前三种最多的颜色,因为最极端情况,就是白色、黑色,还有一个其他颜色。
2、针对白色最多的场景,对后两种颜色取平均值。
3、第二多的颜色为白色,如果第一多为黑色,取第三多的颜色,如果第三多的颜色不存在,则对白色和黑色取均值;如果第一多不为黑色,取第一多的颜色。
4、如果后一种颜色的数量,相比前一种,相差一个数量级以上,则舍去。
5、三种最多的颜色,非黑非白,数量相差不多,取平均值。
private static int getMainColor(Drawable dra) throws IOException {
Bitmap bitmap = drawable2Bitmap(dra);
int staticCnt = 3;
int[] dominantColor = new int[staticCnt];
Arrays.fill(dominantColor, Color.TRANSPARENT);
int[] maxCount = new int[staticCnt];
Arrays.fill(maxCount, 0);
// 用于存储颜色计数
HashMap<Integer, Integer> colorCount = new HashMap<>();
// 遍历图片中的每个像素
for (int y = 0; y < bitmap.getHeight(); y++) {
for (int x = 0; x < bitmap.getWidth(); x++) {
int pixelColor = bitmap.getPixel(x, y);
int red = Color.red(pixelColor);
int green = Color.green(pixelColor);
int blue = Color.blue(pixelColor);
// 将颜色转换为一个整数
int color = Color.argb(255, red, green, blue);
// 更新颜色计数
//noinspection DataFlowIssue
int count = colorCount.containsKey(color) ? colorCount.get(color) + 1 : 1;
colorCount.put(color, count);
}
}
// 保存最大的staticCnt个计数
for (Map.Entry<Integer, Integer> entry : colorCount.entrySet()) {
int color = entry.getKey();
int count = entry.getValue();
// Log.d(TAG, "---color = " + color + ", count = " + count);
// 插入排序
for (int j = 0; j < staticCnt; j++) {
if (maxCount[j] < count) {
for (int k = staticCnt - 1; k >= j + 1; k--) {
maxCount[k] = maxCount[k - 1];
dominantColor[k] = dominantColor[k - 1];
}
maxCount[j] = count;
dominantColor[j] = color;
break;
}
}
}
StringBuilder out = new StringBuilder("---" + bitmap.getHeight() + "X" + bitmap.getWidth() + ":");
for (int i = 0; i < staticCnt; i++) {
out.append(" color: ").append(dominantColor[i]).append(" count: ").append(maxCount[i]);
}
Log.d(TAG, out.toString());
// color为-1是白色,((dominantColor[k] % 0x1000000) == 0x000000)是黑色
if (dominantColor[1] == -1) { // 第二多的颜色为白色
if ((dominantColor[0] % 0x1000000) == 0x000000) { // 第一多的颜色为黑色
// 如果第三个颜色存在,直接返回,否则对前两个颜色取均值
return dominantColor[2] != 0 ? dominantColor[2] : (dominantColor[0] + dominantColor[1]) / 2;
}
return dominantColor[0]; // 第一多的颜色不为黑色,直接返回
}
if (dominantColor[0] == -1) { // 第一多的颜色为白色,对后面的颜色取均值
for (int i = 1; i < staticCnt; i++) {
dominantColor[i - 1] = dominantColor[i];
maxCount[i - 1] = maxCount[i];
}
staticCnt -= 1;
}
int ratio = 20;
int ret = 0;
int rCnt = 0;
for (int k = 0; k < staticCnt; k++) {
if (dominantColor[k] == 0) {
continue;
}
if (ret != 0 && maxCount[k - 1] > maxCount[k] * ratio) {
break;
}
ret += dominantColor[k];
rCnt++;
}
int last = rCnt > 0 ? ret / rCnt : dominantColor[0];
Log.d(TAG, "---last: " + last + " rCnt: " + rCnt);
return last;
}
整体效果: