Home | History | Annotate | Download | only in palette
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License
     15  */
     16 
     17 package com.android.internal.graphics.palette;
     18 
     19 /*
     20  * Copyright 2015 The Android Open Source Project
     21  *
     22  * Licensed under the Apache License, Version 2.0 (the "License");
     23  * you may not use this file except in compliance with the License.
     24  * You may obtain a copy of the License at
     25  *
     26  *       http://www.apache.org/licenses/LICENSE-2.0
     27  *
     28  * Unless required by applicable law or agreed to in writing, software
     29  * distributed under the License is distributed on an "AS IS" BASIS,
     30  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     31  * See the License for the specific language governing permissions and
     32  * limitations under the License.
     33  */
     34 
     35 import android.annotation.FloatRange;
     36 
     37 /**
     38  * Copied from: frameworks/support/v7/palette/src/main/java/android/support/v7/graphics/Target.java
     39  *
     40  * A class which allows custom selection of colors in a {@link Palette}'s generation. Instances
     41  * can be created via the {@link android.support.v7.graphics.Target.Builder} class.
     42  *
     43  * <p>To use the target, use the {@link Palette.Builder#addTarget(Target)} API when building a
     44  * Palette.</p>
     45  */
     46 public final class Target {
     47 
     48     private static final float TARGET_DARK_LUMA = 0.26f;
     49     private static final float MAX_DARK_LUMA = 0.45f;
     50 
     51     private static final float MIN_LIGHT_LUMA = 0.55f;
     52     private static final float TARGET_LIGHT_LUMA = 0.74f;
     53 
     54     private static final float MIN_NORMAL_LUMA = 0.3f;
     55     private static final float TARGET_NORMAL_LUMA = 0.5f;
     56     private static final float MAX_NORMAL_LUMA = 0.7f;
     57 
     58     private static final float TARGET_MUTED_SATURATION = 0.3f;
     59     private static final float MAX_MUTED_SATURATION = 0.4f;
     60 
     61     private static final float TARGET_VIBRANT_SATURATION = 1f;
     62     private static final float MIN_VIBRANT_SATURATION = 0.35f;
     63 
     64     private static final float WEIGHT_SATURATION = 0.24f;
     65     private static final float WEIGHT_LUMA = 0.52f;
     66     private static final float WEIGHT_POPULATION = 0.24f;
     67 
     68     static final int INDEX_MIN = 0;
     69     static final int INDEX_TARGET = 1;
     70     static final int INDEX_MAX = 2;
     71 
     72     static final int INDEX_WEIGHT_SAT = 0;
     73     static final int INDEX_WEIGHT_LUMA = 1;
     74     static final int INDEX_WEIGHT_POP = 2;
     75 
     76     /**
     77      * A target which has the characteristics of a vibrant color which is light in luminance.
     78      */
     79     public static final Target LIGHT_VIBRANT;
     80 
     81     /**
     82      * A target which has the characteristics of a vibrant color which is neither light or dark.
     83      */
     84     public static final Target VIBRANT;
     85 
     86     /**
     87      * A target which has the characteristics of a vibrant color which is dark in luminance.
     88      */
     89     public static final Target DARK_VIBRANT;
     90 
     91     /**
     92      * A target which has the characteristics of a muted color which is light in luminance.
     93      */
     94     public static final Target LIGHT_MUTED;
     95 
     96     /**
     97      * A target which has the characteristics of a muted color which is neither light or dark.
     98      */
     99     public static final Target MUTED;
    100 
    101     /**
    102      * A target which has the characteristics of a muted color which is dark in luminance.
    103      */
    104     public static final Target DARK_MUTED;
    105 
    106     static {
    107         LIGHT_VIBRANT = new Target();
    108         setDefaultLightLightnessValues(LIGHT_VIBRANT);
    109         setDefaultVibrantSaturationValues(LIGHT_VIBRANT);
    110 
    111         VIBRANT = new Target();
    112         setDefaultNormalLightnessValues(VIBRANT);
    113         setDefaultVibrantSaturationValues(VIBRANT);
    114 
    115         DARK_VIBRANT = new Target();
    116         setDefaultDarkLightnessValues(DARK_VIBRANT);
    117         setDefaultVibrantSaturationValues(DARK_VIBRANT);
    118 
    119         LIGHT_MUTED = new Target();
    120         setDefaultLightLightnessValues(LIGHT_MUTED);
    121         setDefaultMutedSaturationValues(LIGHT_MUTED);
    122 
    123         MUTED = new Target();
    124         setDefaultNormalLightnessValues(MUTED);
    125         setDefaultMutedSaturationValues(MUTED);
    126 
    127         DARK_MUTED = new Target();
    128         setDefaultDarkLightnessValues(DARK_MUTED);
    129         setDefaultMutedSaturationValues(DARK_MUTED);
    130     }
    131 
    132     final float[] mSaturationTargets = new float[3];
    133     final float[] mLightnessTargets = new float[3];
    134     final float[] mWeights = new float[3];
    135     boolean mIsExclusive = true; // default to true
    136 
    137     Target() {
    138         setTargetDefaultValues(mSaturationTargets);
    139         setTargetDefaultValues(mLightnessTargets);
    140         setDefaultWeights();
    141     }
    142 
    143     Target(Target from) {
    144         System.arraycopy(from.mSaturationTargets, 0, mSaturationTargets, 0,
    145                 mSaturationTargets.length);
    146         System.arraycopy(from.mLightnessTargets, 0, mLightnessTargets, 0,
    147                 mLightnessTargets.length);
    148         System.arraycopy(from.mWeights, 0, mWeights, 0, mWeights.length);
    149     }
    150 
    151     /**
    152      * The minimum saturation value for this target.
    153      */
    154     @FloatRange(from = 0, to = 1)
    155     public float getMinimumSaturation() {
    156         return mSaturationTargets[INDEX_MIN];
    157     }
    158 
    159     /**
    160      * The target saturation value for this target.
    161      */
    162     @FloatRange(from = 0, to = 1)
    163     public float getTargetSaturation() {
    164         return mSaturationTargets[INDEX_TARGET];
    165     }
    166 
    167     /**
    168      * The maximum saturation value for this target.
    169      */
    170     @FloatRange(from = 0, to = 1)
    171     public float getMaximumSaturation() {
    172         return mSaturationTargets[INDEX_MAX];
    173     }
    174 
    175     /**
    176      * The minimum lightness value for this target.
    177      */
    178     @FloatRange(from = 0, to = 1)
    179     public float getMinimumLightness() {
    180         return mLightnessTargets[INDEX_MIN];
    181     }
    182 
    183     /**
    184      * The target lightness value for this target.
    185      */
    186     @FloatRange(from = 0, to = 1)
    187     public float getTargetLightness() {
    188         return mLightnessTargets[INDEX_TARGET];
    189     }
    190 
    191     /**
    192      * The maximum lightness value for this target.
    193      */
    194     @FloatRange(from = 0, to = 1)
    195     public float getMaximumLightness() {
    196         return mLightnessTargets[INDEX_MAX];
    197     }
    198 
    199     /**
    200      * Returns the weight of importance that this target places on a color's saturation within
    201      * the image.
    202      *
    203      * <p>The larger the weight, relative to the other weights, the more important that a color
    204      * being close to the target value has on selection.</p>
    205      *
    206      * @see #getTargetSaturation()
    207      */
    208     public float getSaturationWeight() {
    209         return mWeights[INDEX_WEIGHT_SAT];
    210     }
    211 
    212     /**
    213      * Returns the weight of importance that this target places on a color's lightness within
    214      * the image.
    215      *
    216      * <p>The larger the weight, relative to the other weights, the more important that a color
    217      * being close to the target value has on selection.</p>
    218      *
    219      * @see #getTargetLightness()
    220      */
    221     public float getLightnessWeight() {
    222         return mWeights[INDEX_WEIGHT_LUMA];
    223     }
    224 
    225     /**
    226      * Returns the weight of importance that this target places on a color's population within
    227      * the image.
    228      *
    229      * <p>The larger the weight, relative to the other weights, the more important that a
    230      * color's population being close to the most populous has on selection.</p>
    231      */
    232     public float getPopulationWeight() {
    233         return mWeights[INDEX_WEIGHT_POP];
    234     }
    235 
    236     /**
    237      * Returns whether any color selected for this target is exclusive for this target only.
    238      *
    239      * <p>If false, then the color can be selected for other targets.</p>
    240      */
    241     public boolean isExclusive() {
    242         return mIsExclusive;
    243     }
    244 
    245     private static void setTargetDefaultValues(final float[] values) {
    246         values[INDEX_MIN] = 0f;
    247         values[INDEX_TARGET] = 0.5f;
    248         values[INDEX_MAX] = 1f;
    249     }
    250 
    251     private void setDefaultWeights() {
    252         mWeights[INDEX_WEIGHT_SAT] = WEIGHT_SATURATION;
    253         mWeights[INDEX_WEIGHT_LUMA] = WEIGHT_LUMA;
    254         mWeights[INDEX_WEIGHT_POP] = WEIGHT_POPULATION;
    255     }
    256 
    257     void normalizeWeights() {
    258         float sum = 0;
    259         for (int i = 0, z = mWeights.length; i < z; i++) {
    260             float weight = mWeights[i];
    261             if (weight > 0) {
    262                 sum += weight;
    263             }
    264         }
    265         if (sum != 0) {
    266             for (int i = 0, z = mWeights.length; i < z; i++) {
    267                 if (mWeights[i] > 0) {
    268                     mWeights[i] /= sum;
    269                 }
    270             }
    271         }
    272     }
    273 
    274     private static void setDefaultDarkLightnessValues(Target target) {
    275         target.mLightnessTargets[INDEX_TARGET] = TARGET_DARK_LUMA;
    276         target.mLightnessTargets[INDEX_MAX] = MAX_DARK_LUMA;
    277     }
    278 
    279     private static void setDefaultNormalLightnessValues(Target target) {
    280         target.mLightnessTargets[INDEX_MIN] = MIN_NORMAL_LUMA;
    281         target.mLightnessTargets[INDEX_TARGET] = TARGET_NORMAL_LUMA;
    282         target.mLightnessTargets[INDEX_MAX] = MAX_NORMAL_LUMA;
    283     }
    284 
    285     private static void setDefaultLightLightnessValues(Target target) {
    286         target.mLightnessTargets[INDEX_MIN] = MIN_LIGHT_LUMA;
    287         target.mLightnessTargets[INDEX_TARGET] = TARGET_LIGHT_LUMA;
    288     }
    289 
    290     private static void setDefaultVibrantSaturationValues(Target target) {
    291         target.mSaturationTargets[INDEX_MIN] = MIN_VIBRANT_SATURATION;
    292         target.mSaturationTargets[INDEX_TARGET] = TARGET_VIBRANT_SATURATION;
    293     }
    294 
    295     private static void setDefaultMutedSaturationValues(Target target) {
    296         target.mSaturationTargets[INDEX_TARGET] = TARGET_MUTED_SATURATION;
    297         target.mSaturationTargets[INDEX_MAX] = MAX_MUTED_SATURATION;
    298     }
    299 
    300     /**
    301      * Builder class for generating custom {@link Target} instances.
    302      */
    303     public final static class Builder {
    304         private final Target mTarget;
    305 
    306         /**
    307          * Create a new {@link Target} builder from scratch.
    308          */
    309         public Builder() {
    310             mTarget = new Target();
    311         }
    312 
    313         /**
    314          * Create a new builder based on an existing {@link Target}.
    315          */
    316         public Builder(Target target) {
    317             mTarget = new Target(target);
    318         }
    319 
    320         /**
    321          * Set the minimum saturation value for this target.
    322          */
    323         public Target.Builder setMinimumSaturation(@FloatRange(from = 0, to = 1) float value) {
    324             mTarget.mSaturationTargets[INDEX_MIN] = value;
    325             return this;
    326         }
    327 
    328         /**
    329          * Set the target/ideal saturation value for this target.
    330          */
    331         public Target.Builder setTargetSaturation(@FloatRange(from = 0, to = 1) float value) {
    332             mTarget.mSaturationTargets[INDEX_TARGET] = value;
    333             return this;
    334         }
    335 
    336         /**
    337          * Set the maximum saturation value for this target.
    338          */
    339         public Target.Builder setMaximumSaturation(@FloatRange(from = 0, to = 1) float value) {
    340             mTarget.mSaturationTargets[INDEX_MAX] = value;
    341             return this;
    342         }
    343 
    344         /**
    345          * Set the minimum lightness value for this target.
    346          */
    347         public Target.Builder setMinimumLightness(@FloatRange(from = 0, to = 1) float value) {
    348             mTarget.mLightnessTargets[INDEX_MIN] = value;
    349             return this;
    350         }
    351 
    352         /**
    353          * Set the target/ideal lightness value for this target.
    354          */
    355         public Target.Builder setTargetLightness(@FloatRange(from = 0, to = 1) float value) {
    356             mTarget.mLightnessTargets[INDEX_TARGET] = value;
    357             return this;
    358         }
    359 
    360         /**
    361          * Set the maximum lightness value for this target.
    362          */
    363         public Target.Builder setMaximumLightness(@FloatRange(from = 0, to = 1) float value) {
    364             mTarget.mLightnessTargets[INDEX_MAX] = value;
    365             return this;
    366         }
    367 
    368         /**
    369          * Set the weight of importance that this target will place on saturation values.
    370          *
    371          * <p>The larger the weight, relative to the other weights, the more important that a color
    372          * being close to the target value has on selection.</p>
    373          *
    374          * <p>A weight of 0 means that it has no weight, and thus has no
    375          * bearing on the selection.</p>
    376          *
    377          * @see #setTargetSaturation(float)
    378          */
    379         public Target.Builder setSaturationWeight(@FloatRange(from = 0) float weight) {
    380             mTarget.mWeights[INDEX_WEIGHT_SAT] = weight;
    381             return this;
    382         }
    383 
    384         /**
    385          * Set the weight of importance that this target will place on lightness values.
    386          *
    387          * <p>The larger the weight, relative to the other weights, the more important that a color
    388          * being close to the target value has on selection.</p>
    389          *
    390          * <p>A weight of 0 means that it has no weight, and thus has no
    391          * bearing on the selection.</p>
    392          *
    393          * @see #setTargetLightness(float)
    394          */
    395         public Target.Builder setLightnessWeight(@FloatRange(from = 0) float weight) {
    396             mTarget.mWeights[INDEX_WEIGHT_LUMA] = weight;
    397             return this;
    398         }
    399 
    400         /**
    401          * Set the weight of importance that this target will place on a color's population within
    402          * the image.
    403          *
    404          * <p>The larger the weight, relative to the other weights, the more important that a
    405          * color's population being close to the most populous has on selection.</p>
    406          *
    407          * <p>A weight of 0 means that it has no weight, and thus has no
    408          * bearing on the selection.</p>
    409          */
    410         public Target.Builder setPopulationWeight(@FloatRange(from = 0) float weight) {
    411             mTarget.mWeights[INDEX_WEIGHT_POP] = weight;
    412             return this;
    413         }
    414 
    415         /**
    416          * Set whether any color selected for this target is exclusive to this target only.
    417          * Defaults to true.
    418          *
    419          * @param exclusive true if any the color is exclusive to this target, or false is the
    420          *                  color can be selected for other targets.
    421          */
    422         public Target.Builder setExclusive(boolean exclusive) {
    423             mTarget.mIsExclusive = exclusive;
    424             return this;
    425         }
    426 
    427         /**
    428          * Builds and returns the resulting {@link Target}.
    429          */
    430         public Target build() {
    431             return mTarget;
    432         }
    433     }
    434 
    435 }