tone_mapping.cc (4644B)
1 // Copyright (c) the JPEG XL Project Authors. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style 4 // license that can be found in the LICENSE file. 5 6 #include "lib/extras/tone_mapping.h" 7 8 #undef HWY_TARGET_INCLUDE 9 #define HWY_TARGET_INCLUDE "lib/extras/tone_mapping.cc" 10 #include <jxl/cms.h> 11 12 #include <hwy/foreach_target.h> 13 #include <hwy/highway.h> 14 15 #include "lib/jxl/cms/tone_mapping-inl.h" 16 #include "lib/jxl/image_bundle.h" 17 18 HWY_BEFORE_NAMESPACE(); 19 namespace jxl { 20 namespace HWY_NAMESPACE { 21 22 static constexpr float rec2020_luminances[3] = {0.2627f, 0.6780f, 0.0593f}; 23 24 Status ToneMapFrame(const std::pair<float, float> display_nits, 25 ImageBundle* const ib, ThreadPool* const pool) { 26 // Perform tone mapping as described in Report ITU-R BT.2390-8, section 5.4 27 // (pp. 23-25). 28 // https://www.itu.int/pub/R-REP-BT.2390-8-2020 29 30 HWY_FULL(float) df; 31 using V = decltype(Zero(df)); 32 33 ColorEncoding linear_rec2020; 34 linear_rec2020.SetColorSpace(ColorSpace::kRGB); 35 JXL_RETURN_IF_ERROR(linear_rec2020.SetPrimariesType(Primaries::k2100)); 36 JXL_RETURN_IF_ERROR(linear_rec2020.SetWhitePointType(WhitePoint::kD65)); 37 linear_rec2020.Tf().SetTransferFunction(TransferFunction::kLinear); 38 JXL_RETURN_IF_ERROR(linear_rec2020.CreateICC()); 39 JXL_RETURN_IF_ERROR( 40 ib->TransformTo(linear_rec2020, *JxlGetDefaultCms(), pool)); 41 42 Rec2408ToneMapper<decltype(df)> tone_mapper( 43 {ib->metadata()->tone_mapping.min_nits, 44 ib->metadata()->IntensityTarget()}, 45 display_nits, rec2020_luminances); 46 47 return RunOnPool( 48 pool, 0, ib->ysize(), ThreadPool::NoInit, 49 [&](const uint32_t y, size_t /* thread */) { 50 float* const JXL_RESTRICT row_r = ib->color()->PlaneRow(0, y); 51 float* const JXL_RESTRICT row_g = ib->color()->PlaneRow(1, y); 52 float* const JXL_RESTRICT row_b = ib->color()->PlaneRow(2, y); 53 for (size_t x = 0; x < ib->xsize(); x += Lanes(df)) { 54 V red = Load(df, row_r + x); 55 V green = Load(df, row_g + x); 56 V blue = Load(df, row_b + x); 57 tone_mapper.ToneMap(&red, &green, &blue); 58 Store(red, df, row_r + x); 59 Store(green, df, row_g + x); 60 Store(blue, df, row_b + x); 61 } 62 }, 63 "ToneMap"); 64 } 65 66 Status GamutMapFrame(ImageBundle* const ib, float preserve_saturation, 67 ThreadPool* const pool) { 68 HWY_FULL(float) df; 69 using V = decltype(Zero(df)); 70 71 ColorEncoding linear_rec2020; 72 linear_rec2020.SetColorSpace(ColorSpace::kRGB); 73 JXL_RETURN_IF_ERROR(linear_rec2020.SetPrimariesType(Primaries::k2100)); 74 JXL_RETURN_IF_ERROR(linear_rec2020.SetWhitePointType(WhitePoint::kD65)); 75 linear_rec2020.Tf().SetTransferFunction(TransferFunction::kLinear); 76 JXL_RETURN_IF_ERROR(linear_rec2020.CreateICC()); 77 JXL_RETURN_IF_ERROR( 78 ib->TransformTo(linear_rec2020, *JxlGetDefaultCms(), pool)); 79 80 JXL_RETURN_IF_ERROR(RunOnPool( 81 pool, 0, ib->ysize(), ThreadPool::NoInit, 82 [&](const uint32_t y, size_t /* thread*/) { 83 float* const JXL_RESTRICT row_r = ib->color()->PlaneRow(0, y); 84 float* const JXL_RESTRICT row_g = ib->color()->PlaneRow(1, y); 85 float* const JXL_RESTRICT row_b = ib->color()->PlaneRow(2, y); 86 for (size_t x = 0; x < ib->xsize(); x += Lanes(df)) { 87 V red = Load(df, row_r + x); 88 V green = Load(df, row_g + x); 89 V blue = Load(df, row_b + x); 90 GamutMap(&red, &green, &blue, rec2020_luminances, 91 preserve_saturation); 92 Store(red, df, row_r + x); 93 Store(green, df, row_g + x); 94 Store(blue, df, row_b + x); 95 } 96 }, 97 "GamutMap")); 98 99 return true; 100 } 101 102 // NOLINTNEXTLINE(google-readability-namespace-comments) 103 } // namespace HWY_NAMESPACE 104 } // namespace jxl 105 HWY_AFTER_NAMESPACE(); 106 107 #if HWY_ONCE 108 namespace jxl { 109 110 namespace { 111 HWY_EXPORT(ToneMapFrame); 112 HWY_EXPORT(GamutMapFrame); 113 } // namespace 114 115 Status ToneMapTo(const std::pair<float, float> display_nits, 116 CodecInOut* const io, ThreadPool* const pool) { 117 const auto tone_map_frame = HWY_DYNAMIC_DISPATCH(ToneMapFrame); 118 for (ImageBundle& ib : io->frames) { 119 JXL_RETURN_IF_ERROR(tone_map_frame(display_nits, &ib, pool)); 120 } 121 io->metadata.m.SetIntensityTarget(display_nits.second); 122 return true; 123 } 124 125 Status GamutMap(CodecInOut* const io, float preserve_saturation, 126 ThreadPool* const pool) { 127 const auto gamut_map_frame = HWY_DYNAMIC_DISPATCH(GamutMapFrame); 128 for (ImageBundle& ib : io->frames) { 129 JXL_RETURN_IF_ERROR(gamut_map_frame(&ib, preserve_saturation, pool)); 130 } 131 return true; 132 } 133 134 } // namespace jxl 135 #endif