张罗欢 發表於 2025-10-22 11:21:00

氛围灯动态屏保取色方案二

<p><strong>hue查找:</strong>整体偏差不会很大,但是对于亮度较高存在误差,精准度不够</p>
<p><strong>lab查找:</strong>整体一般,但是精准度较好,不过算法复杂,增加耗时</p>
<p>hue色相查找存在误差,在有限的256色中,匹配的规则需要调整</p>
<p>这里使用lab算法提高精准度</p>
<h4>RGB转Lab</h4>
<div class="cnblogs_code"><img src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img id="code_img_opened_ddfb89f7-a904-471d-97ce-79dbfb7a3436" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_ddfb89f7-a904-471d-97ce-79dbfb7a3436" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 0, 1)">fun rGBToLab(r: Int, g: Int, b: Int): DoubleArray {
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 处理负值(如-2563864)</span>
      val labR = <span style="color: rgba(0, 0, 255, 1)">if</span> (r &lt; 0) 0f <span style="color: rgba(0, 0, 255, 1)">else</span> r /<span style="color: rgba(0, 0, 0, 1)"> 255f
      val labG </span>= <span style="color: rgba(0, 0, 255, 1)">if</span> (g &lt; 0) 0f <span style="color: rgba(0, 0, 255, 1)">else</span> g /<span style="color: rgba(0, 0, 0, 1)"> 255f
      val labB </span>= <span style="color: rgba(0, 0, 255, 1)">if</span> (b &lt; 0) 0f <span style="color: rgba(0, 0, 255, 1)">else</span> b /<span style="color: rgba(0, 0, 0, 1)"> 255f
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 线性化处理(sRGB转换)</span>
      val rLin = <span style="color: rgba(0, 0, 255, 1)">if</span> (labR &lt;= 0.04045) labR / 12.92 <span style="color: rgba(0, 0, 255, 1)">else</span> ((labR + 0.055) / 1.055).pow(2.4<span style="color: rgba(0, 0, 0, 1)">)
      val gLin </span>= <span style="color: rgba(0, 0, 255, 1)">if</span> (labG &lt;= 0.04045) labG / 12.92 <span style="color: rgba(0, 0, 255, 1)">else</span> ((labG + 0.055) / 1.055).pow(2.4<span style="color: rgba(0, 0, 0, 1)">)
      val bLin </span>= <span style="color: rgba(0, 0, 255, 1)">if</span> (labB &lt;= 0.04045) labB / 12.92 <span style="color: rgba(0, 0, 255, 1)">else</span> ((labB + 0.055) / 1.055).pow(2.4<span style="color: rgba(0, 0, 0, 1)">)

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> XYZ转换(D65标准光源)</span>
      val x = 0.4124564 * rLin + 0.3575761 * gLin + 0.1804375 *<span style="color: rgba(0, 0, 0, 1)"> bLin
      val y </span>= 0.2126729 * rLin + 0.7151522 * gLin + 0.0721750 *<span style="color: rgba(0, 0, 0, 1)"> bLin
      val z </span>= 0.0193339 * rLin + 0.1191920 * gLin + 0.9503041 *<span style="color: rgba(0, 0, 0, 1)"> bLin

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Lab转换</span>
      val xn = 0.95047f<span style="color: rgba(0, 0, 0, 1)">
      val yn </span>= 1.0f<span style="color: rgba(0, 0, 0, 1)">
      val zn </span>= 1.08883f<span style="color: rgba(0, 0, 0, 1)">
      val fX </span>= x /<span style="color: rgba(0, 0, 0, 1)"> xn
      val fY </span>= y /<span style="color: rgba(0, 0, 0, 1)"> yn
      val fZ </span>= z /<span style="color: rgba(0, 0, 0, 1)"> zn

      val l </span>= 116f * fY.pow(1 / 3.0) - 16<span style="color: rgba(0, 0, 0, 1)">
      val a </span>= 500f * (fX.pow(1 / 3.0) - fY.pow(1 / 3.0<span style="color: rgba(0, 0, 0, 1)">))
      val b </span>= 200f * (fY.pow(1 / 3.0) - fZ.pow(1 / 3.0<span style="color: rgba(0, 0, 0, 1)">))

      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> doubleArrayOf(l, a, b)
    }</span></pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>对rgb进行转换,这里是简化版,如果需要精确要求极高,需要完善</p>
<p>处理流程跟方案一一样,使用集合缓存</p>
<p>接着使用&nbsp;ΔE76色差公式 查找色值(另外还有ΔEab欧式距离算法,CIEDE2000色差公式,CIE76)</p>
<div class="cnblogs_code"><img id="code_img_closed_88a54cc7-01fc-48e4-bdf1-e4b48a600745" class="code_img_closed lazyload" data-src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img id="code_img_opened_88a54cc7-01fc-48e4-bdf1-e4b48a600745" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_88a54cc7-01fc-48e4-bdf1-e4b48a600745" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 0, 1)">fun deltaE76(lab1: DoubleArray, lab2: DoubleArray): Double {
      val (l1, a1, b1) </span>=<span style="color: rgba(0, 0, 0, 1)"> lab1
      val (l2, a2, b2) </span>=<span style="color: rgba(0, 0, 0, 1)"> lab2

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 计算中间变量</span>
      val c1 = sqrt(a1.pow(2) + b1.pow(2<span style="color: rgba(0, 0, 0, 1)">))
      val c2 </span>= sqrt(a2.pow(2) + b2.pow(2<span style="color: rgba(0, 0, 0, 1)">))
      val cAvg </span>= (c1 + c2) / 2<span style="color: rgba(0, 0, 0, 1)">

      val g </span>= 0.5 * (1 - sqrt(cAvg.pow(7) / (cAvg.pow(7) + 25f.pow(7<span style="color: rgba(0, 0, 0, 1)">))))
      val a1p </span>= a1 * (1 +<span style="color: rgba(0, 0, 0, 1)"> g)
      val a2p </span>= a2 * (1 +<span style="color: rgba(0, 0, 0, 1)"> g)

      val c1p </span>= sqrt(a1p.pow(2) + b1.pow(2<span style="color: rgba(0, 0, 0, 1)">))
      val c2p </span>= sqrt(a2p.pow(2) + b2.pow(2<span style="color: rgba(0, 0, 0, 1)">))
      val h1p </span>= Math.toDegrees(kotlin.math.atan2(b1, a1p)).let { <span style="color: rgba(0, 0, 255, 1)">if</span> (it &lt; 0) it + 360 <span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> it }
      val h2p </span>= Math.toDegrees(kotlin.math.atan2(b2, a2p)).let { <span style="color: rgba(0, 0, 255, 1)">if</span> (it &lt; 0) it + 360 <span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> it }

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 色差计算</span>
      val deltaLp = l2 -<span style="color: rgba(0, 0, 0, 1)"> l1
      val deltaCp </span>= c2p -<span style="color: rgba(0, 0, 0, 1)"> c1p
      val deltaHp </span>=<span style="color: rgba(0, 0, 0, 1)"> when {
            c1p </span>* c2p == 0.0 -&gt; 0.0<span style="color: rgba(0, 0, 0, 1)">
            abs(h2p </span>- h1p) &lt;= 180 -&gt; h2p -<span style="color: rgba(0, 0, 0, 1)"> h1p
            h2p </span>&lt;= h1p -&gt; h2p - h1p + 360
            <span style="color: rgba(0, 0, 255, 1)">else</span> -&gt; h2p - h1p - 360<span style="color: rgba(0, 0, 0, 1)">
      }
      val deltaHpS </span>= 2 * sqrt(c1p * c2p) * sin(Math.toRadians(deltaHp) / 2<span style="color: rgba(0, 0, 0, 1)">)

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 加权计算</span>
      val lAvg = (l1 + l2) / 2<span style="color: rgba(0, 0, 0, 1)">
      val cpAvg </span>= (c1p + c2p) / 2<span style="color: rgba(0, 0, 0, 1)">
      val hpAvg </span>=<span style="color: rgba(0, 0, 0, 1)"> when {
            c1p </span>* c2p == 0.0 -&gt; h1p +<span style="color: rgba(0, 0, 0, 1)"> h2p
            abs(h1p </span>- h2p) &gt; 180 -&gt; (h1p + h2p + 360) / 2
            <span style="color: rgba(0, 0, 255, 1)">else</span> -&gt; (h1p + h2p) / 2<span style="color: rgba(0, 0, 0, 1)">
      }.let { </span><span style="color: rgba(0, 0, 255, 1)">if</span> (it &gt;= 360) it - 360 <span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> it }

      val t </span>= 1 - 0.17 * cos(Math.toRadians(hpAvg - 30)) +
                0.24 * cos(Math.toRadians(2 * hpAvg)) +
                0.32 * cos(Math.toRadians(3 * hpAvg + 6)) -
                0.20 * cos(Math.toRadians(4 * hpAvg - 63<span style="color: rgba(0, 0, 0, 1)">))

      val sl </span>= 1 + (0.015 * (lAvg - 50).pow(2)) / sqrt(20 + (lAvg - 50).pow(2<span style="color: rgba(0, 0, 0, 1)">))
      val sc </span>= 1 + 0.045 *<span style="color: rgba(0, 0, 0, 1)"> cpAvg
      val sh </span>= 1 + 0.015 * cpAvg *<span style="color: rgba(0, 0, 0, 1)"> t

      val deltaTheta </span>= 30 * exp(-((hpAvg - 275) / 25).pow(2<span style="color: rgba(0, 0, 0, 1)">))
      val rc </span>= 2 * sqrt(cpAvg.pow(7) / (cpAvg.pow(7) + 25f.pow(7<span style="color: rgba(0, 0, 0, 1)">)))
      val rt </span>= -rc * sin(2 *<span style="color: rgba(0, 0, 0, 1)"> Math.toRadians(deltaTheta))

      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> sqrt(
            (deltaLp </span>/ sl).pow(2) +<span style="color: rgba(0, 0, 0, 1)">
                  (deltaCp </span>/ sc).pow(2) +<span style="color: rgba(0, 0, 0, 1)">
                  (deltaHpS </span>/ sh).pow(2) +<span style="color: rgba(0, 0, 0, 1)">
                  rt </span>* (deltaCp / sc) * (deltaHpS /<span style="color: rgba(0, 0, 0, 1)"> sh)
      )
    }</span></pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<div class="cnblogs_code"><img id="code_img_closed_41dfc3e2-fe4d-45ad-ac26-68a720c9cb15" class="code_img_closed lazyload" data-src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img id="code_img_opened_41dfc3e2-fe4d-45ad-ac26-68a720c9cb15" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_41dfc3e2-fe4d-45ad-ac26-68a720c9cb15" class="cnblogs_code_hide">
