| 1 | // LAF Gfx Library |
| 2 | // Copyright (c) 2018-2022 Igara Studio S.A. |
| 3 | // |
| 4 | // This file is released under the terms of the MIT license. |
| 5 | // Read LICENSE.txt for more information. |
| 6 | |
| 7 | #ifndef GFX_COLOR_SPACE_H_INCLUDED |
| 8 | #define GFX_COLOR_SPACE_H_INCLUDED |
| 9 | #pragma once |
| 10 | |
| 11 | #include "base/ref.h" |
| 12 | |
| 13 | #include <algorithm> |
| 14 | #include <cstdint> |
| 15 | #include <string> |
| 16 | #include <vector> |
| 17 | |
| 18 | #pragma push_macro("None") |
| 19 | #undef None // Undefine the X11 None macro |
| 20 | |
| 21 | namespace gfx { |
| 22 | |
| 23 | class ColorSpace; |
| 24 | using ColorSpaceRef = base::Ref<ColorSpace>; |
| 25 | |
| 26 | // Gamut white point and primaries as in Skia's SkColorSpacePrimaries. |
| 27 | struct ColorSpacePrimaries { |
| 28 | float rx, ry, gx, gy, bx, by; // Red/Green/Blue XY |
| 29 | float wx, wy; // White point XY |
| 30 | }; |
| 31 | |
| 32 | // Transfer coefficients as in Skia's skcms_TransferFunction, to |
| 33 | // transform from a curved space to linear: |
| 34 | // |
| 35 | // LinearVal = C*InputVal + F , for 0.0f <= InputVal < D |
| 36 | // LinearVal = (A*InputVal + B)^G + E, for D <= InputVal <= 1.0f |
| 37 | // |
| 38 | struct ColorSpaceTransferFn { |
| 39 | float g, a, b, c, d, e, f; |
| 40 | }; |
| 41 | |
| 42 | class ColorSpace : public base::RefCountT<ColorSpace> { |
| 43 | public: |
| 44 | enum Type { None, |
| 45 | sRGB, |
| 46 | RGB, |
| 47 | ICC }; |
| 48 | |
| 49 | enum Flag { NoFlags = 0, |
| 50 | HasGamma = 1, |
| 51 | HasTransferFn = 2, |
| 52 | HasPrimaries = 4, |
| 53 | HasICC = 8 }; |
| 54 | |
| 55 | ColorSpace(const Type type, |
| 56 | const Flag flags = NoFlags, |
| 57 | const float gamma = 1.0, |
| 58 | std::vector<uint8_t>&& rawData = std::vector<uint8_t>()); |
| 59 | |
| 60 | static ColorSpaceRef MakeNone(); // Use display color space |
| 61 | static ColorSpaceRef MakeSRGB(); |
| 62 | static ColorSpaceRef MakeLinearSRGB(); |
| 63 | static ColorSpaceRef MakeSRGBWithGamma(float gamma); |
| 64 | static ColorSpaceRef MakeRGB(const ColorSpaceTransferFn& fn, |
| 65 | const ColorSpacePrimaries& p); |
| 66 | static ColorSpaceRef MakeRGBWithSRGBGamut(const ColorSpaceTransferFn& fn); |
| 67 | static ColorSpaceRef MakeRGBWithSRGBGamma(const ColorSpacePrimaries& p); |
| 68 | static ColorSpaceRef MakeICC(const void* data, size_t n); |
| 69 | static ColorSpaceRef MakeICC(std::vector<uint8_t>&& data); |
| 70 | |
| 71 | Type type() const { return m_type; } |
| 72 | Flag flags() const { return m_flags; } |
| 73 | |
| 74 | const std::string& name() const { return m_name; } |
| 75 | void setName(const std::string& name) { m_name = name; } |
| 76 | |
| 77 | float gamma() const { return m_gamma; } |
| 78 | |
| 79 | bool hasGamma() const { return has(HasGamma); } |
| 80 | bool hasTransferFn() const { return has(HasTransferFn); } |
| 81 | bool hasPrimaries() const { return has(HasPrimaries); } |
| 82 | |
| 83 | size_t iccSize() const { |
| 84 | if (has(HasICC)) |
| 85 | return m_data.size(); |
| 86 | else |
| 87 | return 0; |
| 88 | } |
| 89 | |
| 90 | const void* iccData() const { |
| 91 | if (has(HasICC)) |
| 92 | return &m_data[0]; |
| 93 | else |
| 94 | return nullptr; |
| 95 | } |
| 96 | |
| 97 | const ColorSpaceTransferFn* transferFn() const { |
| 98 | if (has(HasTransferFn)) |
| 99 | return (const ColorSpaceTransferFn*)&m_data[0]; |
| 100 | else |
| 101 | return nullptr; |
| 102 | } |
| 103 | |
| 104 | const ColorSpacePrimaries* primaries() const { |
| 105 | if (has(HasPrimaries)) { |
| 106 | if (has(HasTransferFn)) |
| 107 | return (const ColorSpacePrimaries*)&m_data[sizeof(ColorSpaceTransferFn)]; |
| 108 | else |
| 109 | return (const ColorSpacePrimaries*)&m_data[0]; |
| 110 | } |
| 111 | else |
| 112 | return nullptr; |
| 113 | } |
| 114 | |
| 115 | bool operator==(const ColorSpace& that) const = delete; |
| 116 | bool operator!=(const ColorSpace& that) const = delete; |
| 117 | bool nearlyEqual(const ColorSpace& that) const; |
| 118 | |
| 119 | // This data can be used |
| 120 | const std::vector<uint8_t>& rawData() const { return m_data; } |
| 121 | |
| 122 | private: |
| 123 | bool has(const Flag flag) const { return (m_flags & int(flag)) == int(flag); } |
| 124 | |
| 125 | Type m_type; |
| 126 | Flag m_flags; |
| 127 | std::string m_name; |
| 128 | float m_gamma = 1.0f; |
| 129 | // ColorSpacePrimaries + ColorSpaceTransferFn or raw ICC profile data |
| 130 | std::vector<uint8_t> m_data; |
| 131 | }; |
| 132 | |
| 133 | } // namespace gfx |
| 134 | |
| 135 | #pragma pop_macro("None") |
| 136 | |
| 137 | #endif |
| 138 | |