render_hlg.cc (3752B)
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 <stdio.h> 7 #include <stdlib.h> 8 9 #include "lib/extras/codec.h" 10 #include "lib/extras/hlg.h" 11 #include "lib/extras/tone_mapping.h" 12 #include "tools/args.h" 13 #include "tools/cmdline.h" 14 #include "tools/hdr/image_utils.h" 15 #include "tools/thread_pool_internal.h" 16 17 int main(int argc, const char** argv) { 18 jpegxl::tools::ThreadPoolInternal pool; 19 20 jpegxl::tools::CommandLineParser parser; 21 float target_nits = 0; 22 auto target_nits_option = parser.AddOptionValue( 23 't', "target_nits", "nits", "peak luminance of the target display", 24 &target_nits, &jpegxl::tools::ParseFloat, 0); 25 float surround_nits = 5; 26 parser.AddOptionValue( 27 's', "surround_nits", "nits", 28 "surround luminance of the viewing environment (default: 5)", 29 &surround_nits, &jpegxl::tools::ParseFloat, 0); 30 float preserve_saturation = .1f; 31 parser.AddOptionValue( 32 '\0', "preserve_saturation", "0..1", 33 "to what extent to try and preserve saturation over luminance if a gamma " 34 "< 1 generates out-of-gamut colors", 35 &preserve_saturation, &jpegxl::tools::ParseFloat, 0); 36 bool pq = false; 37 parser.AddOptionFlag('p', "pq", 38 "write the output with absolute luminance using PQ", &pq, 39 &jpegxl::tools::SetBooleanTrue, 0); 40 const char* input_filename = nullptr; 41 auto input_filename_option = parser.AddPositionalOption( 42 "input", true, "input image", &input_filename, 0); 43 const char* output_filename = nullptr; 44 auto output_filename_option = parser.AddPositionalOption( 45 "output", true, "output image", &output_filename, 0); 46 47 if (!parser.Parse(argc, argv)) { 48 fprintf(stderr, "See -h for help.\n"); 49 return EXIT_FAILURE; 50 } 51 52 if (parser.HelpFlagPassed()) { 53 parser.PrintHelp(); 54 return EXIT_SUCCESS; 55 } 56 57 if (!parser.GetOption(target_nits_option)->matched()) { 58 fprintf(stderr, 59 "Missing required argument --target_nits.\nSee -h for help.\n"); 60 return EXIT_FAILURE; 61 } 62 if (!parser.GetOption(input_filename_option)->matched()) { 63 fprintf(stderr, "Missing input filename.\nSee -h for help.\n"); 64 return EXIT_FAILURE; 65 } 66 if (!parser.GetOption(output_filename_option)->matched()) { 67 fprintf(stderr, "Missing output filename.\nSee -h for help.\n"); 68 return EXIT_FAILURE; 69 } 70 71 jxl::CodecInOut image; 72 jxl::extras::ColorHints color_hints; 73 color_hints.Add("color_space", "RGB_D65_202_Rel_HLG"); 74 std::vector<uint8_t> encoded; 75 JXL_CHECK(jpegxl::tools::ReadFile(input_filename, &encoded)); 76 JXL_CHECK(jxl::SetFromBytes(jxl::Bytes(encoded), color_hints, &image, &pool)); 77 // Ensures that conversions to linear by JxlCms will not apply the OOTF as we 78 // apply it ourselves to control the subsequent gamut mapping. 79 image.metadata.m.SetIntensityTarget(301); 80 const float gamma = jxl::GetHlgGamma(target_nits, surround_nits); 81 fprintf(stderr, "Using a system gamma of %g\n", gamma); 82 JXL_CHECK(jxl::HlgOOTF(&image.Main(), gamma, &pool)); 83 JXL_CHECK(jxl::GamutMap(&image, preserve_saturation, &pool)); 84 image.metadata.m.SetIntensityTarget(target_nits); 85 86 jxl::ColorEncoding c_out = image.metadata.m.color_encoding; 87 jxl::cms::TransferFunction tf = 88 pq ? jxl::TransferFunction::kPQ : jxl::TransferFunction::kSRGB; 89 c_out.Tf().SetTransferFunction(tf); 90 JXL_CHECK(c_out.CreateICC()); 91 JXL_CHECK(jpegxl::tools::TransformCodecInOutTo(image, c_out, &pool)); 92 image.metadata.m.color_encoding = c_out; 93 JXL_CHECK(jpegxl::tools::Encode(image, output_filename, &encoded, &pool)); 94 JXL_CHECK(jpegxl::tools::WriteFile(output_filename, encoded)); 95 }