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