获取Bitmap中主色调的取色器

颜色空间

RGB色彩空间
  • RGB颜色空间以R(红)、G(绿)、B(蓝)三种基本色为基础,进行不同程度的叠加,呈现不同的颜色–>三原色模式
  • RGB颜色空间 可以使用一个立方体来表示颜色,黑、蓝、绿、青、红、紫、黄、白8种常见颜色分别位居立方体的8个顶点,通常将黑色置于三维直角坐标系的原点,绿蓝红分别分别置于xyz轴上,个参数的取值范围是:R : 0 - 255, G : 0 - 255, B : 0 - 255
  • 其中(0,0,0) ->(255,255,255)的提对角线表示从黑色到白色的灰度值
HSV(又称HSB)颜色空间
  • 根据颜色的只管特性创建一种颜色空间 ->六角锥体模型
  • H:色相取值范围(0~360度)
  • S:饱和度 取值范围[0, 1] 数值越大越接近光谱色
  • V:明度 取值范围[0,1]数值越大越明亮
  • B:明度取值范围[0%, 100%] 指的是光的亮,可以是任何一种颜色
HSL颜色空间
  • H:色相取值范围(0~360度)
  • S:饱和度 取值范围[0, 1] 数值越大越接近光谱色
  • L:亮度,指的是白的量,可以是任何一种颜色
Palette
Palette简介
  • Palette 是 Android L SDK 中的新特性,可以使用 Palette 从图像中提取出突出的颜色(主色调)。
方法释义
Palette.Builder生成器类,生成 Palette 实例
Palette.Filter过滤器接口,使 Palette 有更加细腻的颜色过滤
Palette.PaletteAsyncListener异步加载监听
pattle.Swatch提供获取结果的色彩样本
from(List<Palette.Switch> switches)通过预设的 Palette.Swatch 颜色样本列表 来生成 Palette
from(Bitmap bitmap)通过返回 Palette.Builder 实例来构建 Palette
palette.getDarkMutedColor(Color.BLUE)获取到柔和的深色的颜色(可传默认值)
palette.getDarkVibrantColor(Color.BLUE)获取到活跃的深色的颜色(可传默认值)
palette.getLightMutedColor(Color.BLUE)获取到柔和的明亮的颜色(可传默认值)
palette.getLightVibrantColor(Color.BLUE)获取到活跃的明亮的颜色(可传默认值)
palette.getVibrantColor(Color.BLUE)获取图片中最活跃的颜色(也可以说整个图片出现最多的颜色)(可传默认值)
palette.getMutedColor(Color.BLUE)获取图片中一个最柔和的颜色(可传默认值)
Palette使用
  • 导入依赖:
implementation 'com.android.support:palette-v7:29.0.0'
  • 使用同步和异步方式分别创建Palette
Bitmap bm =BitmapFactory.decodeResource(getResources(),R.drawable.kale);
// 同步
Palette.Builder builder = Palette.from(bm);
Palette palette=builder.generate();
// 异步
builder.generate(bitmap, new Palette.PaletteAsyncListener() {
    @Override
    public void onGenerated(Palette palette) {
    }
}
实现获取Bitmap中主色调的取色器
fun getHslColor(context: Context?, bitmap: Bitmap?): Int {
        if (bitmap == null || context == null || context.resources == null) {
            Log.d(
                TAG,
                "getHslColor: Bitmap is null or context is null or resource is null"
            )
            return 0
        }
        val rect =
            Rect(0, 1, bitmap.width, bitmap.height - 1)
        val hsl = FloatArray(HSL_LENGTH)
        val palette = Palette.from(bitmap)
            .setRegion(rect.left, rect.top, rect.right, rect.bottom)
            .clearFilters()
            .maximumColorCount(SWATCH_LENGTH)
            .generate()
        palette?.let {
            val swatches = compare(palette.swatches)
            sMainHsl = getMutiColor(swatches)
            hsl[HUE_INDEX] = sMainHsl[HUE_INDEX]
            hsl[SATURATION_INDEX] = sMainHsl[SATURATION_INDEX]
            hsl[LIGHTNESS_INDEX] = sMainHsl[LIGHTNESS_INDEX]
            // If it is colored hsl you can display the corresponding color according to the current color range.
//            if (Math.abs(hsl[SATURATION_INDEX]) >= FLOAT_COMPARE_VALUE ||
//                Math.abs(hsl[LIGHTNESS_INDEX] - CHROMATIC_HSL) > FLOAT_COMPARE_VALUE) {
//                return handleMutiColor(hsl[HUE_INDEX], context)
//            }
            // Use demo test
            return Color.HSVToColor(hsl)
        }
        return Color.HSVToColor(hsl)
    }
取色器使用
  1. Add the JitPack repository to your build file in your root build.gradle
allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
}
  1. Add the dependency
dependencies {
    implementation 'com.github.wangjianxiandev:ColorPicker:1.0.1'
}
项目源码地址
项目展示
优化方案–lab颜色空间
  • lab是一种设备无关的颜色系统,也是一种基于生理特征的颜色系统
  • L:代表亮度取值范围(0~100)L越大代表越亮,L为0时代表黑色,L为100时代表白色
  • a:代表从绿色到红色的分量,从负数变到正数,对应颜色从绿色变到红色
  • b:代表蓝色到黄色的分量,从负数变为正数,对应颜色从蓝色变为黄色
  • a和b为0都代表灰色
  • 注意: 为什么选择使用lab空间做颜色区分:
    • 在某一个单一色调的背景下,,使用lab很快的可以通过通道进行区分明显的颜色区分的部分
private fun rgbToLab(r: Int, g: Int, b: Int): FloatArray {
    val rgbNormalizedArray = floatArrayOf(
            r.toFloat() / 255, g.toFloat() / 255, b.toFloat() / 255
    )
    for(i in 0 until rgbNormalizedArray.size) {
        if (rgbNormalizedArray[i] > 0.04045) {
            rgbNormalizedArray[i] = (Math.pow((rgbNormalizedArray[i] + 0.055) / 1.055, 2.4)).toFloat();
        } else {
            rgbNormalizedArray[i] = rgbNormalizedArray[i] / 12.92f;
        }
    }
    val xyzArray = FloatArray(3)
    xyzArray[0] =
        (rgbNormalizedArray.get(0) * 0.4124564f + rgbNormalizedArray.get(1) * 0.3575761f + rgbNormalizedArray.get(
            2
        ) * 0.1804375f) / 0.95047f
    xyzArray[1] =
        (rgbNormalizedArray.get(0) + 0.2126729f + rgbNormalizedArray.get(1) * 0.7151522f + rgbNormalizedArray.get(
            2
        ) * 0.0721750f) / 1.00000f
    xyzArray[2] =
        (rgbNormalizedArray.get(0) + 0.0193339f + rgbNormalizedArray.get(1) * 0.1191920f + rgbNormalizedArray.get(
            2
        ) * 0.9503041f) / 1.08883f
    for (i in xyzArray.indices) {
        if (xyzArray[i] > 0.008856) {
            xyzArray[i] =
                Math.pow(xyzArray[i].toDouble(), 1 / 3f.toDouble()).toFloat()
        } else {
            xyzArray[i] = xyzArray[i] * 7.787037f + 16 / 116f
        }
    }
    val labArray = FloatArray(3)
    labArray[0] = 116 * xyzArray[1] - 16
    labArray[1] = 500 * (xyzArray[0] - xyzArray[1])
    labArray[2] = 200 * (xyzArray[1] - xyzArray[2])
    return labArray
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wjxbless

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值