欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android利用Palette實(shí)現(xiàn)提取圖片顏色

 更新時(shí)間:2022年03月21日 17:00:53   作者:BennuCTech  
Palette是一個(gè)類似調(diào)色板的工具類,根據(jù)傳入的bitmap,提取出主體顏色,使得圖片和顏色更加搭配,界面更協(xié)調(diào)。本文將詳解如何利用Palette實(shí)現(xiàn)提取圖片顏色,需要的可以參考一下

前言

Palette即調(diào)色板這個(gè)功能其實(shí)很早就發(fā)布了,Jetpack同樣將這個(gè)功能也納入其中,想要使用這個(gè)功能,需要先依賴庫

implementation 'androidx.palette:palette:1.0.0'

本篇文章就來講解一下如何使用Palette在圖片中提取顏色。

創(chuàng)建Palette

創(chuàng)建Palette其實(shí)很簡(jiǎn)單,如下

var builder = Palette.from(bitmap)
var palette = builder.generate()

這樣,我們就通過一個(gè)Bitmap創(chuàng)建一個(gè)Pallete對(duì)象。

注意:直接使用Palette.generate(bitmap)也可以,但是這個(gè)方法已經(jīng)不推薦使用了,網(wǎng)上很多老文章中依然使用這種方式。建議還是使用Palette.Builder這種方式。

generate()這個(gè)函數(shù)是同步的,當(dāng)然考慮圖片處理可能比較耗時(shí),Android同時(shí)提供了異步函數(shù)

public AsyncTask<Bitmap, Void, Palette> generate(
        @NonNull final PaletteAsyncListener listener) {

通過一個(gè)PaletteAsyncListener來獲取Palette實(shí)例,這個(gè)接口如下:

public interface PaletteAsyncListener {
    /**
     * Called when the {@link Palette} has been generated. {@code null} will be passed when an
     * error occurred during generation.
     */
    void onGenerated(@Nullable Palette palette);
}

提取顏色

有了Palette實(shí)例,就可以通過Palette對(duì)象的相應(yīng)函數(shù)就可以獲取圖片中的顏色,而且不只一種顏色,下面一一列舉:

  • getDominantColor:獲取圖片中的主色調(diào)
  • getMutedColor:獲取圖片中柔和的顏色
  • getDarkMutedColor:獲取圖片中柔和的暗色
  • getLightMutedColor:獲取圖片中柔和的亮色
  • getVibrantColor:獲取圖片中有活力的顏色
  • getDarkVibrantColor:獲取圖片中有活力的暗色
  • getLightVibrantColor:獲取圖片中有活力的亮色

這些函數(shù)都需要提供一個(gè)默認(rèn)顏色,如果這個(gè)顏色Swatch無效則使用這個(gè)默認(rèn)顏色。光這么說不直觀,我們來測(cè)試一下,代碼如下:

var bitmap = BitmapFactory.decodeResource(resources, R.mipmap.a)
var builder = Palette.from(bitmap)
var palette = builder.generate()
color0.setBackgroundColor(palette.getDominantColor(Color.WHITE))
color1.setBackgroundColor(palette.getMutedColor(Color.WHITE))
color2.setBackgroundColor(palette.getDarkMutedColor(Color.WHITE))
color3.setBackgroundColor(palette.getLightMutedColor(Color.WHITE))
color4.setBackgroundColor(palette.getVibrantColor(Color.WHITE))
color5.setBackgroundColor(palette.getDarkVibrantColor(Color.WHITE))
color6.setBackgroundColor(palette.getLightVibrantColor(Color.WHITE))

運(yùn)行后結(jié)果如下:

這樣各個(gè)顏色的差別就一目了然。除了上面的函數(shù),還可以使用getColorForTarget這個(gè)函數(shù),如下:

@ColorInt
public int getColorForTarget(@NonNull final Target target, @ColorInt final int defaultColor) {

這個(gè)函數(shù)需要一個(gè)Target,提供了6個(gè)靜態(tài)字段,如下:

/**
 * A target which has the characteristics of a vibrant color which is light in luminance.
*/
public static final Target LIGHT_VIBRANT;

/**
 * A target which has the characteristics of a vibrant color which is neither light or dark.
 */
public static final Target VIBRANT;

/**
 * A target which has the characteristics of a vibrant color which is dark in luminance.
 */
public static final Target DARK_VIBRANT;

/**
 * A target which has the characteristics of a muted color which is light in luminance.
 */
public static final Target LIGHT_MUTED;

/**
 * A target which has the characteristics of a muted color which is neither light or dark.
 */
public static final Target MUTED;

/**
 * A target which has the characteristics of a muted color which is dark in luminance.
 */
public static final Target DARK_MUTED;

其實(shí)就是對(duì)應(yīng)著上面除了主色調(diào)之外的六種顏色。

文字顏色自動(dòng)適配

在上面的運(yùn)行結(jié)果中可以看到,每個(gè)顏色上面的文字都很清楚的顯示,而且它們并不是同一種顏色。其實(shí)這也是Palette提供的功能。

通過下面的函數(shù),我們可以得到各種色調(diào)所對(duì)應(yīng)的Swatch對(duì)象:

  • getDominantSwatch
  • getMutedSwatch
  • getDarkMutedSwatch
  • getLightMutedSwatch
  • getVibrantSwatch
  • getDarkVibrantSwatch
  • getLightVibrantSwatch

注意:同上面一樣,也可以通過getSwatchForTarget(@NonNull final Target target)來獲取

Swatch類提供了以下函數(shù):

  • getPopulation(): 樣本中的像素?cái)?shù)量
  • getRgb(): 顏色的RBG值
  • getHsl(): 顏色的HSL值
  • getBodyTextColor(): 能都適配這個(gè)Swatch的主體文字的顏色值
  • getTitleTextColor(): 能都適配這個(gè)Swatch的標(biāo)題文字的顏色值

