xref: /aosp_15_r20/external/skia/include/private/SkGainmapInfo.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2023 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #ifndef SkGainmapInfo_DEFINED
9*c8dee2aaSAndroid Build Coastguard Worker #define SkGainmapInfo_DEFINED
10*c8dee2aaSAndroid Build Coastguard Worker 
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorSpace.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
14*c8dee2aaSAndroid Build Coastguard Worker class SkData;
15*c8dee2aaSAndroid Build Coastguard Worker 
16*c8dee2aaSAndroid Build Coastguard Worker /**
17*c8dee2aaSAndroid Build Coastguard Worker  *  Gainmap rendering parameters. Suppose our display has HDR to SDR ratio of H and we wish to
18*c8dee2aaSAndroid Build Coastguard Worker  *  display an image with gainmap on this display. Let B be the pixel value from the base image
19*c8dee2aaSAndroid Build Coastguard Worker  *  in a color space that has the primaries of the base image and a linear transfer function. Let
20*c8dee2aaSAndroid Build Coastguard Worker  *  G be the pixel value from the gainmap. Let D be the output pixel in the same color space as B.
21*c8dee2aaSAndroid Build Coastguard Worker  *  The value of D is computed as follows:
22*c8dee2aaSAndroid Build Coastguard Worker  *
23*c8dee2aaSAndroid Build Coastguard Worker  *  First, let W be a weight parameter determing how much the gainmap will be applied.
24*c8dee2aaSAndroid Build Coastguard Worker  *    W = clamp((log(H)                - log(fDisplayRatioSdr)) /
25*c8dee2aaSAndroid Build Coastguard Worker  *              (log(fDisplayRatioHdr) - log(fDisplayRatioSdr), 0, 1)
26*c8dee2aaSAndroid Build Coastguard Worker  *
27*c8dee2aaSAndroid Build Coastguard Worker  *  Next, let L be the gainmap value in log space. We compute this from the value G that was
28*c8dee2aaSAndroid Build Coastguard Worker  *  sampled from the texture as follows:
29*c8dee2aaSAndroid Build Coastguard Worker  *    L = mix(log(fGainmapRatioMin), log(fGainmapRatioMax), pow(G, fGainmapGamma))
30*c8dee2aaSAndroid Build Coastguard Worker  *
31*c8dee2aaSAndroid Build Coastguard Worker  *  Finally, apply the gainmap to compute D, the displayed pixel. If the base image is SDR then
32*c8dee2aaSAndroid Build Coastguard Worker  *  compute:
33*c8dee2aaSAndroid Build Coastguard Worker  *    D = (B + fEpsilonSdr) * exp(L * W) - fEpsilonHdr
34*c8dee2aaSAndroid Build Coastguard Worker  *  If the base image is HDR then compute:
35*c8dee2aaSAndroid Build Coastguard Worker  *    D = (B + fEpsilonHdr) * exp(L * (W - 1)) - fEpsilonSdr
36*c8dee2aaSAndroid Build Coastguard Worker  *
37*c8dee2aaSAndroid Build Coastguard Worker  *  In the above math, log() is a natural logarithm and exp() is natural exponentiation. Note,
38*c8dee2aaSAndroid Build Coastguard Worker  *  however, that the base used for the log() and exp() functions does not affect the results of
39*c8dee2aaSAndroid Build Coastguard Worker  *  the computation (it cancels out, as long as the same base is used throughout).
40*c8dee2aaSAndroid Build Coastguard Worker  *
41*c8dee2aaSAndroid Build Coastguard Worker  *  This product includes Gain Map technology under license by Adobe.
42*c8dee2aaSAndroid Build Coastguard Worker  */
43*c8dee2aaSAndroid Build Coastguard Worker struct SkGainmapInfo {
44*c8dee2aaSAndroid Build Coastguard Worker     /**
45*c8dee2aaSAndroid Build Coastguard Worker      *  Parameters for converting the gainmap from its image encoding to log space. These are
46*c8dee2aaSAndroid Build Coastguard Worker      *  specified per color channel. The alpha value is unused.
47*c8dee2aaSAndroid Build Coastguard Worker      */
48*c8dee2aaSAndroid Build Coastguard Worker     SkColor4f fGainmapRatioMin = {1.f, 1.f, 1.f, 1.0};
49*c8dee2aaSAndroid Build Coastguard Worker     SkColor4f fGainmapRatioMax = {2.f, 2.f, 2.f, 1.0};
50*c8dee2aaSAndroid Build Coastguard Worker     SkColor4f fGainmapGamma = {1.f, 1.f, 1.f, 1.f};
51*c8dee2aaSAndroid Build Coastguard Worker 
52*c8dee2aaSAndroid Build Coastguard Worker     /**
53*c8dee2aaSAndroid Build Coastguard Worker      *  Parameters sometimes used in gainmap computation to avoid numerical instability.
54*c8dee2aaSAndroid Build Coastguard Worker      */
55*c8dee2aaSAndroid Build Coastguard Worker     SkColor4f fEpsilonSdr = {0.f, 0.f, 0.f, 1.0};
56*c8dee2aaSAndroid Build Coastguard Worker     SkColor4f fEpsilonHdr = {0.f, 0.f, 0.f, 1.0};
57*c8dee2aaSAndroid Build Coastguard Worker 
58*c8dee2aaSAndroid Build Coastguard Worker     /**
59*c8dee2aaSAndroid Build Coastguard Worker      *  If the output display's HDR to SDR ratio is less or equal than fDisplayRatioSdr then the SDR
60*c8dee2aaSAndroid Build Coastguard Worker      *  rendition is displayed. If the output display's HDR to SDR ratio is greater or equal than
61*c8dee2aaSAndroid Build Coastguard Worker      *  fDisplayRatioHdr then the HDR rendition is displayed. If the output display's HDR to SDR
62*c8dee2aaSAndroid Build Coastguard Worker      *  ratio is between these values then an interpolation between the two is displayed using the
63*c8dee2aaSAndroid Build Coastguard Worker      *  math above.
64*c8dee2aaSAndroid Build Coastguard Worker      */
65*c8dee2aaSAndroid Build Coastguard Worker     float fDisplayRatioSdr = 1.f;
66*c8dee2aaSAndroid Build Coastguard Worker     float fDisplayRatioHdr = 2.f;
67*c8dee2aaSAndroid Build Coastguard Worker 
68*c8dee2aaSAndroid Build Coastguard Worker     /**
69*c8dee2aaSAndroid Build Coastguard Worker      *  Whether the base image is the SDR image or the HDR image.
70*c8dee2aaSAndroid Build Coastguard Worker      */
71*c8dee2aaSAndroid Build Coastguard Worker     enum class BaseImageType {
72*c8dee2aaSAndroid Build Coastguard Worker         kSDR,
73*c8dee2aaSAndroid Build Coastguard Worker         kHDR,
74*c8dee2aaSAndroid Build Coastguard Worker     };
75*c8dee2aaSAndroid Build Coastguard Worker     BaseImageType fBaseImageType = BaseImageType::kSDR;
76*c8dee2aaSAndroid Build Coastguard Worker 
77*c8dee2aaSAndroid Build Coastguard Worker     /**
78*c8dee2aaSAndroid Build Coastguard Worker      *  The type of the gainmap image. If the type is kApple, then the gainmap image was originally
79*c8dee2aaSAndroid Build Coastguard Worker      *  encoded according to the specification at [0], and can be converted to the kDefault type by
80*c8dee2aaSAndroid Build Coastguard Worker      *  applying the transformation described at [1].
81*c8dee2aaSAndroid Build Coastguard Worker      *  [0] https://developer.apple.com/documentation/appkit/images_and_pdf/
82*c8dee2aaSAndroid Build Coastguard Worker      *      applying_apple_hdr_effect_to_your_photos
83*c8dee2aaSAndroid Build Coastguard Worker      *  [1] https://docs.google.com/document/d/1iUpYAThVV_FuDdeiO3t0vnlfoA1ryq0WfGS9FuydwKc
84*c8dee2aaSAndroid Build Coastguard Worker      */
85*c8dee2aaSAndroid Build Coastguard Worker     enum class Type {
86*c8dee2aaSAndroid Build Coastguard Worker         kDefault,
87*c8dee2aaSAndroid Build Coastguard Worker         kApple,
88*c8dee2aaSAndroid Build Coastguard Worker     };
89*c8dee2aaSAndroid Build Coastguard Worker     Type fType = Type::kDefault;
90*c8dee2aaSAndroid Build Coastguard Worker 
91*c8dee2aaSAndroid Build Coastguard Worker     /**
92*c8dee2aaSAndroid Build Coastguard Worker      * If specified, color space to apply the gainmap in, otherwise the base image's color space
93*c8dee2aaSAndroid Build Coastguard Worker      * is used. Only the color primaries are used, the transfer function is irrelevant.
94*c8dee2aaSAndroid Build Coastguard Worker      */
95*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkColorSpace> fGainmapMathColorSpace = nullptr;
96*c8dee2aaSAndroid Build Coastguard Worker 
97*c8dee2aaSAndroid Build Coastguard Worker     /**
98*c8dee2aaSAndroid Build Coastguard Worker      * Return true if this can be encoded as an UltraHDR v1 image.
99*c8dee2aaSAndroid Build Coastguard Worker      */
100*c8dee2aaSAndroid Build Coastguard Worker     bool isUltraHDRv1Compatible() const;
101*c8dee2aaSAndroid Build Coastguard Worker 
102*c8dee2aaSAndroid Build Coastguard Worker     /**
103*c8dee2aaSAndroid Build Coastguard Worker      * If |data| contains an ISO 21496-1 version that is supported, return true. Otherwise return
104*c8dee2aaSAndroid Build Coastguard Worker      * false.
105*c8dee2aaSAndroid Build Coastguard Worker      */
106*c8dee2aaSAndroid Build Coastguard Worker     static bool ParseVersion(const SkData* data);
107*c8dee2aaSAndroid Build Coastguard Worker 
108*c8dee2aaSAndroid Build Coastguard Worker     /**
109*c8dee2aaSAndroid Build Coastguard Worker      * If |data| constains ISO 21496-1 metadata then parse that metadata then use it to populate
110*c8dee2aaSAndroid Build Coastguard Worker      * |info| and return true, otherwise return false. If |data| indicates that that the base image
111*c8dee2aaSAndroid Build Coastguard Worker      * color space primaries should be used for gainmap application then set
112*c8dee2aaSAndroid Build Coastguard Worker      * |fGainmapMathColorSpace| to nullptr, otherwise set |fGainmapMathColorSpace| to sRGB (the
113*c8dee2aaSAndroid Build Coastguard Worker      * default, to be overwritten by the image decoder).
114*c8dee2aaSAndroid Build Coastguard Worker      */
115*c8dee2aaSAndroid Build Coastguard Worker     static bool Parse(const SkData* data, SkGainmapInfo& info);
116*c8dee2aaSAndroid Build Coastguard Worker 
117*c8dee2aaSAndroid Build Coastguard Worker     /**
118*c8dee2aaSAndroid Build Coastguard Worker      * Serialize an ISO 21496-1 version 0 blob containing only the version structure.
119*c8dee2aaSAndroid Build Coastguard Worker      */
120*c8dee2aaSAndroid Build Coastguard Worker     static sk_sp<SkData> SerializeVersion();
121*c8dee2aaSAndroid Build Coastguard Worker 
122*c8dee2aaSAndroid Build Coastguard Worker     /**
123*c8dee2aaSAndroid Build Coastguard Worker      * Serialize an ISO 21496-1 version 0 blob containing this' gainmap parameters.
124*c8dee2aaSAndroid Build Coastguard Worker      */
125*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkData> serialize() const;
126*c8dee2aaSAndroid Build Coastguard Worker 
127*c8dee2aaSAndroid Build Coastguard Worker     inline bool operator==(const SkGainmapInfo& other) const {
128*c8dee2aaSAndroid Build Coastguard Worker         return fGainmapRatioMin == other.fGainmapRatioMin &&
129*c8dee2aaSAndroid Build Coastguard Worker                fGainmapRatioMax == other.fGainmapRatioMax && fGainmapGamma == other.fGainmapGamma &&
130*c8dee2aaSAndroid Build Coastguard Worker                fEpsilonSdr == other.fEpsilonSdr && fEpsilonHdr == other.fEpsilonHdr &&
131*c8dee2aaSAndroid Build Coastguard Worker                fDisplayRatioSdr == other.fDisplayRatioSdr &&
132*c8dee2aaSAndroid Build Coastguard Worker                fDisplayRatioHdr == other.fDisplayRatioHdr &&
133*c8dee2aaSAndroid Build Coastguard Worker                fBaseImageType == other.fBaseImageType && fType == other.fType &&
134*c8dee2aaSAndroid Build Coastguard Worker                SkColorSpace::Equals(fGainmapMathColorSpace.get(),
135*c8dee2aaSAndroid Build Coastguard Worker                                     other.fGainmapMathColorSpace.get());
136*c8dee2aaSAndroid Build Coastguard Worker     }
137*c8dee2aaSAndroid Build Coastguard Worker     inline bool operator!=(const SkGainmapInfo& other) const { return !(*this == other); }
138*c8dee2aaSAndroid Build Coastguard Worker };
139*c8dee2aaSAndroid Build Coastguard Worker 
140*c8dee2aaSAndroid Build Coastguard Worker #endif
141