<pre>var minIndex = 0<span style="color: rgba(0, 0, 0, 1)">
      var minDistance </span>=<span style="color: rgba(0, 0, 0, 1)"> Double.MAX_VALUE
      var minLab </span>=<span style="color: rgba(0, 0, 0, 1)"> doubleArrayOf()
      tableLabPalette.forEachIndexed { index, lab </span>-&gt;<span style="color: rgba(0, 0, 0, 1)">
            val distance </span>=<span style="color: rgba(0, 0, 0, 1)"> ColorEabLabUtils.deltaE76(lab, list)
            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (distance &lt;<span style="color: rgba(0, 0, 0, 1)"> minDistance) {
                minDistance </span>=<span style="color: rgba(0, 0, 0, 1)"> distance
                minLab </span>=<span style="color: rgba(0, 0, 0, 1)"> lab
                minIndex </span>=<span style="color: rgba(0, 0, 0, 1)"> index
            }
      }</span></pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p><img alt="image" width="405" height="310" loading="lazy" src="https://img2024.cnblogs.com/blog/583064/202510/583064-20251022110239280-1062942616.png"></p>
<p>从上面图中结果可以明显看到,大部分图片中,hue原方案精准度对比lab查找,是有差距的</p>
<p>但是缺点也明显,在某些图片上表现不好,可以看到原方案hue更精准</p>
<p><img src="https://img2024.cnblogs.com/blog/583064/202510/583064-20251022110112007-1144896521.png"></p>
<p>经过大量调整算法,优化算法,测试下来发现,如果在不通过底层显示屏直接转换色值情况下,都存在误差</p>
<p>而刚好这两种查找结果有一定互补作用,那是否可以取各自的优势,结合结果,达到一个平衡</p>
<div class="cnblogs_code"><img src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img id="code_img_opened_edfbdec2-85d5-46dc-bd2a-1570f4ff50bc" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_edfbdec2-85d5-46dc-bd2a-1570f4ff50bc" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> fun findLabColor(list: DoubleArray, hue: Float): Int {
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 寻找最近颜色(简化版)</span>
      var minIndex = 0<span style="color: rgba(0, 0, 0, 1)">
      var minDistance </span>=<span style="color: rgba(0, 0, 0, 1)"> Double.MAX_VALUE
      var minLab </span>=<span style="color: rgba(0, 0, 0, 1)"> doubleArrayOf()
      tableLabPalette.forEachIndexed { index, lab </span>-&gt;<span style="color: rgba(0, 0, 0, 1)">
            val distance </span>=<span style="color: rgba(0, 0, 0, 1)"> ColorEabLabUtils.deltaE76(lab, list)
            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (distance &lt;<span style="color: rgba(0, 0, 0, 1)"> minDistance) {
                minDistance </span>=<span style="color: rgba(0, 0, 0, 1)"> distance
                minLab </span>=<span style="color: rgba(0, 0, 0, 1)"> lab
                minIndex </span>=<span style="color: rgba(0, 0, 0, 1)"> index
            }
      }
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (minDistance &lt; 26<span style="color: rgba(0, 0, 0, 1)">) {
            tableColorList
      } </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
            findColor(hue).colorTip
      }
    }</span></pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>在lab精度不够时,可能结果偏差较大,但是hue偏差不会很大,hue只是精度不够,所以这里兼容两种方案</p>
<p>在lab误差较大时,直接采用hue方案计算结果,这样直接弥补了自身的缺点,比如图一中误差小,采用lab方案,提高了精准度,而在图二精度不够时,采用hue,避免误差偏差较大</p>
<p><img alt="image" width="404" height="360" loading="lazy" src="https://img2024.cnblogs.com/blog/583064/202510/583064-20251022111128634-2073798422.png"></p>
<p>这里需要注意,hue色相查找需要调整排序,原生排序对于黑白纯色判断效果不佳</p>
<p>Palette.from(bitmap).maximumColorCount(24).clearFilters().generate(),所以这里过滤了黑白色,同时修改了原生的排序,按照新的计算方式取的主色</p>
<div class="cnblogs_code"><img id="code_img_closed_95c2d12d-05c1-4268-8c23-20023e29a000" class="code_img_closed lazyload" data-src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img id="code_img_opened_95c2d12d-05c1-4268-8c23-20023e29a000" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_95c2d12d-05c1-4268-8c23-20023e29a000" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 0, 1)">fun getPerceptuallyDominantColor(bitmap: Bitmap): Int {
      val palette </span>= Palette.from(bitmap).maximumColorCount(24<span style="color: rgba(0, 0, 0, 1)">).clearFilters().generate()
      val swatches </span>=<span style="color: rgba(0, 0, 0, 1)"> palette.swatches
      </span><span style="color: rgba(0, 0, 255, 1)">if</span> (swatches.isEmpty()) <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> Color.WHITE

      var bestSwatch: Swatch</span>? = <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">
      var maxScore </span>=<span style="color: rgba(0, 0, 0, 1)"> 0f

      </span><span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)"> (swatch in swatches) {
            val hsl </span>=<span style="color: rgba(0, 0, 0, 1)"> swatch.getHsl()
            val saturation </span>= hsl <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 饱和度 (0-1)</span>
            val luminance = hsl <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 亮度 (0-1)</span>
            val population =<span style="color: rgba(0, 0, 0, 1)"> swatch.population

            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 评分公式:人口占比 * 饱和度 * 亮度因子
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 亮度因子确保避免过暗或过亮的颜色(0.1-0.9为理想范围)</span>
            val luminanceFactor = 1f - abs(luminance - 0.5f) * 1.8f<span style="color: rgba(0, 0, 0, 1)">
            val score </span>= population * saturation *<span style="color: rgba(0, 0, 0, 1)"> luminanceFactor

            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (score &gt;<span style="color: rgba(0, 0, 0, 1)"> maxScore) {
                maxScore </span>=<span style="color: rgba(0, 0, 0, 1)"> score
                bestSwatch </span>=<span style="color: rgba(0, 0, 0, 1)"> swatch
            }
      }

      </span><span style="color: rgba(0, 0, 255, 1)">return</span> bestSwatch?.rgb ?<span style="color: rgba(0, 0, 0, 1)">: palette.getDominantColor(Color.WHITE)
    }</span></pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>最终方案是融合方案,不过精度任然存在误差,但本身转换过程结果只有256色,所以不可能达到完美,相比原图取色结果精度是较高</p>
<div class="cnblogs_code"><img id="code_img_closed_20b40641-7ff6-481b-9756-0d1f53994dd7" class="code_img_closed lazyload" data-src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img id="code_img_opened_20b40641-7ff6-481b-9756-0d1f53994dd7" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_20b40641-7ff6-481b-9756-0d1f53994dd7" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> android.graphics.Bitmap
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> android.graphics.Color
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> androidx.palette.graphics.Palette
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> androidx.palette.graphics.Palette.Swatch
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.lang.Math.toDegrees
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.lang.Math.toRadians
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> kotlin.math.abs
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> kotlin.math.atan2
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> kotlin.math.cos
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> kotlin.math.exp
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> kotlin.math.pow
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> kotlin.math.sin
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> kotlin.math.sqrt

object ColorEabLabUtils {