所以我們通過getBodyTextColor()getTitleTextColor()可以很容易得到在這個(gè)顏色上可以很好現(xiàn)實(shí)的標(biāo)題和主體文本顏色。所以上面的測(cè)試代碼完整如下:

var bitmap = BitmapFactory.decodeResource(resources, R.mipmap.a)
var builder = Palette.from(bitmap)
var palette = builder.generate()

color0.setBackgroundColor(palette.getDominantColor(Color.WHITE))
color0.setTextColor(palette.dominantSwatch?.bodyTextColor ?: Color.WHITE)

color1.setBackgroundColor(palette.getMutedColor(Color.WHITE))
color1.setTextColor(palette.mutedSwatch?.bodyTextColor ?: Color.WHITE)

color2.setBackgroundColor(palette.getDarkMutedColor(Color.WHITE))
color2.setTextColor(palette.darkMutedSwatch?.bodyTextColor ?: Color.WHITE)

color3.setBackgroundColor(palette.getLightMutedColor(Color.WHITE))
color3.setTextColor(palette.lightMutedSwatch?.bodyTextColor ?: Color.WHITE)

color4.setBackgroundColor(palette.getVibrantColor(Color.WHITE))
color4.setTextColor(palette.vibrantSwatch?.bodyTextColor ?: Color.WHITE)

color5.setBackgroundColor(palette.getDarkVibrantColor(Color.WHITE))
color5.setTextColor(palette.darkVibrantSwatch?.bodyTextColor ?: Color.WHITE)

color6.setBackgroundColor(palette.getLightVibrantColor(Color.WHITE))
color6.setTextColor(palette.lightVibrantSwatch?.bodyTextColor ?: Color.WHITE)

這樣每個(gè)顏色上的文字都可以清晰的顯示。

那么這個(gè)標(biāo)題和主體文本顏色有什么差別,他們又是如何的到的?我們來看看源碼:

/**
 * Returns an appropriate color to use for any 'title' text which is displayed over this
 * {@link Swatch}'s color. This color is guaranteed to have sufficient contrast.
 */
@ColorInt
public int getTitleTextColor() {
    ensureTextColorsGenerated();
    return mTitleTextColor;
}

/**
 * Returns an appropriate color to use for any 'body' text which is displayed over this
 * {@link Swatch}'s color. This color is guaranteed to have sufficient contrast.
 */
@ColorInt
public int getBodyTextColor() {
    ensureTextColorsGenerated();
    return mBodyTextColor;
}

可以看到都會(huì)先執(zhí)行ensureTextColorsGenerated(),它的源碼如下:

private void ensureTextColorsGenerated() {
    if (!mGeneratedTextColors) {
        // First check white, as most colors will be dark
        final int lightBodyAlpha = ColorUtils.calculateMinimumAlpha(
                Color.WHITE, mRgb, MIN_CONTRAST_BODY_TEXT);
        final int lightTitleAlpha = ColorUtils.calculateMinimumAlpha(
                Color.WHITE, mRgb, MIN_CONTRAST_TITLE_TEXT);

        if (lightBodyAlpha != -1 && lightTitleAlpha != -1) {
            // If we found valid light values, use them and return
            mBodyTextColor = ColorUtils.setAlphaComponent(Color.WHITE, lightBodyAlpha);
            mTitleTextColor = ColorUtils.setAlphaComponent(Color.WHITE, lightTitleAlpha);
            mGeneratedTextColors = true;
            return;
        }

        final int darkBodyAlpha = ColorUtils.calculateMinimumAlpha(
                Color.BLACK, mRgb, MIN_CONTRAST_BODY_TEXT);
        final int darkTitleAlpha = ColorUtils.calculateMinimumAlpha(
                Color.BLACK, mRgb, MIN_CONTRAST_TITLE_TEXT);

        if (darkBodyAlpha != -1 && darkTitleAlpha != -1) {
            // If we found valid dark values, use them and return
            mBodyTextColor = ColorUtils.setAlphaComponent(Color.BLACK, darkBodyAlpha);
            mTitleTextColor = ColorUtils.setAlphaComponent(Color.BLACK, darkTitleAlpha);
            mGeneratedTextColors = true;
            return;
        }

        // If we reach here then we can not find title and body values which use the same
        // lightness, we need to use mismatched values
        mBodyTextColor = lightBodyAlpha != -1
                ? ColorUtils.setAlphaComponent(Color.WHITE, lightBodyAlpha)
                : ColorUtils.setAlphaComponent(Color.BLACK, darkBodyAlpha);
        mTitleTextColor = lightTitleAlpha != -1
                ? ColorUtils.setAlphaComponent(Color.WHITE, lightTitleAlpha)
                : ColorUtils.setAlphaComponent(Color.BLACK, darkTitleAlpha);
        mGeneratedTextColors = true;
    }
}

通過代碼可以看到,這兩種文本顏色實(shí)際上要么是白色要么是黑色,只是透明度Alpha不同。

這里面有一個(gè)關(guān)鍵函數(shù),即ColorUtils.calculateMinimumAlpha()

public static int calculateMinimumAlpha(@ColorInt int foreground, @ColorInt int background,
        float minContrastRatio) {
    if (Color.alpha(background) != 255) {
        throw new IllegalArgumentException("background can not be translucent: #"
                + Integer.toHexString(background));
    }

    // First lets check that a fully opaque foreground has sufficient contrast
    int testForeground = setAlphaComponent(foreground, 255);
    double testRatio = calculateContrast(testForeground, background);
    if (testRatio < minContrastRatio) {
        // Fully opaque foreground does not have sufficient contrast, return error
        return -1;
    }

    // Binary search to find a value with the minimum value which provides sufficient contrast
    int numIterations = 0;
    int minAlpha = 0;
    int maxAlpha = 255;

    while (numIterations <= MIN_ALPHA_SEARCH_MAX_ITERATIONS &&
            (maxAlpha - minAlpha) > MIN_ALPHA_SEARCH_PRECISION) {
        final int testAlpha = (minAlpha + maxAlpha) / 2;

        testForeground = setAlphaComponent(foreground, testAlpha);
        testRatio = calculateContrast(testForeground, background);

        if (testRatio < minContrastRatio) {
            minAlpha = testAlpha;
        } else {
            maxAlpha = testAlpha;
        }

        numIterations++;
    }

    // Conservatively return the max of the range of possible alphas, which is known to pass.
    return maxAlpha;
}

它根據(jù)背景色和前景色計(jì)算前景色最合適的Alpha。這期間如果小于minContrastRatio則返回-1,說明這個(gè)前景色不合適。而標(biāo)題和主體文本的差別就是這個(gè)minContrastRatio不同而已。

回到ensureTextColorsGenerated代碼可以看到,先根據(jù)當(dāng)前色調(diào),計(jì)算出白色前景色的Alpha,如果兩個(gè)Alpha都不是-1,就返回對(duì)應(yīng)顏色;否則計(jì)算黑色前景色的Alpha,如果都不是-1,返回對(duì)應(yīng)顏色;否則標(biāo)題和主體文本一個(gè)用白色一個(gè)用黑色,返回對(duì)應(yīng)顏色即可。

更多功能

上面我們創(chuàng)建Palette時(shí)先通過Palette.from(bitmap)的到了一個(gè)Palette.Builder對(duì)象,通過這個(gè)builder可以實(shí)現(xiàn)更多功能,比如:

  • addFilter:增加一個(gè)過濾器
  • setRegion:設(shè)置圖片上的提取區(qū)域
  • maximumColorCount:調(diào)色板的最大顏色數(shù)

等等

總結(jié)

通過上面我們看到,Palette的功能很強(qiáng)大,但是它使用起來非常簡(jiǎn)單,可以讓我們很方便的提取圖片中的顏色,并且適配合適的文字顏色。同時(shí)注意因?yàn)镃olorUtils是public的,所以當(dāng)我們需要文字自動(dòng)適配顏色的情況時(shí),也可以通過ColorUtils的幾個(gè)函數(shù)自己實(shí)現(xiàn)計(jì)算動(dòng)態(tài)顏色的方案。

以上就是Android利用Palette實(shí)現(xiàn)提取圖片顏色的詳細(xì)內(nèi)容,更多關(guān)于Android Palette提取顏色的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論