@@ -17,13 +17,9 @@ data class Histogram(
1717 val spread : Map <Color , Amount >
1818)
1919
20- val Histogram .colors : Set <Color >
20+ val Histogram .colors: Set <Color >
2121 get() = spread.keys
2222
23- fun Histogram.hasAlpha (): Boolean = colors.firstOrNull {
24- it.alpha < 0xff
25- } != null
26-
2723fun Bitmap.colorHistogram (): Histogram {
2824 // all colors
2925 val result = mutableMapOf<Color , Amount >()
@@ -45,21 +41,29 @@ fun Bitmap.colorHistogram(): Histogram {
4541}
4642
4743fun Bitmap.reduceColors (maxColorCounts : Int ): Pair <Bitmap , Histogram > {
48- var histogram = colorHistogram().mergeSimilarColors().removeLowCounts()
49- val hasAlpha = histogram.hasAlpha()
50- val desiredColorCount = (if (hasAlpha) 1 else 0 ) + maxColorCounts
44+ val minDistance = 25
45+ var histogram =
46+ colorHistogram()
47+ .mergeSimilarColors(maxColorCounts, minDistance)
48+ .removeLowCounts(maxColorCounts, minDistance)
5149
5250 var maxTries = 3
53- while (histogram.colors.size > desiredColorCount && maxTries > 0 ) {
54- histogram = histogram.mergeSimilarColors().removeLowCounts()
51+ while (histogram.colors.size > maxColorCounts && maxTries > 0 ) {
52+ histogram = histogram
53+ .mergeSimilarColors(maxColorCounts, minDistance)
54+ .removeLowCounts(maxColorCounts, minDistance)
5555 maxTries--
5656 }
5757
5858 maxTries = 3
5959 var currentDistance = 50
60+
6061 // reduce more aggressively
61- while (histogram.colors.size > desiredColorCount && maxTries > 0 ) {
62- histogram = histogram.mergeSimilarColors(currentDistance).removeLowCounts()
62+ while (histogram.colors.size > maxColorCounts && maxTries > 0 ) {
63+ histogram = histogram
64+ .mergeSimilarColors(maxColorCounts, currentDistance)
65+ .removeLowCounts(maxColorCounts, currentDistance)
66+
6367 currentDistance = (currentDistance * 1.25f ).toInt()
6468 maxTries--
6569 } // todo if not reject and give up
@@ -69,7 +73,7 @@ fun Bitmap.reduceColors(maxColorCounts: Int): Pair<Bitmap, Histogram> {
6973 .spread
7074 .toList()
7175 .sortedByDescending { it.second }
72- .take(desiredColorCount )
76+ .take(maxColorCounts )
7377 .toMap()
7478 )
7579
@@ -86,7 +90,11 @@ fun Bitmap.reduceColors(maxColorCounts: Int): Pair<Bitmap, Histogram> {
8690 return result to histogram
8791}
8892
89- fun Histogram.mergeSimilarColors (distance : Int = 25): Histogram {
93+ fun Histogram.mergeSimilarColors (maxColorCounts : Int , distance : Int ): Histogram {
94+ if (spread.size <= maxColorCounts) {
95+ return this
96+ }
97+
9098 val result = mutableMapOf<Color , Amount >()
9199
92100 for (e in spread) {
@@ -109,7 +117,11 @@ fun Histogram.mergeSimilarColors(distance: Int = 25): Histogram {
109117 return Histogram (result)
110118}
111119
112- fun Histogram.removeLowCounts (threshold : Int = 25): Histogram {
120+ fun Histogram.removeLowCounts (maxColorCounts : Int , threshold : Int ): Histogram {
121+ if (spread.size <= maxColorCounts) {
122+ return this
123+ }
124+
113125 val result = mutableMapOf<Color , Amount >()
114126 var removedCount = 0
115127
@@ -143,27 +155,21 @@ private fun IntArray.filteredBy(targetPixels: List<Int>): IntArray {
143155}
144156
145157private fun distance (a : Int , b : Int ): Float {
146- val aA = a.alpha
158+ val aR = a.red
159+ val aG = a.green
160+ val aB = a.blue
147161
148- return if (aA < 0xff ) {
149- 0f
150- } else {
151- val aR = a.red
152- val aG = a.green
153- val aB = a.blue
162+ val aLAB = DoubleArray (3 )
163+ RGBToLAB (aR, aG, aB, aLAB)
154164
155- val aLAB = DoubleArray (3 )
156- RGBToLAB (aR, aG, aB, aLAB)
165+ val bR = b.red
166+ val bG = b.green
167+ val bB = b.blue
157168
158- val bR = b.red
159- val bG = b.green
160- val bB = b.blue
169+ val bLAB = DoubleArray (3 )
170+ RGBToLAB (bR, bG, bB, bLAB)
161171
162- val bLAB = DoubleArray (3 )
163- RGBToLAB (bR, bG, bB, bLAB)
164-
165- ColorUtils .distanceEuclidean(aLAB, bLAB).toFloat()
166- }
172+ return ColorUtils .distanceEuclidean(aLAB, bLAB).toFloat()
167173}
168174
169175
0 commit comments