    fun getPerceptuallyDominantColor(bitmap: Bitmap): Int {
      val palette </span>= Palette.from(bitmap).maximumColorCount(24<span style="color: rgba(0, 0, 0, 1)">).clearFilters().generate()
      val swatches </span>=<span style="color: rgba(0, 0, 0, 1)"> palette.swatches
      </span><span style="color: rgba(0, 0, 255, 1)">if</span> (swatches.isEmpty()) <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> Color.WHITE

      var bestSwatch: Swatch</span>? = <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">
      var maxScore </span>=<span style="color: rgba(0, 0, 0, 1)"> 0f

      </span><span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)"> (swatch in swatches) {
            val hsl </span>=<span style="color: rgba(0, 0, 0, 1)"> swatch.getHsl()
            val saturation </span>= hsl <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 饱和度 (0-1)</span>
            val luminance = hsl <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 亮度 (0-1)</span>
            val population =<span style="color: rgba(0, 0, 0, 1)"> swatch.population

            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 评分公式:人口占比 * 饱和度 * 亮度因子
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 亮度因子确保避免过暗或过亮的颜色(0.1-0.9为理想范围)</span>
            val luminanceFactor = 1f - abs(luminance - 0.5f) * 1.8f<span style="color: rgba(0, 0, 0, 1)">
            val score </span>= population * saturation *<span style="color: rgba(0, 0, 0, 1)"> luminanceFactor

            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (score &gt;<span style="color: rgba(0, 0, 0, 1)"> maxScore) {
                maxScore </span>=<span style="color: rgba(0, 0, 0, 1)"> score
                bestSwatch </span>=<span style="color: rgba(0, 0, 0, 1)"> swatch
            }
      }

      </span><span style="color: rgba(0, 0, 255, 1)">return</span> bestSwatch?.rgb ?<span style="color: rgba(0, 0, 0, 1)">: palette.getDominantColor(Color.WHITE)
    }

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> RGB转Lab *********</span>
<span style="color: rgba(0, 0, 0, 1)">    fun rGBToLab(r: Int, g: Int, b: Int): DoubleArray {
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 处理负值(如-2563864)</span>
      val labR = <span style="color: rgba(0, 0, 255, 1)">if</span> (r &lt; 0) 0f <span style="color: rgba(0, 0, 255, 1)">else</span> r /<span style="color: rgba(0, 0, 0, 1)"> 255f
      val labG </span>= <span style="color: rgba(0, 0, 255, 1)">if</span> (g &lt; 0) 0f <span style="color: rgba(0, 0, 255, 1)">else</span> g /<span style="color: rgba(0, 0, 0, 1)"> 255f
      val labB </span>= <span style="color: rgba(0, 0, 255, 1)">if</span> (b &lt; 0) 0f <span style="color: rgba(0, 0, 255, 1)">else</span> b /<span style="color: rgba(0, 0, 0, 1)"> 255f
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 线性化处理(sRGB转换)</span>
      val rLin = <span style="color: rgba(0, 0, 255, 1)">if</span> (labR &lt;= 0.04045) labR / 12.92 <span style="color: rgba(0, 0, 255, 1)">else</span> ((labR + 0.055) / 1.055).pow(2.4<span style="color: rgba(0, 0, 0, 1)">)
      val gLin </span>= <span style="color: rgba(0, 0, 255, 1)">if</span> (labG &lt;= 0.04045) labG / 12.92 <span style="color: rgba(0, 0, 255, 1)">else</span> ((labG + 0.055) / 1.055).pow(2.4<span style="color: rgba(0, 0, 0, 1)">)
      val bLin </span>= <span style="color: rgba(0, 0, 255, 1)">if</span> (labB &lt;= 0.04045) labB / 12.92 <span style="color: rgba(0, 0, 255, 1)">else</span> ((labB + 0.055) / 1.055).pow(2.4<span style="color: rgba(0, 0, 0, 1)">)

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> XYZ转换(D65标准光源)</span>
      val x = 0.4124564 * rLin + 0.3575761 * gLin + 0.1804375 *<span style="color: rgba(0, 0, 0, 1)"> bLin
      val y </span>= 0.2126729 * rLin + 0.7151522 * gLin + 0.0721750 *<span style="color: rgba(0, 0, 0, 1)"> bLin
      val z </span>= 0.0193339 * rLin + 0.1191920 * gLin + 0.9503041 *<span style="color: rgba(0, 0, 0, 1)"> bLin

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Lab转换</span>
      val xn = 0.95047f<span style="color: rgba(0, 0, 0, 1)">
      val yn </span>= 1.0f<span style="color: rgba(0, 0, 0, 1)">
      val zn </span>= 1.08883f<span style="color: rgba(0, 0, 0, 1)">
      val fX </span>= x /<span style="color: rgba(0, 0, 0, 1)"> xn
      val fY </span>= y /<span style="color: rgba(0, 0, 0, 1)"> yn
      val fZ </span>= z /<span style="color: rgba(0, 0, 0, 1)"> zn

      val l </span>= 116f * fY.pow(1 / 3.0) - 16<span style="color: rgba(0, 0, 0, 1)">
      val a </span>= 500f * (fX.pow(1 / 3.0) - fY.pow(1 / 3.0<span style="color: rgba(0, 0, 0, 1)">))
      val b </span>= 200f * (fY.pow(1 / 3.0) - fZ.pow(1 / 3.0<span style="color: rgba(0, 0, 0, 1)">))

      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> doubleArrayOf(l, a, b)
    }

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ΔEab算法</span>
<span style="color: rgba(0, 0, 0, 1)">    fun deltaEab(lab1: DoubleArray, lab2: DoubleArray): Double {
      val dL </span>= lab1 - lab2
      val da </span>= lab1 - lab2
      val db </span>= lab1 - lab2
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> sqrt(dL.pow(2) + da.pow(2) + db.pow(2<span style="color: rgba(0, 0, 0, 1)">))
    }

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 改进的RGB转Lab(包含伽马校正和D65白点)</span>
<span style="color: rgba(0, 0, 0, 1)">    fun rgbToLab(r: Int, g: Int, b: Int): DoubleArray {
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 处理负值(如-2563864)</span>
      val labR = <span style="color: rgba(0, 0, 255, 1)">if</span> (r &lt; 0) 0f <span style="color: rgba(0, 0, 255, 1)">else</span> r /<span style="color: rgba(0, 0, 0, 1)"> 255f
      val labG </span>= <span style="color: rgba(0, 0, 255, 1)">if</span> (g &lt; 0) 0f <span style="color: rgba(0, 0, 255, 1)">else</span> g /<span style="color: rgba(0, 0, 0, 1)"> 255f
      val labB </span>= <span style="color: rgba(0, 0, 255, 1)">if</span> (b &lt; 0) 0f <span style="color: rgba(0, 0, 255, 1)">else</span> b /<span style="color: rgba(0, 0, 0, 1)"> 255f

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> sRGB伽马校正</span>
      val rLin = <span style="color: rgba(0, 0, 255, 1)">if</span> (labR &lt;= 0.04045) labR / 12.92 <span style="color: rgba(0, 0, 255, 1)">else</span> ((labR + 0.055) / 1.055).pow(2.4<span style="color: rgba(0, 0, 0, 1)">)
      val gLin </span>= <span style="color: rgba(0, 0, 255, 1)">if</span> (labG &lt;= 0.04045) labG / 12.92 <span style="color: rgba(0, 0, 255, 1)">else</span> ((labG + 0.055) / 1.055).pow(2.4<span style="color: rgba(0, 0, 0, 1)">)
      val bLin </span>= <span style="color: rgba(0, 0, 255, 1)">if</span> (labB &lt;= 0.04045) labB / 12.92 <span style="color: rgba(0, 0, 255, 1)">else</span> ((labB + 0.055) / 1.055).pow(2.4<span style="color: rgba(0, 0, 0, 1)">)

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> D65标准光源XYZ转换</span>
      val x = 0.4124564 * rLin + 0.3575761 * gLin + 0.1804375 *<span style="color: rgba(0, 0, 0, 1)"> bLin
      val y </span>= 0.2126729 * rLin + 0.7151522 * gLin + 0.0721750 *<span style="color: rgba(0, 0, 0, 1)"> bLin
      val z </span>= 0.0193339 * rLin + 0.1191920 * gLin + 0.9503041 *<span style="color: rgba(0, 0, 0, 1)"> bLin

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Lab转换(包含阈值处理)</span>
      val xn = 0.95047<span style="color: rgba(0, 0, 0, 1)">
      val yn </span>= 1.0<span style="color: rgba(0, 0, 0, 1)">
      val zn </span>= 1.08883<span style="color: rgba(0, 0, 0, 1)">
      val fX </span>= x /<span style="color: rgba(0, 0, 0, 1)"> xn
      val fY </span>= y /<span style="color: rgba(0, 0, 0, 1)"> yn
      val fZ </span>= z /<span style="color: rgba(0, 0, 0, 1)"> zn

      val l </span>= <span style="color: rgba(0, 0, 255, 1)">if</span> (fY &gt; 0.008856) 116 * fY.pow(1 / 3.0) - 16 <span style="color: rgba(0, 0, 255, 1)">else</span> 903.3 *<span style="color: rgba(0, 0, 0, 1)"> fY
      val a </span>= 500 * (fX.pow(1 / 3.0) - fY.pow(1 / 3.0<span style="color: rgba(0, 0, 0, 1)">))
      val b </span>= 200 * (fY.pow(1 / 3.0) - fZ.pow(1 / 3.0<span style="color: rgba(0, 0, 0, 1)">))

      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> doubleArrayOf(l, a, b)
    }

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 改进的ΔE76色差公式(包含亮度权重)*********</span>
<span style="color: rgba(0, 0, 0, 1)">    fun deltaE76(lab1: DoubleArray, lab2: DoubleArray): Double {
      val (l1, a1, b1) </span>=<span style="color: rgba(0, 0, 0, 1)"> lab1
      val (l2, a2, b2) </span>=<span style="color: rgba(0, 0, 0, 1)"> lab2

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 计算中间变量</span>
      val c1 = sqrt(a1.pow(2) + b1.pow(2<span style="color: rgba(0, 0, 0, 1)">))
      val c2 </span>= sqrt(a2.pow(2) + b2.pow(2<span style="color: rgba(0, 0, 0, 1)">))
      val cAvg </span>= (c1 + c2) / 2<span style="color: rgba(0, 0, 0, 1)">

      val g </span>= 0.5 * (1 - sqrt(cAvg.pow(7) / (cAvg.pow(7) + 25f.pow(7<span style="color: rgba(0, 0, 0, 1)">))))
      val a1p </span>= a1 * (1 +<span style="color: rgba(0, 0, 0, 1)"> g)
      val a2p </span>= a2 * (1 +<span style="color: rgba(0, 0, 0, 1)"> g)

      val c1p </span>= sqrt(a1p.pow(2) + b1.pow(2<span style="color: rgba(0, 0, 0, 1)">))
      val c2p </span>= sqrt(a2p.pow(2) + b2.pow(2<span style="color: rgba(0, 0, 0, 1)">))
      val h1p </span>= Math.toDegrees(kotlin.math.atan2(b1, a1p)).let { <span style="color: rgba(0, 0, 255, 1)">if</span> (it &lt; 0) it + 360 <span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> it }
      val h2p </span>= Math.toDegrees(kotlin.math.atan2(b2, a2p)).let { <span style="color: rgba(0, 0, 255, 1)">if</span> (it &lt; 0) it + 360 <span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> it }

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 色差计算</span>
      val deltaLp = l2 -<span style="color: rgba(0, 0, 0, 1)"> l1
      val deltaCp </span>= c2p -<span style="color: rgba(0, 0, 0, 1)"> c1p
      val deltaHp </span>=<span style="color: rgba(0, 0, 0, 1)"> when {
            c1p </span>* c2p == 0.0 -&gt; 0.0<span style="color: rgba(0, 0, 0, 1)">
            abs(h2p </span>- h1p) &lt;= 180 -&gt; h2p -<span style="color: rgba(0, 0, 0, 1)"> h1p
            h2p </span>&lt;= h1p -&gt; h2p - h1p + 360
            <span style="color: rgba(0, 0, 255, 1)">else</span> -&gt; h2p - h1p - 360<span style="color: rgba(0, 0, 0, 1)">
      }
      val deltaHpS </span>= 2 * sqrt(c1p * c2p) * sin(Math.toRadians(deltaHp) / 2<span style="color: rgba(0, 0, 0, 1)">)

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 加权计算</span>
      val lAvg = (l1 + l2) / 2<span style="color: rgba(0, 0, 0, 1)">
      val cpAvg </span>= (c1p + c2p) / 2<span style="color: rgba(0, 0, 0, 1)">
      val hpAvg </span>=<span style="color: rgba(0, 0, 0, 1)"> when {
            c1p </span>* c2p == 0.0 -&gt; h1p +<span style="color: rgba(0, 0, 0, 1)"> h2p
            abs(h1p </span>- h2p) &gt; 180 -&gt; (h1p + h2p + 360) / 2
            <span style="color: rgba(0, 0, 255, 1)">else</span> -&gt; (h1p + h2p) / 2<span style="color: rgba(0, 0, 0, 1)">
      }.let { </span><span style="color: rgba(0, 0, 255, 1)">if</span> (it &gt;= 360) it - 360 <span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> it }

      val t </span>= 1 - 0.17 * cos(Math.toRadians(hpAvg - 30)) +
                0.24 * cos(Math.toRadians(2 * hpAvg)) +
                0.32 * cos(Math.toRadians(3 * hpAvg + 6)) -
                0.20 * cos(Math.toRadians(4 * hpAvg - 63<span style="color: rgba(0, 0, 0, 1)">))

      val sl </span>= 1 + (0.015 * (lAvg - 50).pow(2)) / sqrt(20 + (lAvg - 50).pow(2<span style="color: rgba(0, 0, 0, 1)">))
      val sc </span>= 1 + 0.045 *<span style="color: rgba(0, 0, 0, 1)"> cpAvg
      val sh </span>= 1 + 0.015 * cpAvg *<span style="color: rgba(0, 0, 0, 1)"> t

      val deltaTheta </span>= 30 * exp(-((hpAvg - 275) / 25).pow(2<span style="color: rgba(0, 0, 0, 1)">))
      val rc </span>= 2 * sqrt(cpAvg.pow(7) / (cpAvg.pow(7) + 25f.pow(7<span style="color: rgba(0, 0, 0, 1)">)))
      val rt </span>= -rc * sin(2 *<span style="color: rgba(0, 0, 0, 1)"> Math.toRadians(deltaTheta))

      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> sqrt(
            (deltaLp </span>/ sl).pow(2) +<span style="color: rgba(0, 0, 0, 1)">
                  (deltaCp </span>/ sc).pow(2) +<span style="color: rgba(0, 0, 0, 1)">
                  (deltaHpS </span>/ sh).pow(2) +<span style="color: rgba(0, 0, 0, 1)">
                  rt </span>* (deltaCp / sc) * (deltaHpS /<span style="color: rgba(0, 0, 0, 1)"> sh)
      )
    }


    </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
   * CIEDE2000色差公式实现
   * 更符合人眼感知的颜色差异计算
   * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> lab1 第一个颜色的Lab值
   * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> lab2 第二个颜色的Lab值
   * </span><span style="color: rgba(128, 128, 128, 1)">@return</span><span style="color: rgba(0, 128, 0, 1)"> Double 色差值(ΔE越小颜色越接近)
   </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
    fun deltaE2000(lab1: DoubleArray, lab2: DoubleArray): Double {
      val (l1, a1, b1) </span>=<span style="color: rgba(0, 0, 0, 1)"> lab1
      val (l2, a2, b2) </span>=<span style="color: rgba(0, 0, 0, 1)"> lab2

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 步骤1:计算色度</span>
      val c1 = sqrt(a1.pow(2) + b1.pow(2<span style="color: rgba(0, 0, 0, 1)">))
      val c2 </span>= sqrt(a2.pow(2) + b2.pow(2<span style="color: rgba(0, 0, 0, 1)">))
      val cAvg </span>= (c1 + c2) / 2.0

      <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 步骤2:计算补偿因子</span>
      val g = 0.5 * (1.0 - sqrt(cAvg.pow(7) / (cAvg.pow(7) + 25.0.pow(7<span style="color: rgba(0, 0, 0, 1)">))))

      val a1Prime </span>= a1 * (1.0 +<span style="color: rgba(0, 0, 0, 1)"> g)
      val a2Prime </span>= a2 * (1.0 +<span style="color: rgba(0, 0, 0, 1)"> g)

      val c1Prime </span>= sqrt(a1Prime.pow(2) + b1.pow(2<span style="color: rgba(0, 0, 0, 1)">))
      val c2Prime </span>= sqrt(a2Prime.pow(2) + b2.pow(2<span style="color: rgba(0, 0, 0, 1)">))
      val cBarPrime </span>= (c1Prime + c2Prime) / 2.0

      <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 步骤3:计算色调角</span>
      val h1Prime = toDegrees(atan2(b1, a1Prime)).let { <span style="color: rgba(0, 0, 255, 1)">if</span> (it &lt; 0) it + 360.0 <span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> it }
      val h2Prime </span>= toDegrees(atan2(b2, a2Prime)).let { <span style="color: rgba(0, 0, 255, 1)">if</span> (it &lt; 0) it + 360.0 <span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> it }

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 步骤4:计算基本差异</span>
      val deltaLPrime = l2 -<span style="color: rgba(0, 0, 0, 1)"> l1
      val deltaCPrime </span>= c2Prime -<span style="color: rgba(0, 0, 0, 1)"> c1Prime

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 步骤5:计算色调差</span>
      var deltaHPrime = 0.0
      <span style="color: rgba(0, 0, 255, 1)">if</span> (c1Prime * c2Prime != 0.0<span style="color: rgba(0, 0, 0, 1)">) {
            val deltaHPrimeRaw </span>=<span style="color: rgba(0, 0, 0, 1)"> when {
                abs(h2Prime </span>- h1Prime) &lt;= 180.0 -&gt; h2Prime -<span style="color: rgba(0, 0, 0, 1)"> h1Prime
                h2Prime </span>&lt;= h1Prime -&gt; h2Prime - h1Prime + 360.0
                <span style="color: rgba(0, 0, 255, 1)">else</span> -&gt; h2Prime - h1Prime - 360.0<span style="color: rgba(0, 0, 0, 1)">
            }
            deltaHPrime </span>= 2.0 * sqrt(c1Prime * c2Prime) * sin(toRadians(deltaHPrimeRaw) / 2.0<span style="color: rgba(0, 0, 0, 1)">)
      }

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 步骤6:计算加权平均值</span>
      val lBar = (l1 + l2) / 2.0<span style="color: rgba(0, 0, 0, 1)">
      val cBar </span>= (c1 + c2) / 2.0

      <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 步骤7:计算色调平均值</span>
      val hBarPrime =<span style="color: rgba(0, 0, 0, 1)"> when {
            abs(h1Prime </span>- h2Prime) &gt; 180.0 -&gt; (h1Prime + h2Prime + 360.0) / 2.0
            <span style="color: rgba(0, 0, 255, 1)">else</span> -&gt; (h1Prime + h2Prime) / 2.0<span style="color: rgba(0, 0, 0, 1)">
      }

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 步骤8:计算补偿项</span>
      val t = 1.0 - 0.17 * cos(toRadians(hBarPrime - 30.0)) +
                0.24 * cos(toRadians(2.0 * hBarPrime)) +
                0.32 * cos(toRadians(3.0 * hBarPrime + 6.0)) -
                0.20 * cos(toRadians(4.0 * hBarPrime - 63.0<span style="color: rgba(0, 0, 0, 1)">))

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 步骤9:计算旋转项</span>
      val deltaTheta = 30.0 * exp(-((hBarPrime - 275.0) / 25.0).pow(2<span style="color: rgba(0, 0, 0, 1)">))

      val rc </span>= 2.0 * sqrt(cBarPrime.pow(7) / (cBarPrime.pow(7) + 25.0.pow(7<span style="color: rgba(0, 0, 0, 1)">)))
      val rt </span>= -rc * sin(2.0 *<span style="color: rgba(0, 0, 0, 1)"> toRadians(deltaTheta))

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 步骤10:计算权重因子</span>
      val sl = 1.0 + (0.015 * (lBar - 50.0).pow(2) / sqrt(20.0 + (lBar - 50.0).pow(2<span style="color: rgba(0, 0, 0, 1)">)))
      val sc </span>= 1.0 + 0.045 *<span style="color: rgba(0, 0, 0, 1)"> cBarPrime
      val sh </span>= 1.0 + 0.015 * cBarPrime *<span style="color: rgba(0, 0, 0, 1)"> t

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 步骤11:最终色差计算</span>
      val term1 = (deltaLPrime / sl).pow(2<span style="color: rgba(0, 0, 0, 1)">)
      val term2 </span>= (deltaCPrime / sc).pow(2<span style="color: rgba(0, 0, 0, 1)">)
      val term3 </span>= (deltaHPrime / sh).pow(2<span style="color: rgba(0, 0, 0, 1)">)
      val term4 </span>= rt * (deltaCPrime / sc) * (deltaHPrime /<span style="color: rgba(0, 0, 0, 1)"> sh)

      </span><span style="color: rgba(0, 0, 255, 1)">return</span> sqrt(term1 + term2 + term3 +<span style="color: rgba(0, 0, 0, 1)"> term4)
    }


    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 优化的伽马校正函数</span>
    fun preciseGammaExpand(c: Double) = <span style="color: rgba(0, 0, 255, 1)">if</span> (c &lt;= 0.04045<span style="color: rgba(0, 0, 0, 1)">) {
      c </span>/ 12.92<span style="color: rgba(0, 0, 0, 1)">
    } </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
      ((c </span>+ 0.055) / 1.055).pow(2.4<span style="color: rgba(0, 0, 0, 1)">)
    }

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 优化的Lab转换函数</span>
    fun preciseF(t: Double) = <span style="color: rgba(0, 0, 255, 1)">if</span> (t &gt; 0.008856<span style="color: rgba(0, 0, 0, 1)">) {
      t.pow(</span>1.0 / 3.0<span style="color: rgba(0, 0, 0, 1)">)
    } </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
      (</span>7.787 * t) + (16.0 / 116.0<span style="color: rgba(0, 0, 0, 1)">)
    }

    </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
   * 优化的RGB转Lab转换方法
   * 使用更精确的浮点数计算和标准化处理
   </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
    fun rgbToLabOptimized(r: Int, g: Int, b: Int): DoubleArray {
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 使用更精确的归一化</span>
      val rNormalized = r / 255.0<span style="color: rgba(0, 0, 0, 1)">
      val gNormalized </span>= g / 255.0<span style="color: rgba(0, 0, 0, 1)">
      val bNormalized </span>= b / 255.0

      <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 应用伽马校正</span>
      val rLinear =<span style="color: rgba(0, 0, 0, 1)"> preciseGammaExpand(rNormalized)
      val gLinear </span>=<span style="color: rgba(0, 0, 0, 1)"> preciseGammaExpand(gNormalized)
      val bLinear </span>=<span style="color: rgba(0, 0, 0, 1)"> preciseGammaExpand(bNormalized)

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 使用D65标准光源的精确XYZ转换矩阵</span>
      val x = 0.4124564 * rLinear + 0.3575761 * gLinear + 0.1804375 *<span style="color: rgba(0, 0, 0, 1)"> bLinear
      val y </span>= 0.2126729 * rLinear + 0.7151522 * gLinear + 0.0721750 *<span style="color: rgba(0, 0, 0, 1)"> bLinear
      val z </span>= 0.0193339 * rLinear + 0.1191920 * gLinear + 0.9503041 *<span style="color: rgba(0, 0, 0, 1)"> bLinear

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 使用CIE标准参考白点</span>
      val refX = 0.95047<span style="color: rgba(0, 0, 0, 1)">
      val refY </span>= 1.00000<span style="color: rgba(0, 0, 0, 1)">
      val refZ </span>= 1.08883

      <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 计算相对值</span>
      val xRelative = x /<span style="color: rgba(0, 0, 0, 1)"> refX
      val yRelative </span>= y /<span style="color: rgba(0, 0, 0, 1)"> refY
      val zRelative </span>= z /<span style="color: rgba(0, 0, 0, 1)"> refZ

      val fx </span>=<span style="color: rgba(0, 0, 0, 1)"> preciseF(xRelative)
      val fy </span>=<span style="color: rgba(0, 0, 0, 1)"> preciseF(yRelative)
      val fz </span>=<span style="color: rgba(0, 0, 0, 1)"> preciseF(zRelative)

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 计算Lab值</span>
      val l = (116.0 * fy) - 16.0<span style="color: rgba(0, 0, 0, 1)">
      val a </span>= 500.0 * (fx -<span style="color: rgba(0, 0, 0, 1)"> fy)
      val bLab </span>= 200.0 * (fy -<span style="color: rgba(0, 0, 0, 1)"> fz)

      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> doubleArrayOf(l, a, bLab)
    }

    </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
   * 完整的CIEDE2000色差公式实现
   * 包含所有补偿项和旋转项
   </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
    fun deltaE2000Complete(lab1: DoubleArray, lab2: DoubleArray): Double {
      val (l1, a1, b1) </span>=<span style="color: rgba(0, 0, 0, 1)"> lab1
      val (l2, a2, b2) </span>=<span style="color: rgba(0, 0, 0, 1)"> lab2

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 步骤1:计算色度值</span>
      val c1 = sqrt(a1.pow(2) + b1.pow(2<span style="color: rgba(0, 0, 0, 1)">))
      val c2 </span>= sqrt(a2.pow(2) + b2.pow(2<span style="color: rgba(0, 0, 0, 1)">))

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 步骤2:计算平均值</span>
      val lBar = (l1 + l2) / 2.0<span style="color: rgba(0, 0, 0, 1)">
      val cBar </span>= (c1 + c2) / 2.0

      <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 步骤3:计算补偿因子</span>
      val g = 0.5 * (1.0 - sqrt(cBar.pow(7) / (cBar.pow(7) + 25.0.pow(7<span style="color: rgba(0, 0, 0, 1)">))))

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 步骤4:计算调整后的a'值</span>
      val a1Prime = a1 * (1.0 +<span style="color: rgba(0, 0, 0, 1)"> g)
      val a2Prime </span>= a2 * (1.0 +<span style="color: rgba(0, 0, 0, 1)"> g)

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 步骤5:计算调整后的色度值</span>
      val c1Prime = sqrt(a1Prime.pow(2) + b1.pow(2<span style="color: rgba(0, 0, 0, 1)">))
      val c2Prime </span>= sqrt(a2Prime.pow(2) + b2.pow(2<span style="color: rgba(0, 0, 0, 1)">))
      val cBarPrime </span>= (c1Prime + c2Prime) / 2.0

      <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 步骤6:计算色调角</span>
      val h1Prime =<span style="color: rgba(0, 0, 0, 1)"> toDegrees(atan2(b1, a1Prime)).let {
            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (it &lt; 0) it + 360.0 <span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> it
      }
      val h2Prime </span>=<span style="color: rgba(0, 0, 0, 1)"> toDegrees(atan2(b2, a2Prime)).let {
            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (it &lt; 0) it + 360.0 <span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> it
      }

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 步骤7:计算基本差异</span>
      val deltaLPrime = l2 -<span style="color: rgba(0, 0, 0, 1)"> l1
      val deltaCPrime </span>= c2Prime -<span style="color: rgba(0, 0, 0, 1)"> c1Prime

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 步骤8:计算色调差</span>
      var deltaHPrime = 0.0
      <span style="color: rgba(0, 0, 255, 1)">if</span> (c1Prime != 0.0 &amp;&amp; c2Prime != 0.0<span style="color: rgba(0, 0, 0, 1)">) {
            val deltaHPrimeRaw </span>=<span style="color: rgba(0, 0, 0, 1)"> when {
                abs(h2Prime </span>- h1Prime) &lt;= 180.0 -&gt; h2Prime -<span style="color: rgba(0, 0, 0, 1)"> h1Prime
                h2Prime </span>&lt;= h1Prime -&gt; h2Prime - h1Prime + 360.0
                <span style="color: rgba(0, 0, 255, 1)">else</span> -&gt; h2Prime - h1Prime - 360.0<span style="color: rgba(0, 0, 0, 1)">
            }
            deltaHPrime </span>= 2.0 * sqrt(c1Prime * c2Prime) * sin(toRadians(deltaHPrimeRaw) / 2.0<span style="color: rgba(0, 0, 0, 1)">)
      }

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 步骤9:计算色调平均值</span>
      val hBarPrime =<span style="color: rgba(0, 0, 0, 1)"> when {
            abs(h1Prime </span>- h2Prime) &gt; 180.0 -&gt; (h1Prime + h2Prime + 360.0) / 2.0
            <span style="color: rgba(0, 0, 255, 1)">else</span> -&gt; (h1Prime + h2Prime) / 2.0<span style="color: rgba(0, 0, 0, 1)">
      }

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 步骤10:计算补偿项</span>
      val t = 1.0 - 0.17 * cos(toRadians(hBarPrime - 30.0)) +
                0.24 * cos(toRadians(2.0 * hBarPrime)) +
                0.32 * cos(toRadians(3.0 * hBarPrime + 6.0)) -
                0.20 * cos(toRadians(4.0 * hBarPrime - 63.0<span style="color: rgba(0, 0, 0, 1)">))

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 步骤11:计算旋转项</span>
      val deltaTheta = 30.0 * exp(-((hBarPrime - 275.0) / 25.0).pow(2<span style="color: rgba(0, 0, 0, 1)">))

      val rc </span>= 2.0 * sqrt(cBarPrime.pow(7) / (cBarPrime.pow(7) + 25.0.pow(7<span style="color: rgba(0, 0, 0, 1)">)))
      val rt </span>= -rc * sin(2.0 *<span style="color: rgba(0, 0, 0, 1)"> toRadians(deltaTheta))

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 步骤12:计算权重因子</span>
      val sl = 1.0 + (0.015 * (lBar - 50.0).pow(2) / sqrt(20.0 + (lBar - 50.0).pow(2<span style="color: rgba(0, 0, 0, 1)">)))
      val sc </span>= 1.0 + 0.045 *<span style="color: rgba(0, 0, 0, 1)"> cBarPrime
      val sh </span>= 1.0 + 0.015 * cBarPrime *<span style="color: rgba(0, 0, 0, 1)"> t

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 步骤13:最终色差计算</span>
      val term1 = (deltaLPrime / sl).pow(2<span style="color: rgba(0, 0, 0, 1)">)
      val term2 </span>= (deltaCPrime / sc).pow(2<span style="color: rgba(0, 0, 0, 1)">)
      val term3 </span>= (deltaHPrime / sh).pow(2<span style="color: rgba(0, 0, 0, 1)">)
      val term4 </span>= rt * (deltaCPrime / sc) * (deltaHPrime /<span style="color: rgba(0, 0, 0, 1)"> sh)

      </span><span style="color: rgba(0, 0, 255, 1)">return</span> sqrt(term1 + term2 + term3 +<span style="color: rgba(0, 0, 0, 1)"> term4)
    }

}</span></pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<div class="cnblogs_code"><img id="code_img_closed_d44521c4-0af6-4442-8a19-02381ce7c747" class="code_img_closed lazyload" data-src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img id="code_img_opened_d44521c4-0af6-4442-8a19-02381ce7c747" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_d44521c4-0af6-4442-8a19-02381ce7c747" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 0, 1)">{
"list": [
    {
      "r": 0,
      "g": 84,
      "b": 255
    },
    {
      "r": 18,
      "g": 92,
      "b": 255
    },
    {
      "r": 65,
      "g": 82,
      "b": 255
    },
    {
      "r": 90,
      "g": 81,
      "b": 255
    },
    {
      "r": 110,
      "g": 80,
      "b": 255
    },
    {
      "r": 127,
      "g": 78,
      "b": 255
    },
    {
      "r": 142,
      "g": 77,
      "b": 255
    },
    {
      "r": 157,
      "g": 76,
      "b": 255
    },
    {
      "r": 170,
      "g": 74,
      "b": 255
    },
    {
      "r": 197,
      "g": 70,
      "b": 255
    },
    {
      "r": 209,
      "g": 68,
      "b": 255
    },
    {
      "r": 237,
      "g": 62,
      "b": 255
    },
    {
      "r": 255,
      "g": 51,
      "b": 244
    },
    {
      "r": 255,
      "g": 35,
      "b": 219
    },
    {
      "r": 255,
      "g": 11,
      "b": 196
    },
    {
      "r": 255,
      "g": 0,
      "b": 176
    },
    {
      "r": 255,
      "g": 48,
      "b": 158
    },
    {
      "r": 255,
      "g": 19,
      "b": 142
    },
    {
      "r": 255,
      "g": 15,
      "b": 122
    },
    {
      "r": 255,
      "g": 0,
      "b": 99
    },
    {
      "r": 255,
      "g": 6,
      "b": 75
    },
    {
      "r": 255,
      "g": 9,
      "b": 55
    },
    {
      "r": 255,
      "g": 6,
      "b": 0
    },
    {
      "r": 255,
      "g": 28,
      "b": 0
    },
    {
      "r": 255,
      "g": 62,
      "b": 0
    },
    {
      "r": 255,
      "g": 85,
      "b": 0
    },
    {
      "r": 255,
      "g": 105,
      "b": 0
    },
    {
      "r": 255,
      "g": 125,
      "b": 0
    },
    {
      "r": 255,
      "g": 155,
      "b": 5
    },
    {
      "r": 255,
      "g": 171,
      "b": 41
    },
    {
      "r": 255,
      "g": 180,
      "b": 15
    },
    {
      "r": 255,
      "g": 192,
      "b": 19
    },
    {
      "r": 255,
      "g": 206,
      "b": 45
    },
    {
      "r": 255,
      "g": 218,
      "b": 27
    },
    {
      "r": 255,
      "g": 231,
      "b": 30
    },
    {
      "r": 255,
      "g": 244,
      "b": 34
    },
    {
      "r": 251,
      "g": 255,
      "b": 37
    },
    {
      "r": 235,
      "g": 255,
      "b": 38
    },
    {
      "r": 219,
      "g": 255,
      "b": 39
    },
    {
      "r": 203,
      "g": 255,
      "b": 40
    },
    {
      "r": 185,
      "g": 255,
      "b": 41
    },
    {
      "r": 165,
      "g": 255,
      "b": 42
    },
    {
      "r": 142,
      "g": 255,
      "b": 42
    },
    {
      "r": 109,
      "g": 255,
      "b": 29
    },
    {
      "r": 69,
      "g": 255,
      "b": 44
    },
    {
      "r": 24,
      "g": 255,
      "b": 46
    },
    {
      "r": 22,
      "g": 255,
      "b": 32
    },
    {
      "r": 0,
      "g": 255,
      "b": 102
    },
    {
      "r": 0,
      "g": 255,
      "b": 136
    },
    {
      "r": 6,
      "g": 209,
      "b": 128
    },
    {
      "r": 0,
      "g": 255,
      "b": 189
    },
    {
      "r": 0,
      "g": 255,
      "b": 212
    },
    {
      "r": 0,
      "g": 255,
      "b": 234
    },
    {
      "r": 0,
      "g": 254,
      "b": 255
    },
    {
      "r": 0,
      "g": 234,
      "b": 255
    },
    {
      "r": 0,
      "g": 200,
      "b": 255
    },
    {
      "r": 0,
      "g": 186,
      "b": 255
    },
    {
      "r": 0,
      "g": 173,
      "b": 255
    },
    {
      "r": 72,
      "g": 164,
      "b": 237
    },
    {
      "r": 2,
      "g": 146,
      "b": 255
    },
    {
      "r": 0,
      "g": 138,
      "b": 255
    },
    {
      "r": 0,
      "g": 127,
      "b": 255
    },
    {
      "r": 0,
      "g": 106,
      "b": 255
    },
    {
      "r": 255,
      "g": 255,
      "b": 255
    },
    {
      "r": 78,
      "g": 85,
      "b": 255
    },
    {
      "r": 100,
      "g": 150,
      "b": 255
    },
    {
      "r": 98,
      "g": 204,
      "b": 255
    },
    {
      "r": 103,
      "g": 172,
      "b": 156
    },
    {
      "r": 84,
      "g": 255,
      "b": 167
    },
    {
      "r": 58,
      "g": 255,
      "b": 112
    },
    {
      "r": 52,
      "g": 255,
      "b": 88
    },
    {
      "r": 149,
      "g": 95,
      "b": 255
    },
    {
      "r": 162,
      "g": 152,
      "b": 255
    },
    {
      "r": 171,
      "g": 228,
      "b": 255
    },
    {
      "r": 159,
      "g": 255,
      "b": 201
    },
    {
      "r": 130,
      "g": 255,
      "b": 142
    },
    {
      "r": 108,
      "g": 255,
      "b": 99
    },
    {
      "r": 97,
      "g": 255,
      "b": 74
    },
    {
      "r": 79,
      "g": 255,
      "b": 41
    },
    {
      "r": 236,
      "g": 101,
      "b": 254
    },
    {
      "r": 254,
      "g": 169,
      "b": 255
    },
    {
      "r": 225,
      "g": 255,
      "b": 170
    },
    {
      "r": 184,
      "g": 255,
      "b": 155
    },
    {
      "r": 155,
      "g": 255,
      "b": 75
    },
    {
      "r": 133,
      "g": 255,
      "b": 45
    },
    {
      "r": 255,
      "g": 86,
      "b": 196
    },
    {
      "r": 255,
      "g": 130,
      "b": 171
    },
    {
      "r": 255,
      "g": 175,
      "b": 146
    },
    {
      "r": 255,
      "g": 221,
      "b": 119
    },
    {
      "r": 235,
      "g": 255,
      "b": 95
    },
    {
      "r": 203,
      "g": 255,
      "b": 51
    },
    {
      "r": 255,
      "g": 68,
      "b": 138
    },
    {
      "r": 255,
      "g": 104,
      "b": 117
    },
    {
      "r": 255,
      "g": 140,
      "b": 95
    },
    {
      "r": 255,
      "g": 187,
      "b": 85
    },
    {
      "r": 255,
      "g": 217,
      "b": 49
    },
    {
      "r": 255,
      "g": 25,
      "b": 115
    },
    {
      "r": 255,
      "g": 40,
      "b": 96
    },
    {
      "r": 255,
      "g": 85,
      "b": 78
    },
    {
      "r": 255,
      "g": 116,
      "b": 59
    },
    {
      "r": 255,
      "g": 148,
      "b": 40
    },
    {
      "r": 255,
      "g": 45,
      "b": 62
    },
    {
      "r": 255,
      "g": 81,
      "b": 54
    },
    {
      "r": 255,
      "g": 98,
      "b": 33
    },
    {
      "r": 255,
      "g": 22,
      "b": 36
    },
    {
      "r": 255,
      "g": 49,
      "b": 35
    },
    {
      "r": 255,
      "g": 32,
      "b": 23
    },
    {
      "r": 35,
      "g": 55,
      "b": 255
    },
    {
      "r": 35,
      "g": 73,
      "b": 255
    },
    {
      "r": 35,
      "g": 94,
      "b": 255
    },
    {
      "r": 35,
      "g": 116,
      "b": 255
    },
    {
      "r": 65,
      "g": 145,
      "b": 255
    },
    {
      "r": 35,
      "g": 182,
      "b": 255
    },
    {
      "r": 35,
      "g": 214,
      "b": 255
    },
    {
      "r": 2,
      "g": 251,
      "b": 255
    },
    {
      "r": 0,
      "g": 255,
      "b": 223
    },
    {
      "r": 0,
      "g": 255,
      "b": 203
    },
    {
      "r": 22,
      "g": 255,
      "b": 168
    },
    {
      "r": 54,
      "g": 255,
      "b": 144
    },
    {
      "r": 58,
      "g": 55,
      "b": 255
    },
    {
      "r": 59,
      "g": 86,
      "b": 255
    },
    {
      "r": 61,
      "g": 120,
      "b": 255
    },
    {
      "r": 64,
      "g": 175,
      "b": 255
    },
    {
      "r": 66,
      "g": 225,
      "b": 255
    },
    {
      "r": 65,
      "g": 255,
      "b": 246
    },
    {
      "r": 83,
      "g": 255,
      "b": 211
    },
    {
      "r": 51,
      "g": 255,
      "b": 181
    },
    {
      "r": 46,
      "g": 255,
      "b": 156
    },
    {
      "r": 41,
      "g": 255,
      "b": 134
    },
    {
      "r": 37,
      "g": 255,
      "b": 115
    },
    {
      "r": 83,
      "g": 56,
      "b": 255
    },
    {
      "r": 84,
      "g": 67,
      "b": 255
    },
    {
      "r": 85,
      "g": 77,
      "b": 255
    },
    {
      "r": 86,
      "g": 104,
      "b": 255
    },
    {
      "r": 89,
      "g": 113,
      "b": 255
    },
    {
      "r": 90,
      "g": 126,
      "b": 255
    },
    {
      "r": 94,
      "g": 170,
      "b": 255
    },
    {
      "r": 102,
      "g": 242,
      "b": 255
    },
    {
      "r": 84,
      "g": 255,
      "b": 193
    },
    {
      "r": 68,
      "g": 255,
      "b": 140
    },
    {
      "r": 56,
      "g": 255,
      "b": 101
    },
    {
      "r": 110,
      "g": 58,
      "b": 255
    },
    {
      "r": 112,
      "g": 68,
      "b": 255
    },
    {
      "r": 116,
      "g": 91,
      "b": 255
    },
    {
      "r": 120,
      "g": 117,
      "b": 255
    },
    {
      "r": 124,
      "g": 145,
      "b": 255
    },
    {
      "r": 130,
      "g": 176,
      "b": 255
    },
    {
      "r": 149,
      "g": 222,
      "b": 255
    },
    {
      "r": 142,
      "g": 253,
      "b": 255
    },
    {
      "r": 127,
      "g": 255,
      "b": 216
    },
    {
      "r": 114,
      "g": 255,
      "b": 183
    },
    {
      "r": 103,
      "g": 255,
      "b": 156
    },
    {
      "r": 94,
      "g": 255,
      "b": 132
    },
    {
      "r": 86,
      "g": 255,
      "b": 111
    },
    {
      "r": 78,
      "g": 255,
      "b": 93
    },
    {
      "r": 72,
      "g": 255,
      "b": 77
    },
    {
      "r": 87,
      "g": 255,
      "b": 71
    },
    {
      "r": 62,
      "g": 255,
      "b": 51
    },
    {
      "r": 143,
      "g": 70,
      "b": 255
    },
    {
      "r": 140,
      "g": 112,
      "b": 255
    },
    {
      "r": 170,
      "g": 186,
      "b": 255
    },
    {
      "r": 178,
      "g": 255,
      "b": 240
    },
    {
      "r": 143,
      "g": 255,
      "b": 169
    },
    {
      "r": 118,
      "g": 255,
      "b": 119
    },
    {
      "r": 100,
      "g": 255,
      "b": 82
    },
    {
      "r": 85,
      "g": 255,
      "b": 53
    },
    {
      "r": 74,
      "g": 255,
      "b": 30
    },
    {
      "r": 178,
      "g": 72,
      "b": 255
    },
    {
      "r": 192,
      "g": 105,
      "b": 255
    },
    {
      "r": 195,
      "g": 127,
      "b": 255
    },
    {
      "r": 205,
      "g": 160,
      "b": 255
    },
    {
      "r": 216,
      "g": 198,
      "b": 255
    },
    {
      "r": 191,
      "g": 255,
      "b": 186
    },
    {
      "r": 173,
      "g": 255,
      "b": 155
    },
    {
      "r": 162,
      "g": 255,
      "b": 125
    },
    {
      "r": 143,
      "g": 255,
      "b": 106
    },
    {
      "r": 130,
      "g": 255,
      "b": 91
    },
    {
      "r": 121,
      "g": 255,
      "b": 71
    },
    {
      "r": 112,
      "g": 255,
      "b": 56
    },
    {
      "r": 104,
      "g": 255,
      "b": 43
    },
    {
      "r": 93,
      "g": 255,
      "b": 37
    },
    {
      "r": 217,
      "g": 74,
      "b": 255
    },
    {
      "r": 242,
      "g": 140,
      "b": 255
    },
    {
      "r": 255,
      "g": 199,
      "b": 240
    },
    {
      "r": 203,
      "g": 255,
      "b": 140
    },
    {
      "r": 169,
      "g": 255,
      "b": 94
    },
    {
      "r": 143,
      "g": 255,
      "b": 59
    },
    {
      "r": 124,
      "g": 255,
      "b": 33
    },
    {
      "r": 255,
      "g": 84,
      "b": 255
    },
    {
      "r": 255,
      "g": 112,
      "b": 255
    },
    {
      "r": 255,
      "g": 123,
      "b": 222
    },
    {
      "r": 255,
      "g": 148,
      "b": 208
    },
    {
      "r": 255,
      "g": 166,
      "b": 205
    },
    {
      "r": 255,
      "g": 194,
      "b": 204
    },
    {
      "r": 255,
      "g": 224,
      "b": 166
    },
    {
      "r": 255,
      "g": 251,
      "b": 151
    },
    {
      "r": 233,
      "g": 255,
      "b": 125
    },
    {
      "r": 210,
      "g": 255,
      "b": 91
    },
    {
      "r": 194,
      "g": 255,
      "b": 81
    },
    {
      "r": 179,
      "g": 255,
      "b": 63
    },
    {
      "r": 154,
      "g": 255,
      "b": 32
    },
    {
      "r": 158,
      "g": 255,
      "b": 37
    },
    {
      "r": 255,
      "g": 65,
      "b": 208
    },
    {
      "r": 255,
      "g": 108,
      "b": 184
    },
    {
      "r": 255,
      "g": 152,
      "b": 159
    },
    {
      "r": 255,
      "g": 198,
      "b": 133
    },
    {
      "r": 255,
      "g": 253,
      "b": 95
    },
    {
      "r": 220,
      "g": 255,
      "b": 67
    },
    {
      "r": 188,
      "g": 255,
      "b": 36
    },
    {
      "r": 255,
      "g": 57,
      "b": 176
    },
    {
      "r": 255,
      "g": 76,
      "b": 164
    },
    {
      "r": 255,
      "g": 96,
      "b": 153
    },
    {
      "r": 255,
      "g": 125,
      "b": 150
    },
    {
      "r": 255,
      "g": 136,
      "b": 130
    },
    {
      "r": 255,
      "g": 166,
      "b": 126
    },
    {
      "r": 255,
      "g": 176,
      "b": 106
    },
    {
      "r": 255,
      "g": 197,
      "b": 94
    },
    {
      "r": 255,
      "g": 223,
      "b": 88
    },
    {
      "r": 255,
      "g": 240,
      "b": 69
    },
    {
      "r": 248,
      "g": 255,
      "b": 56
    },
    {
      "r": 228,
      "g": 255,
      "b": 38
    },
    {
      "r": 255,
      "g": 36,
      "b": 167
    },
    {
      "r": 255,
      "g": 88,
      "b": 134
    },
    {
      "r": 255,
      "g": 122,
      "b": 106
    },
    {
      "r": 255,
      "g": 160,
      "b": 77
    },
    {
      "r": 255,
      "g": 207,
      "b": 86
    },
    {
      "r": 255,
      "g": 237,
      "b": 37
    },
    {
      "r": 255,
      "g": 41,
      "b": 143
    },
    {
      "r": 255,
      "g": 61,
      "b": 116
    },
    {
      "r": 255,
      "g": 84,
      "b": 111
    },
    {
      "r": 255,
      "g": 94,
      "b": 96
    },
    {
      "r": 255,
      "g": 110,
      "b": 86
    },
    {
      "r": 255,
      "g": 127,
      "b": 76
    },
    {
      "r": 255,
      "g": 144,
      "b": 65
    },
    {
      "r": 255,
      "g": 162,
      "b": 55
    },
    {
      "r": 255,
      "g": 179,
      "b": 44
    },
    {
      "r": 255,
      "g": 197,
      "b": 33
    },
    {
      "r": 255,
      "g": 70,
      "b": 88
    },
    {
      "r": 254,
      "g": 107,
      "b": 64
    },
    {
      "r": 255,
      "g": 132,
      "b": 50
    },
    {
      "r": 255,
      "g": 164,
      "b": 30
    },
    {
      "r": 255,
      "g": 22,
      "b": 98
    },
    {
      "r": 255,
      "g": 50,
      "b": 80
    },
    {
      "r": 254,
      "g": 89,
      "b": 64
    },
    {
      "r": 255,
      "g": 92,
      "b": 54
    },
    {
      "r": 255,
      "g": 121,
      "b": 36
    },
    {
      "r": 255,
      "g": 138,
      "b": 37
    },
    {
      "r": 255,
      "g": 111,
      "b": 25
    },
    {
      "r": 255,
      "g": 41,
      "b": 54
    },
    {
      "r": 255,
      "g": 53,
      "b": 46
    },
    {
      "r": 255,
      "g": 78,
      "b": 30
    },
    {
      "r": 255,
      "g": 61,
      "b": 28
    },
    {
      "r": 255,
      "g": 39,
      "b": 37
    },
    {
      "r": 255,
      "g": 57,
      "b": 18
    },
    {
      "r": 255,
      "g": 29,
      "b": 15
    },
    {
      "r": 255,
      "g": 14,
      "b": 8
    }
]
}</span></pre>
</div>
<span class="cnblogs_code_collapse">color_rgb_256.json</span></div>
<div class="cnblogs_code"><img id="code_img_closed_0de0e9cb-ea55-4535-b736-ac376a8ceff6" class="code_img_closed lazyload" data-src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img id="code_img_opened_0de0e9cb-ea55-4535-b736-ac376a8ceff6" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_0de0e9cb-ea55-4535-b736-ac376a8ceff6" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> android.graphics.Bitmap
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> android.graphics.Color
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> android.util.Log
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> com.blankj.utilcode.util.GsonUtils
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> com.blankj.utilcode.util.ScreenUtils
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> com.blankj.utilcode.util.Utils
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> com.google.gson.Gson
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> com.google.gson.reflect.TypeToken
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> kotlinx.coroutines.Dispatchers
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> kotlinx.coroutines.MainScope
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> kotlinx.coroutines.launch
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.concurrent.CopyOnWriteArrayList
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> kotlin.math.abs


