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