Home | History | Annotate | Download | only in ui
      1 /*
      2  * Copyright (C) 2016 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 #ifndef ANDROID_UI_COLOR_SPACE
     18 #define ANDROID_UI_COLOR_SPACE
     19 
     20 #include <array>
     21 #include <cmath>
     22 #include <functional>
     23 #include <memory>
     24 #include <string>
     25 
     26 #include <math/mat3.h>
     27 #include <math/scalar.h>
     28 #include <math/vec2.h>
     29 #include <math/vec3.h>
     30 
     31 namespace android {
     32 
     33 class ColorSpace {
     34 public:
     35     typedef std::function<float(float)> transfer_function;
     36     typedef std::function<float(float)> clamping_function;
     37 
     38     struct TransferParameters {
     39         float g = 0.0f;
     40         float a = 0.0f;
     41         float b = 0.0f;
     42         float c = 0.0f;
     43         float d = 0.0f;
     44         float e = 0.0f;
     45         float f = 0.0f;
     46     };
     47 
     48     /**
     49      * Creates a named color space with the specified RGB->XYZ
     50      * conversion matrix. The white point and primaries will be
     51      * computed from the supplied matrix.
     52      *
     53      * The default transfer functions are a linear response x->x
     54      * and the default clamping function is a simple saturate
     55      * (clamp(x, 0, 1)).
     56      */
     57     ColorSpace(
     58             const std::string& name,
     59             const mat3& rgbToXYZ,
     60             transfer_function OETF = linearResponse,
     61             transfer_function EOTF = linearResponse,
     62             clamping_function clamper = saturate<float>
     63     ) noexcept;
     64 
     65     /**
     66      * Creates a named color space with the specified RGB->XYZ
     67      * conversion matrix. The white point and primaries will be
     68      * computed from the supplied matrix.
     69      *
     70      * The transfer functions are defined by the set of supplied
     71      * transfer parameters. The default clamping function is a
     72      * simple saturate (clamp(x, 0, 1)).
     73      */
     74     ColorSpace(
     75             const std::string& name,
     76             const mat3& rgbToXYZ,
     77             const TransferParameters parameters,
     78             clamping_function clamper = saturate<float>
     79     ) noexcept;
     80 
     81     /**
     82      * Creates a named color space with the specified RGB->XYZ
     83      * conversion matrix. The white point and primaries will be
     84      * computed from the supplied matrix.
     85      *
     86      * The transfer functions are defined by a simple gamma value.
     87      * The default clamping function is a saturate (clamp(x, 0, 1)).
     88      */
     89     ColorSpace(
     90             const std::string& name,
     91             const mat3& rgbToXYZ,
     92             float gamma,
     93             clamping_function clamper = saturate<float>
     94     ) noexcept;
     95 
     96     /**
     97      * Creates a named color space with the specified primaries
     98      * and white point. The RGB<>XYZ conversion matrices are
     99      * computed from the primaries and white point.
    100      *
    101      * The default transfer functions are a linear response x->x
    102      * and the default clamping function is a simple saturate
    103      * (clamp(x, 0, 1)).
    104      */
    105     ColorSpace(
    106             const std::string& name,
    107             const std::array<float2, 3>& primaries,
    108             const float2& whitePoint,
    109             transfer_function OETF = linearResponse,
    110             transfer_function EOTF = linearResponse,
    111             clamping_function clamper = saturate<float>
    112     ) noexcept;
    113 
    114     /**
    115      * Creates a named color space with the specified primaries
    116      * and white point. The RGB<>XYZ conversion matrices are
    117      * computed from the primaries and white point.
    118      *
    119      * The transfer functions are defined by the set of supplied
    120      * transfer parameters. The default clamping function is a
    121      * simple saturate (clamp(x, 0, 1)).
    122      */
    123     ColorSpace(
    124             const std::string& name,
    125             const std::array<float2, 3>& primaries,
    126             const float2& whitePoint,
    127             const TransferParameters parameters,
    128             clamping_function clamper = saturate<float>
    129     ) noexcept;
    130 
    131     /**
    132      * Creates a named color space with the specified primaries
    133      * and white point. The RGB<>XYZ conversion matrices are
    134      * computed from the primaries and white point.
    135      *
    136      * The transfer functions are defined by a single gamma value.
    137      * The default clamping function is a saturate (clamp(x, 0, 1)).
    138      */
    139     ColorSpace(
    140             const std::string& name,
    141             const std::array<float2, 3>& primaries,
    142             const float2& whitePoint,
    143             float gamma,
    144             clamping_function clamper = saturate<float>
    145     ) noexcept;
    146 
    147     ColorSpace() noexcept = delete;
    148 
    149     /**
    150      * Encodes the supplied RGB value using this color space's
    151      * opto-electronic transfer function.
    152      */
    153     constexpr float3 fromLinear(const float3& v) const noexcept {
    154         return apply(v, mOETF);
    155     }
    156 
    157     /**
    158      * Decodes the supplied RGB value using this color space's
    159      * electro-optical transfer function.
    160      */
    161     constexpr float3 toLinear(const float3& v) const noexcept {
    162         return apply(v, mEOTF);
    163     }
    164 
    165     /**
    166      * Converts the supplied XYZ value to RGB. The returned value
    167      * is encoded with this color space's opto-electronic transfer
    168      * function and clamped by this color space's clamping function.
    169      */
    170     constexpr float3 xyzToRGB(const float3& xyz) const noexcept {
    171         return apply(fromLinear(mXYZtoRGB * xyz), mClamper);
    172     }
    173 
    174     /**
    175      * Converts the supplied RGB value to XYZ. The input RGB value
    176      * is decoded using this color space's electro-optical function
    177      * before being converted to XYZ.
    178      */
    179     constexpr float3 rgbToXYZ(const float3& rgb) const noexcept {
    180         return mRGBtoXYZ * toLinear(rgb);
    181     }
    182 
    183     constexpr const std::string& getName() const noexcept {
    184         return mName;
    185     }
    186 
    187     constexpr const mat3& getRGBtoXYZ() const noexcept {
    188         return mRGBtoXYZ;
    189     }
    190 
    191     constexpr const mat3& getXYZtoRGB() const noexcept {
    192         return mXYZtoRGB;
    193     }
    194 
    195     constexpr const transfer_function& getOETF() const noexcept {
    196         return mOETF;
    197     }
    198 
    199     constexpr const transfer_function& getEOTF() const noexcept {
    200         return mEOTF;
    201     }
    202 
    203     constexpr const clamping_function& getClamper() const noexcept {
    204         return mClamper;
    205     }
    206 
    207     constexpr const std::array<float2, 3>& getPrimaries() const noexcept {
    208         return mPrimaries;
    209     }
    210 
    211     constexpr const float2& getWhitePoint() const noexcept {
    212         return mWhitePoint;
    213     }
    214 
    215     constexpr const TransferParameters& getTransferParameters() const noexcept {
    216         return mParameters;
    217     }
    218 
    219     /**
    220      * Converts the supplied XYZ value to xyY.
    221      */
    222     static constexpr float2 xyY(const float3& XYZ) {
    223         return XYZ.xy / dot(XYZ, float3{1});
    224     }
    225 
    226     /**
    227      * Converts the supplied xyY value to XYZ.
    228      */
    229     static constexpr float3 XYZ(const float3& xyY) {
    230         return float3{(xyY.x * xyY.z) / xyY.y, xyY.z, ((1 - xyY.x - xyY.y) * xyY.z) / xyY.y};
    231     }
    232 
    233     static const ColorSpace sRGB();
    234     static const ColorSpace linearSRGB();
    235     static const ColorSpace extendedSRGB();
    236     static const ColorSpace linearExtendedSRGB();
    237     static const ColorSpace NTSC();
    238     static const ColorSpace BT709();
    239     static const ColorSpace BT2020();
    240     static const ColorSpace AdobeRGB();
    241     static const ColorSpace ProPhotoRGB();
    242     static const ColorSpace DisplayP3();
    243     static const ColorSpace DCIP3();
    244     static const ColorSpace ACES();
    245     static const ColorSpace ACEScg();
    246 
    247     // Creates a NxNxN 3D LUT, where N is the specified size (min=2, max=256)
    248     // The 3D lookup coordinates map to the RGB components: u=R, v=G, w=B
    249     // The generated 3D LUT is meant to be used as a 3D texture and its Y
    250     // axis is thus already flipped
    251     // The source color space must define its values in the domain [0..1]
    252     // The generated LUT transforms from gamma space to gamma space
    253     static std::unique_ptr<float3> createLUT(uint32_t size,
    254             const ColorSpace& src, const ColorSpace& dst);
    255 
    256 private:
    257     static constexpr mat3 computeXYZMatrix(
    258             const std::array<float2, 3>& primaries, const float2& whitePoint);
    259 
    260     static constexpr float linearResponse(float v) {
    261         return v;
    262     }
    263 
    264     std::string mName;
    265 
    266     mat3 mRGBtoXYZ;
    267     mat3 mXYZtoRGB;
    268 
    269     TransferParameters mParameters;
    270     transfer_function mOETF;
    271     transfer_function mEOTF;
    272     clamping_function mClamper;
    273 
    274     std::array<float2, 3> mPrimaries;
    275     float2 mWhitePoint;
    276 };
    277 
    278 class ColorSpaceConnector {
    279 public:
    280     ColorSpaceConnector(const ColorSpace& src, const ColorSpace& dst) noexcept;
    281 
    282     constexpr const ColorSpace& getSource() const noexcept { return mSource; }
    283     constexpr const ColorSpace& getDestination() const noexcept { return mDestination; }
    284 
    285     constexpr const mat3& getTransform() const noexcept { return mTransform; }
    286 
    287     constexpr float3 transform(const float3& v) const noexcept {
    288         float3 linear = mSource.toLinear(apply(v, mSource.getClamper()));
    289         return apply(mDestination.fromLinear(mTransform * linear), mDestination.getClamper());
    290     }
    291 
    292     constexpr float3 transformLinear(const float3& v) const noexcept {
    293         float3 linear = apply(v, mSource.getClamper());
    294         return apply(mTransform * linear, mDestination.getClamper());
    295     }
    296 
    297 private:
    298     ColorSpace mSource;
    299     ColorSpace mDestination;
    300     mat3 mTransform;
    301 };
    302 
    303 }; // namespace android
    304 
    305 #endif // ANDROID_UI_COLOR_SPACE
    306