object AmbientLightColorPickManager {

    </span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">const</span> val TAG = "AmbientLightColorPickManager"

    <span style="color: rgba(0, 0, 255, 1)">private</span> var scope =<span style="color: rgba(0, 0, 0, 1)"> MainScope()
    </span><span style="color: rgba(0, 0, 255, 1)">private</span> val mWidth = ScreenUtils.getScreenWidth() / 2
    <span style="color: rgba(0, 0, 255, 1)">private</span> val mHeight = ScreenUtils.getScreenHeight() / 2

    <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 256色</span>
    <span style="color: rgba(0, 0, 255, 1)">private</span> val tableList = mutableListOf&lt;ColorTableBean&gt;<span style="color: rgba(0, 0, 0, 1)">()

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 原图色</span>
    <span style="color: rgba(0, 0, 255, 1)">private</span> val originalList = CopyOnWriteArrayList&lt;ColorTableBean&gt;<span style="color: rgba(0, 0, 0, 1)">()

    var test1Listener: ((Int) </span>-&gt; Unit)? = <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">
    var test2Listener: ((Int, Int, Int) </span>-&gt; Unit)? = <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">

    @JvmStatic
    fun init() {
      log(</span>"$TAG init"<span style="color: rgba(0, 0, 0, 1)">)
      scope.launch(Dispatchers.IO) {
            initHsvColor()
      }
    }

