/src/skia/include/private/SkGainmapInfo.h
Line | Count | Source (jump to first uncovered line) |
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 | | * If |data| contains an ISO 21496-1 version that is supported, return true. Otherwise return |
99 | | * false. |
100 | | */ |
101 | | static bool ParseVersion(const SkData* data); |
102 | | |
103 | | /** |
104 | | * If |data| constains ISO 21496-1 metadata then parse that metadata then use it to populate |
105 | | * |info| and return true, otherwise return false. If |data| indicates that that the base image |
106 | | * color space primaries should be used for gainmap application then set |
107 | | * |fGainmapMathColorSpace| to nullptr, otherwise set |fGainmapMathColorSpace| to sRGB (the |
108 | | * default, to be overwritten by the image decoder). |
109 | | */ |
110 | | static bool Parse(const SkData* data, SkGainmapInfo& info); |
111 | | |
112 | | /** |
113 | | * Serialize an ISO 21496-1 version 0 blob containing only the version structure. |
114 | | */ |
115 | | static sk_sp<SkData> SerializeVersion(); |
116 | | |
117 | | /** |
118 | | * Serialize an ISO 21496-1 version 0 blob containing this' gainmap parameters. |
119 | | */ |
120 | | sk_sp<SkData> serialize() const; |
121 | | |
122 | 0 | inline bool operator==(const SkGainmapInfo& other) const { |
123 | 0 | return fGainmapRatioMin == other.fGainmapRatioMin && |
124 | 0 | fGainmapRatioMax == other.fGainmapRatioMax && fGainmapGamma == other.fGainmapGamma && |
125 | 0 | fEpsilonSdr == other.fEpsilonSdr && fEpsilonHdr == other.fEpsilonHdr && |
126 | 0 | fDisplayRatioSdr == other.fDisplayRatioSdr && |
127 | 0 | fDisplayRatioHdr == other.fDisplayRatioHdr && |
128 | 0 | fBaseImageType == other.fBaseImageType && fType == other.fType && |
129 | 0 | SkColorSpace::Equals(fGainmapMathColorSpace.get(), |
130 | 0 | other.fGainmapMathColorSpace.get()); |
131 | 0 | } |
132 | 0 | inline bool operator!=(const SkGainmapInfo& other) const { return !(*this == other); } |
133 | | }; |
134 | | |
135 | | #endif |