BrightnessUtils.java revision 106b1c0d804bcf4b875f987d8f3855f1ff67734a
1106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang/* 2106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * Copyright (C) 2018 The Android Open Source Project 3106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * 4106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * Licensed under the Apache License, Version 2.0 (the "License"); 5106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * you may not use this file except in compliance with the License. 6106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * You may obtain a copy of the License at 7106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * 8106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * http://www.apache.org/licenses/LICENSE-2.0 9106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * 10106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * Unless required by applicable law or agreed to in writing, software 11106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * distributed under the License is distributed on an "AS IS" BASIS, 12106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * See the License for the specific language governing permissions and 14106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * limitations under the License. 15106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang */ 16106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang 17106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhangpackage com.android.settingslib.display; 18106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang 19106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhangimport android.util.MathUtils; 20106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang 21106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhangpublic class BrightnessUtils { 22106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang 23106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang public static final int GAMMA_SPACE_MAX = 1023; 24106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang 25106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang // Hybrid Log Gamma constant values 26106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang private static final float R = 0.5f; 27106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang private static final float A = 0.17883277f; 28106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang private static final float B = 0.28466892f; 29106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang private static final float C = 0.55991073f; 30106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang 31106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang /** 32106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * A function for converting from the gamma space that the slider works in to the 33106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * linear space that the setting works in. 34106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * 35106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * The gamma space effectively provides us a way to make linear changes to the slider that 36106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * result in linear changes in perception. If we made changes to the slider in the linear space 37106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * then we'd see an approximately logarithmic change in perception (c.f. Fechner's Law). 38106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * 39106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * Internally, this implements the Hybrid Log Gamma electro-optical transfer function, which is 40106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * a slight improvement to the typical gamma transfer function for displays whose max 41106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * brightness exceeds the 120 nit reference point, but doesn't set a specific reference 42106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * brightness like the PQ function does. 43106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * 44106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * Note that this transfer function is only valid if the display's backlight value is a linear 45106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * control. If it's calibrated to be something non-linear, then a different transfer function 46106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * should be used. 47106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * 48106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * @param val The slider value. 49106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * @param min The minimum acceptable value for the setting. 50106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * @param max The maximum acceptable value for the setting. 51106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * @return The corresponding setting value. 52106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang */ 53106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang public static final int convertGammaToLinear(int val, int min, int max) { 54106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang final float normalizedVal = MathUtils.norm(0, GAMMA_SPACE_MAX, val); 55106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang final float ret; 56106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang if (normalizedVal <= R) { 57106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang ret = MathUtils.sq(normalizedVal / R); 58106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang } else { 59106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang ret = MathUtils.exp((normalizedVal - C) / A) + B; 60106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang } 61106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang 62106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang // HLG is normalized to the range [0, 12], so we need to re-normalize to the range [0, 1] 63106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang // in order to derive the correct setting value. 64106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang return Math.round(MathUtils.lerp(min, max, ret / 12)); 65106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang } 66106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang 67106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang /** 68106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * A function for converting from the linear space that the setting works in to the 69106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * gamma space that the slider works in. 70106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * 71106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * The gamma space effectively provides us a way to make linear changes to the slider that 72106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * result in linear changes in perception. If we made changes to the slider in the linear space 73106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * then we'd see an approximately logarithmic change in perception (c.f. Fechner's Law). 74106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * 75106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * Internally, this implements the Hybrid Log Gamma opto-electronic transfer function, which is 76106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * a slight improvement to the typical gamma transfer function for displays whose max 77106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * brightness exceeds the 120 nit reference point, but doesn't set a specific reference 78106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * brightness like the PQ function does. 79106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * 80106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * Note that this transfer function is only valid if the display's backlight value is a linear 81106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * control. If it's calibrated to be something non-linear, then a different transfer function 82106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * should be used. 83106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * 84106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * @param val The brightness setting value. 85106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * @param min The minimum acceptable value for the setting. 86106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * @param max The maximum acceptable value for the setting. 87106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang * @return The corresponding slider value 88106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang */ 89106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang public static final int convertLinearToGamma(int val, int min, int max) { 90106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang // For some reason, HLG normalizes to the range [0, 12] rather than [0, 1] 91106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang final float normalizedVal = MathUtils.norm(min, max, val) * 12; 92106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang final float ret; 93106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang if (normalizedVal <= 1f) { 94106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang ret = MathUtils.sqrt(normalizedVal) * R; 95106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang } else { 96106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang ret = A * MathUtils.log(normalizedVal - B) + C; 97106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang } 98106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang 99106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang return Math.round(MathUtils.lerp(0, GAMMA_SPACE_MAX, ret)); 100106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang } 101106b1c0d804bcf4b875f987d8f3855f1ff67734aFan Zhang} 102