1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
/*
* 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
|