pq_to_hlg.cc (3265B)
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 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 preserve_saturation = .1f; 26 parser.AddOptionValue( 27 's', "preserve_saturation", "0..1", 28 "to what extent to try and preserve saturation over luminance", 29 &preserve_saturation, &jpegxl::tools::ParseFloat, 0); 30 const char* input_filename = nullptr; 31 auto input_filename_option = parser.AddPositionalOption( 32 "input", true, "input image", &input_filename, 0); 33 const char* output_filename = nullptr; 34 auto output_filename_option = parser.AddPositionalOption( 35 "output", true, "output image", &output_filename, 0); 36 37 if (!parser.Parse(argc, argv)) { 38 fprintf(stderr, "See -h for help.\n"); 39 return EXIT_FAILURE; 40 } 41 42 if (parser.HelpFlagPassed()) { 43 parser.PrintHelp(); 44 return EXIT_SUCCESS; 45 } 46 47 if (!parser.GetOption(input_filename_option)->matched()) { 48 fprintf(stderr, "Missing input filename.\nSee -h for help.\n"); 49 return EXIT_FAILURE; 50 } 51 if (!parser.GetOption(output_filename_option)->matched()) { 52 fprintf(stderr, "Missing output filename.\nSee -h for help.\n"); 53 return EXIT_FAILURE; 54 } 55 56 jxl::CodecInOut image; 57 jxl::extras::ColorHints color_hints; 58 color_hints.Add("color_space", "RGB_D65_202_Rel_PeQ"); 59 std::vector<uint8_t> encoded; 60 JXL_CHECK(jpegxl::tools::ReadFile(input_filename, &encoded)); 61 JXL_CHECK(jxl::SetFromBytes(jxl::Bytes(encoded), color_hints, &image, &pool)); 62 if (max_nits > 0) { 63 image.metadata.m.SetIntensityTarget(max_nits); 64 } 65 const jxl::Primaries original_primaries = 66 image.Main().c_current().GetPrimariesType(); 67 JXL_CHECK(jxl::ToneMapTo({0, 1000}, &image, &pool)); 68 JXL_CHECK(jxl::HlgInverseOOTF(&image.Main(), 1.2f, &pool)); 69 JXL_CHECK(jxl::GamutMap(&image, preserve_saturation, &pool)); 70 // Peak luminance at which the system gamma is 1, since we are now in scene 71 // light, having applied the inverse OOTF ourselves to control the subsequent 72 // gamut mapping instead of leaving it to JxlCms below. 73 image.metadata.m.SetIntensityTarget(301); 74 75 jxl::ColorEncoding hlg; 76 hlg.SetColorSpace(jxl::ColorSpace::kRGB); 77 JXL_CHECK(hlg.SetPrimariesType(original_primaries)); 78 JXL_CHECK(hlg.SetWhitePointType(jxl::WhitePoint::kD65)); 79 hlg.Tf().SetTransferFunction(jxl::TransferFunction::kHLG); 80 JXL_CHECK(hlg.CreateICC()); 81 JXL_CHECK(jpegxl::tools::TransformCodecInOutTo(image, hlg, &pool)); 82 image.metadata.m.color_encoding = hlg; 83 JXL_CHECK(jpegxl::tools::Encode(image, output_filename, &encoded, &pool)); 84 JXL_CHECK(jpegxl::tools::WriteFile(output_filename, encoded)); 85 }