/* * Copyright 2016 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "include/core/SkColorSpace.h" #include "include/core/SkData.h" #include "include/core/SkRefCnt.h" #include "include/core/SkTypes.h" #include "include/encode/SkICC.h" #include "modules/skcms/skcms.h" #include "tests/Test.h" #include "tools/Resources.h" #include #include #include DEF_TEST(AdobeRGB, r) { if (sk_sp profile = GetResourceAsData("icc_profiles/AdobeRGB1998.icc")) { skcms_ICCProfile parsed; REPORTER_ASSERT(r, skcms_Parse(profile->data(), profile->size(), &parsed)); REPORTER_ASSERT(r, !parsed.has_CICP); auto got = SkColorSpace::Make(parsed); auto want = SkColorSpace::MakeRGB(SkNamedTransferFn::k2Dot2, SkNamedGamut::kAdobeRGB); REPORTER_ASSERT(r, SkColorSpace::Equals(got.get(), want.get())); } } DEF_TEST(HDR_ICC, r) { constexpr size_t kTestCount = 3; sk_sp profile[kTestCount] = { SkWriteICCProfile(SkNamedTransferFn::kPQ, SkNamedGamut::kRec2020), SkWriteICCProfile(SkNamedTransferFn::kHLG, SkNamedGamut::kDisplayP3), SkWriteICCProfile(SkNamedTransferFn::kSRGB, SkNamedGamut::kSRGB), }; sk_sp dst_profile[kTestCount] = { SkWriteICCProfile(SkNamedTransferFn::kLinear, SkNamedGamut::kRec2020), SkWriteICCProfile(SkNamedTransferFn::kLinear, SkNamedGamut::kDisplayP3), SkWriteICCProfile(SkNamedTransferFn::kLinear, SkNamedGamut::kSRGB), }; constexpr size_t kPixelCount = 7; // clang-format off float pixels[kPixelCount][3] = { { 0.00f, 0.00f, 0.00f, }, { 0.50f, 0.50f, 0.50f, }, { 0.50f, 0.00f, 0.00f, }, { 0.00f, 0.50f, 0.00f, }, { 0.00f, 0.00f, 0.50f, }, { 0.25f, 0.50f, 0.00f, }, { 0.75f, 0.75f, 0.75f, }, }; // The tone mapped value of PQ 0.5 and 0.75. constexpr float kPQ_05 = 0.3182877451f; constexpr float kPQ_075 = 0.9943588777f; // The tone mapped value of PQ 0.25, when maxRGB is 0.5. constexpr float kPQ_025 = 0.020679904f; // The tone mapped value of HLG 0.5 and 0.75 (when all channels are equal). constexpr float kHLG_05 = 0.20188954163f; constexpr float kHLG_075 = 0.5208149688f; // The linearized values of sRGB 0.25, 0.5, and 0.75. constexpr float kSRGB_025 = 0.05087607f; constexpr float kSRGB_05 = 0.21404112f; constexpr float kSRGB_075 = 0.52252153f; float dst_pixels_expected[kTestCount][kPixelCount][3] = { { { 0.f, 0.f, 0.f, }, { kPQ_05, kPQ_05, kPQ_05, }, { kPQ_05, 0.f, 0.f, }, { 0.f, kPQ_05, 0.f, }, { 0.f, 0.f, kPQ_05, }, { kPQ_025, kPQ_05, 0.f, }, { kPQ_075, kPQ_075, kPQ_075, }, // PQ maps 0.75 ~ 1000 nits to 1.0 }, { { 0.f, 0.f, 0.f, }, { kHLG_05, kHLG_05, kHLG_05, }, { 0.1618f, 0.f, 0.f, }, // HLG will map 0.5 to different values { 0.f, 0.1895f, 0.f, }, // if it is the R, G, or B channel, because { 0.f, 0.f, 0.1251f, }, // of the OOTF. { 0.0513f, 0.1924f, 0.f, }, { kHLG_075, kHLG_075, kHLG_075, }, }, { { 0.f, 0.f, 0.f, }, { kSRGB_05, kSRGB_05, kSRGB_05, }, // This is just the sRGB transfer function { kSRGB_05, 0.f, 0.f, }, { 0.f, kSRGB_05, 0.f, }, { 0.f, 0.f, kSRGB_05, }, { kSRGB_025, kSRGB_05, 0.f, }, { kSRGB_075, kSRGB_075, kSRGB_075, }, }, }; // clang-format on bool cicp_expected[kTestCount] = {true, true, false}; bool a2b_expected[kTestCount] = {true, true, false}; uint32_t cicp_primaries_expected[kTestCount] = {9, 12, 0}; uint32_t cicp_trfn_expected[kTestCount] = {16, 18, 0}; for (size_t test = 0; test < kTestCount; ++test) { skcms_ICCProfile parsed; REPORTER_ASSERT(r, skcms_Parse(profile[test]->data(), profile[test]->size(), &parsed)); REPORTER_ASSERT(r, parsed.has_A2B == a2b_expected[test]); REPORTER_ASSERT(r, parsed.has_CICP == cicp_expected[test]); if (cicp_expected[test]) { REPORTER_ASSERT(r, parsed.CICP.color_primaries == cicp_primaries_expected[test]); REPORTER_ASSERT(r, parsed.CICP.transfer_characteristics == cicp_trfn_expected[test]); REPORTER_ASSERT(r, parsed.CICP.matrix_coefficients == 0); REPORTER_ASSERT(r, parsed.CICP.video_full_range_flag == 1); } skcms_ICCProfile dst_parsed; REPORTER_ASSERT( r, skcms_Parse(dst_profile[test]->data(), dst_profile[test]->size(), &dst_parsed)); for (size_t pixel = 0; pixel < kPixelCount; ++pixel) { float dst_pixel_actual[3]{0.f, 0.f, 0.f}; bool xform_result = skcms_Transform(pixels[pixel], skcms_PixelFormat_RGB_fff, skcms_AlphaFormat_Opaque, &parsed, dst_pixel_actual, skcms_PixelFormat_RGB_fff, skcms_AlphaFormat_Opaque, &dst_parsed, 1); REPORTER_ASSERT(r, xform_result); auto approx_equal = [=](float x, float y) { return std::abs(x - y) < 1.f / 64.f; }; for (size_t i = 0; i < 3; ++i) { REPORTER_ASSERT( r, approx_equal(dst_pixel_actual[i], dst_pixels_expected[test][pixel][i])); } } } }