| /* |
| * Copyright 2023 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #ifndef SkGainmapInfo_DEFINED |
| #define SkGainmapInfo_DEFINED |
| |
| #include "include/core/SkColor.h" |
| #include "include/core/SkColorSpace.h" |
| #include "include/core/SkRefCnt.h" |
| class SkData; |
| |
| /** |
| * Gainmap rendering parameters. Suppose our display has HDR to SDR ratio of H and we wish to |
| * display an image with gainmap on this display. Let B be the pixel value from the base image |
| * in a color space that has the primaries of the base image and a linear transfer function. Let |
| * G be the pixel value from the gainmap. Let D be the output pixel in the same color space as B. |
| * The value of D is computed as follows: |
| * |
| * First, let W be a weight parameter determing how much the gainmap will be applied. |
| * W = clamp((log(H) - log(fDisplayRatioSdr)) / |
| * (log(fDisplayRatioHdr) - log(fDisplayRatioSdr), 0, 1) |
| * |
| * Next, let L be the gainmap value in log space. We compute this from the value G that was |
| * sampled from the texture as follows: |
| * L = mix(log(fGainmapRatioMin), log(fGainmapRatioMax), pow(G, fGainmapGamma)) |
| * |
| * Finally, apply the gainmap to compute D, the displayed pixel. If the base image is SDR then |
| * compute: |
| * D = (B + fEpsilonSdr) * exp(L * W) - fEpsilonHdr |
| * If the base image is HDR then compute: |
| * D = (B + fEpsilonHdr) * exp(L * (W - 1)) - fEpsilonSdr |
| * |
| * In the above math, log() is a natural logarithm and exp() is natural exponentiation. Note, |
| * however, that the base used for the log() and exp() functions does not affect the results of |
| * the computation (it cancels out, as long as the same base is used throughout). |
| * |
| * This product includes Gain Map technology under license by Adobe. |
| */ |
| struct SkGainmapInfo { |
| /** |
| * Parameters for converting the gainmap from its image encoding to log space. These are |
| * specified per color channel. The alpha value is unused. |
| */ |
| SkColor4f fGainmapRatioMin = {1.f, 1.f, 1.f, 1.0}; |
| SkColor4f fGainmapRatioMax = {2.f, 2.f, 2.f, 1.0}; |
| SkColor4f fGainmapGamma = {1.f, 1.f, 1.f, 1.f}; |
| |
| /** |
| * Parameters sometimes used in gainmap computation to avoid numerical instability. |
| */ |
| SkColor4f fEpsilonSdr = {0.f, 0.f, 0.f, 1.0}; |
| SkColor4f fEpsilonHdr = {0.f, 0.f, 0.f, 1.0}; |
| |
| /** |
| * If the output display's HDR to SDR ratio is less or equal than fDisplayRatioSdr then the SDR |
| * rendition is displayed. If the output display's HDR to SDR ratio is greater or equal than |
| * fDisplayRatioHdr then the HDR rendition is displayed. If the output display's HDR to SDR |
| * ratio is between these values then an interpolation between the two is displayed using the |
| * math above. |
| */ |
| float fDisplayRatioSdr = 1.f; |
| float fDisplayRatioHdr = 2.f; |
| |
| /** |
| * Whether the base image is the SDR image or the HDR image. |
| */ |
| enum class BaseImageType { |
| kSDR, |
| kHDR, |
| }; |
| BaseImageType fBaseImageType = BaseImageType::kSDR; |
| |
| /** |
| * The type of the gainmap image. If the type is kApple, then the gainmap image was originally |
| * encoded according to the specification at [0], and can be converted to the kDefault type by |
| * applying the transformation described at [1]. |
| * [0] https://developer.apple.com/documentation/appkit/images_and_pdf/ |
| * applying_apple_hdr_effect_to_your_photos |
| * [1] https://docs.google.com/document/d/1iUpYAThVV_FuDdeiO3t0vnlfoA1ryq0WfGS9FuydwKc |
| */ |
| enum class Type { |
| kDefault, |
| kApple, |
| }; |
| Type fType = Type::kDefault; |
| |
| /** |
| * If specified, color space to apply the gainmap in, otherwise the base image's color space |
| * is used. Only the color primaries are used, the transfer function is irrelevant. |
| */ |
| sk_sp<SkColorSpace> fGainmapMathColorSpace = nullptr; |
| |
| /** |
| * Return true if this can be encoded as an UltraHDR v1 image. |
| */ |
| bool isUltraHDRv1Compatible() const; |
| |
| /** |
| * If |data| contains an ISO 21496-1 version that is supported, return true. Otherwise return |
| * false. |
| */ |
| static bool ParseVersion(const SkData* data); |
| |
| /** |
| * If |data| constains ISO 21496-1 metadata then parse that metadata then use it to populate |
| * |info| and return true, otherwise return false. If |data| indicates that that the base image |
| * color space primaries should be used for gainmap application then set |
| * |fGainmapMathColorSpace| to nullptr, otherwise set |fGainmapMathColorSpace| to sRGB (the |
| * default, to be overwritten by the image decoder). |
| */ |
| static bool Parse(const SkData* data, SkGainmapInfo& info); |
| |
| /** |
| * Serialize an ISO 21496-1 version 0 blob containing only the version structure. |
| */ |
| static sk_sp<SkData> SerializeVersion(); |
| |
| /** |
| * Serialize an ISO 21496-1 version 0 blob containing this' gainmap parameters. |
| */ |
| sk_sp<SkData> serialize() const; |
| |
| inline bool operator==(const SkGainmapInfo& other) const { |
| return fGainmapRatioMin == other.fGainmapRatioMin && |
| fGainmapRatioMax == other.fGainmapRatioMax && fGainmapGamma == other.fGainmapGamma && |
| fEpsilonSdr == other.fEpsilonSdr && fEpsilonHdr == other.fEpsilonHdr && |
| fDisplayRatioSdr == other.fDisplayRatioSdr && |
| fDisplayRatioHdr == other.fDisplayRatioHdr && |
| fBaseImageType == other.fBaseImageType && fType == other.fType && |
| SkColorSpace::Equals(fGainmapMathColorSpace.get(), |
| other.fGainmapMathColorSpace.get()); |
| } |
| inline bool operator!=(const SkGainmapInfo& other) const { return !(*this == other); } |
| }; |
| |
| #endif |