    </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> fun initHsvColor() {
      tableList.clear()
      runCatching {
            val json </span>=<span style="color: rgba(0, 0, 0, 1)"> SharedPreferencesUtils.getRGB256HsvColor(Utils.getApp())
            val listType </span>= object : TypeToken&lt;MutableList&lt;ColorTableBean&gt;&gt;<span style="color: rgba(0, 0, 0, 1)">() {}.type
            Gson().fromJson</span>&lt;MutableList&lt;ColorTableBean&gt;&gt;(json, listType)?<span style="color: rgba(0, 0, 0, 1)">.let {
                tableList.addAll(it)
                log(</span>"initHsvColor xml list size=${tableList.size}"<span style="color: rgba(0, 0, 0, 1)">)
            }
      }.getOrElse {
            Log.e(TAG, </span>"initHsvColor Exception ${it.message}"<span style="color: rgba(0, 0, 0, 1)">)
      }
      </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (tableList.isEmpty()) {
            saveHsvColor().let {
                </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (it.isNotEmpty()) {
                  tableList.addAll(it)
                }
            }
            log(</span>"initHsvColor json list size=${tableList.size}"<span style="color: rgba(0, 0, 0, 1)">)
      }
    }

    </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)"> 将本地rgb色值转换成hsv保存到本地 </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
    <span style="color: rgba(0, 0, 255, 1)">private</span> fun saveHsvColor(): MutableList&lt;ColorTableBean&gt;<span style="color: rgba(0, 0, 0, 1)"> {
      log(</span>"saveHsvColor"<span style="color: rgba(0, 0, 0, 1)">)
      val hsvList </span>= mutableListOf&lt;ColorTableBean&gt;<span style="color: rgba(0, 0, 0, 1)">()
      runCatching {
            val assetManager </span>=<span style="color: rgba(0, 0, 0, 1)"> Utils.getApp().assets
            val file </span>= assetManager.open("color_rgb_256.json"<span style="color: rgba(0, 0, 0, 1)">)
            val jsonStr </span>=<span style="color: rgba(0, 0, 0, 1)"> file.bufferedReader().readText()
            file.close()
            val bean </span>= Gson().fromJson(jsonStr, AmbientLightList::<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">.java)
            </span><span style="color: rgba(0, 0, 255, 1)">for</span> (i in 0<span style="color: rgba(0, 0, 0, 1)"> until bean.list.size) {
                bean.list.apply {
                  val myColor </span>=<span style="color: rgba(0, 0, 0, 1)"> Color.rgb(r, g, b)
                  val hsvColors </span>= FloatArray(3<span style="color: rgba(0, 0, 0, 1)">)
                  Color.colorToHSV(myColor, hsvColors)
                  val lab </span>=<span style="color: rgba(0, 0, 0, 1)"> ColorEabLabUtils.rGBToLab(r, g, b)
                  val bean </span>=<span style="color: rgba(0, 0, 0, 1)"> ColorTableBean(hsvColors, lab, myColor)
                  hsvList.add(bean)
                }
            }
            val json </span>=<span style="color: rgba(0, 0, 0, 1)"> Gson().toJson(hsvList)
            log(</span>"saveHsvColor hsvListSize=${hsvList.size}"<span style="color: rgba(0, 0, 0, 1)">)
            SharedPreferencesUtils.setRGB256HsvColor(Utils.getApp(), json)
      }.getOrElse {
            Log.e(TAG, </span>"saveHsvColor Exception ${it.message}"<span style="color: rgba(0, 0, 0, 1)">)
      }
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> hsvList
    }


    </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)"> 设置氛围灯 </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
    @JvmStatic
    fun setAmbientLight(displayId: Int, index: Int) {
      </span><span style="color: rgba(0, 0, 255, 1)">if</span> (displayId != DisplayParameter.DISPLAY_CSD.displayId) <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
      log(</span>"setAmbientLight displayId=$displayId"<span style="color: rgba(0, 0, 0, 1)">)
      scope.launch(Dispatchers.IO) {
            </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (originalList.isEmpty()) {
                Log.w(TAG, </span>"setAmbientLight hueList is null"<span style="color: rgba(0, 0, 0, 1)">)
                </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">@launch
            }
            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (index &lt; 0 || index &gt;=<span style="color: rgba(0, 0, 0, 1)"> originalList.size) {
                Log.w(TAG, </span>"setAmbientLight 索引异常"<span style="color: rgba(0, 0, 0, 1)">)
                </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">@launch
            }
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 氛围灯取色</span>
<span style="color: rgba(0, 0, 0, 1)">            setBytesFunctionValue(index)
      }
    }

    @JvmStatic
    fun switchLight(isOn: Boolean) {
      log(</span>"switchLight isOn=$isOn"<span style="color: rgba(0, 0, 0, 1)">)
    }

    </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)"> 初始化资源 </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
    @JvmStatic
    fun loadData(displayId: Int, pictures: List</span>&lt;String&gt;<span style="color: rgba(0, 0, 0, 1)">) {
      </span><span style="color: rgba(0, 0, 255, 1)">if</span> (displayId != DisplayParameter.DISPLAY_CSD.displayId) <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
      log(</span>"loadData pictures size=${pictures.size} pictures $pictures"<span style="color: rgba(0, 0, 0, 1)">)
      originalList.clear()
      </span><span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)"> ((_, picture) in pictures.withIndex()) {
            runCatching {
                val bitmap </span>=<span style="color: rgba(0, 0, 0, 1)"> GlideCacheUtils.loadImageAsBitmap(picture, mWidth, mHeight)
                originalList.add(generate(bitmap))
            }.getOrElse {
                Log.e(TAG, </span>"loadData exception ${it.message}"<span style="color: rgba(0, 0, 0, 1)">)
            }
      }
      log(</span>"loadData hueList size=${originalList.size}"<span style="color: rgba(0, 0, 0, 1)">)
    }

    </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> fun setFunctionValue(functionId: Int, value: Int, zone: Int) {
      
    }

    </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> fun setBytesFunctionValue(index: Int) {
      </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
            originalList.let {
                test1Listener</span>?<span style="color: rgba(0, 0, 0, 1)">.invoke(it.color)
                test2Listener</span>?<span style="color: rgba(0, 0, 0, 1)">.invoke(
                  findColor(it.hue()).colorTip, findLabColor(it), findTestColor(it.labArray)
                )
            }
      } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (e: Exception) {
            Log.e(TAG, </span>"setBytesFunctionValue Exception $e"<span style="color: rgba(0, 0, 0, 1)">)
      }
    }

    </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> fun findColor(bgHue: Float): ColorTipBean {
      </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (tableList.isEmpty()) {
            Log.w(TAG, </span>"findColor hsvList is null"<span style="color: rgba(0, 0, 0, 1)">)
            </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> ColorTipBean(Color.WHITE)
      }
      var result </span>= tableList
      var minDiff </span>= abs(result.hue() -<span style="color: rgba(0, 0, 0, 1)"> bgHue)
      </span><span style="color: rgba(0, 0, 255, 1)">for</span> (i in 0<span style="color: rgba(0, 0, 0, 1)"> until tableList.size) {
            val currentDiff </span>= abs(tableList.hue() -<span style="color: rgba(0, 0, 0, 1)"> bgHue)
            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (currentDiff &lt;<span style="color: rgba(0, 0, 0, 1)"> minDiff) {
                minDiff </span>=<span style="color: rgba(0, 0, 0, 1)"> currentDiff
                result </span>=<span style="color: rgba(0, 0, 0, 1)"> tableList
            }
      }
      log(</span>"findColor bgHue=$bgHue,minDiff=$minDiff,result=$result"<span style="color: rgba(0, 0, 0, 1)">)
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> ColorTipBean(result.color)
    }

    </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> fun findLabColor(bean: ColorTableBean): Int {
      var color </span>=<span style="color: rgba(0, 0, 0, 1)"> Color.WHITE
      var minDiff </span>=<span style="color: rgba(0, 0, 0, 1)"> Double.MAX_VALUE
      tableList.forEachIndexed { index, it </span>-&gt;<span style="color: rgba(0, 0, 0, 1)">
            val distance </span>=<span style="color: rgba(0, 0, 0, 1)"> ColorEabLabUtils.deltaE76(it.labArray, bean.labArray)
            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (distance &lt;<span style="color: rgba(0, 0, 0, 1)"> minDiff) {
                minDiff </span>=<span style="color: rgba(0, 0, 0, 1)"> distance
                color </span>=<span style="color: rgba(0, 0, 0, 1)"> it.color
            }
      }
      log(</span>"findLabColor minDiff=$minDiff,color=[${bean.color},$color]"<span style="color: rgba(0, 0, 0, 1)">)
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (minDiff &lt; 26) color <span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> findColor(bean.hue()).colorTip
    }

    </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> fun findTestColor(list: DoubleArray): Int {
      var color </span>=<span style="color: rgba(0, 0, 0, 1)"> Color.WHITE
      var minDiff </span>=<span style="color: rgba(0, 0, 0, 1)"> Double.MAX_VALUE
      tableList.forEachIndexed { index, it </span>-&gt;<span style="color: rgba(0, 0, 0, 1)">
            val distance </span>=<span style="color: rgba(0, 0, 0, 1)"> ColorEabLabUtils.deltaE76(it.labArray, list)
            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (distance &lt;<span style="color: rgba(0, 0, 0, 1)"> minDiff) {
                minDiff </span>=<span style="color: rgba(0, 0, 0, 1)"> distance
                color </span>=<span style="color: rgba(0, 0, 0, 1)"> it.color
            }
      }
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> color
    }

    </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> fun getColors(bean: ColorTableBean): ByteArray {
      val result </span>= mutableListOf&lt;ColorTipBean&gt;<span style="color: rgba(0, 0, 0, 1)">()
      val colorBean </span>=<span style="color: rgba(0, 0, 0, 1)"> ColorTipBean(findLabColor(bean))
      result.add(colorBean)
      result.add(colorBean)
      result.add(colorBean)
      val json </span>=<span style="color: rgba(0, 0, 0, 1)"> GsonUtils.toJson(ColorLightBean(result).list)
      log(</span>"setBytesFunctionValue json=$json"<span style="color: rgba(0, 0, 0, 1)">)
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> json.toByteArray()
    }

    </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> fun generate(newMap: Bitmap): ColorTableBean {
      val dominantColor </span>=<span style="color: rgba(0, 0, 0, 1)"> ColorEabLabUtils.getPerceptuallyDominantColor(newMap)
      val hsvArray </span>= FloatArray(3<span style="color: rgba(0, 0, 0, 1)">)
      Color.colorToHSV(dominantColor, hsvArray)
      val labArray </span>=<span style="color: rgba(0, 0, 0, 1)"> ColorEabLabUtils.rGBToLab(dominantColor)
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> ColorTableBean(hsvArray, labArray, dominantColor)
    }

    </span><span style="color: rgba(0, 0, 255, 1)">private</span> fun log(str: String) =<span style="color: rgba(0, 0, 0, 1)"> Log.d(TAG, str)

}</span></pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>&nbsp;</p><br><br>
来源:https://www.cnblogs.com/LiuZhen/p/19157538
頁: [1]
查看完整版本: 氛围灯动态屏保取色方案二