tone_map.cc (3589B)
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/tone_mapping.h" 11 #include "tools/args.h" 12 #include "tools/cmdline.h" 13 #include "tools/file_io.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 max_nits = 0; 22 parser.AddOptionValue('m', "max_nits", "nits", 23 "maximum luminance in the image", &max_nits, 24 &jpegxl::tools::ParseFloat, 0); 25 float target_nits = 0; 26 auto target_nits_option = parser.AddOptionValue( 27 't', "target_nits", "nits", 28 "peak luminance of the display for which to tone map", &target_nits, 29 &jpegxl::tools::ParseFloat, 0); 30 float preserve_saturation = .1f; 31 parser.AddOptionValue( 32 's', "preserve_saturation", "0..1", 33 "to what extent to try and preserve saturation over luminance", 34 &preserve_saturation, &jpegxl::tools::ParseFloat, 0); 35 bool pq = false; 36 parser.AddOptionFlag('p', "pq", 37 "write the output with absolute luminance using PQ", &pq, 38 &jpegxl::tools::SetBooleanTrue, 0); 39 const char* input_filename = nullptr; 40 auto input_filename_option = parser.AddPositionalOption( 41 "input", true, "input image", &input_filename, 0); 42 const char* output_filename = nullptr; 43 auto output_filename_option = parser.AddPositionalOption( 44 "output", true, "output image", &output_filename, 0); 45 46 if (!parser.Parse(argc, argv)) { 47 fprintf(stderr, "See -h for help.\n"); 48 return EXIT_FAILURE; 49 } 50 51 if (parser.HelpFlagPassed()) { 52 parser.PrintHelp(); 53 return EXIT_SUCCESS; 54 } 55 56 if (!parser.GetOption(target_nits_option)->matched()) { 57 fprintf(stderr, 58 "Missing required argument --target_nits.\nSee -h for help.\n"); 59 return EXIT_FAILURE; 60 } 61 if (!parser.GetOption(input_filename_option)->matched()) { 62 fprintf(stderr, "Missing input filename.\nSee -h for help.\n"); 63 return EXIT_FAILURE; 64 } 65 if (!parser.GetOption(output_filename_option)->matched()) { 66 fprintf(stderr, "Missing output filename.\nSee -h for help.\n"); 67 return EXIT_FAILURE; 68 } 69 70 jxl::CodecInOut image; 71 jxl::extras::ColorHints color_hints; 72 color_hints.Add("color_space", "RGB_D65_202_Rel_PeQ"); 73 std::vector<uint8_t> encoded; 74 JXL_CHECK(jpegxl::tools::ReadFile(input_filename, &encoded)); 75 JXL_CHECK(jxl::SetFromBytes(jxl::Bytes(encoded), color_hints, &image, &pool)); 76 if (max_nits > 0) { 77 image.metadata.m.SetIntensityTarget(max_nits); 78 } 79 JXL_CHECK(jxl::ToneMapTo({0, target_nits}, &image, &pool)); 80 JXL_CHECK(jxl::GamutMap(&image, preserve_saturation, &pool)); 81 82 jxl::ColorEncoding c_out = image.metadata.m.color_encoding; 83 jxl::cms::TransferFunction tf = 84 pq ? jxl::TransferFunction::kPQ : jxl::TransferFunction::kSRGB; 85 86 if (jxl::extras::CodecFromPath(output_filename) == jxl::extras::Codec::kEXR) { 87 tf = jxl::TransferFunction::kLinear; 88 image.metadata.m.SetFloat16Samples(); 89 } 90 c_out.Tf().SetTransferFunction(tf); 91 92 JXL_CHECK(c_out.CreateICC()); 93 JXL_CHECK(jpegxl::tools::TransformCodecInOutTo(image, c_out, &pool)); 94 image.metadata.m.color_encoding = c_out; 95 JXL_CHECK(jpegxl::tools::Encode(image, output_filename, &encoded, &pool)); 96 JXL_CHECK(jpegxl::tools::WriteFile(output_filename, encoded)); 97 }