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 <cmath>
10 
11 #include "lib/extras/codec.h"
12 #include "lib/extras/tone_mapping.h"
13 #include "lib/jxl/base/thread_pool_internal.h"
14 #include "tools/args.h"
15 #include "tools/cmdline.h"
16 
17 namespace jxl {
18 namespace {
19 
HlgInverseOOTF(ImageBundle * ib,ThreadPool * pool)20 Status HlgInverseOOTF(ImageBundle* ib, ThreadPool* pool) {
21   ColorEncoding linear_rec2020;
22   linear_rec2020.SetColorSpace(ColorSpace::kRGB);
23   linear_rec2020.primaries = Primaries::k2100;
24   linear_rec2020.white_point = WhitePoint::kD65;
25   linear_rec2020.tf.SetTransferFunction(TransferFunction::kLinear);
26   JXL_RETURN_IF_ERROR(linear_rec2020.CreateICC());
27   JXL_RETURN_IF_ERROR(ib->TransformTo(linear_rec2020, pool));
28 
29   return RunOnPool(
30       pool, 0, ib->ysize(), ThreadPool::SkipInit(),
31       [&](const int y, const int thread) {
32         float* const JXL_RESTRICT rows[3] = {ib->color()->PlaneRow(0, y),
33                                              ib->color()->PlaneRow(1, y),
34                                              ib->color()->PlaneRow(2, y)};
35         for (size_t x = 0; x < ib->xsize(); ++x) {
36           float& red = rows[0][x];
37           float& green = rows[1][x];
38           float& blue = rows[2][x];
39           const float luminance =
40               0.2627f * red + 0.6780f * green + 0.0593f * blue;
41           const float ratio = std::pow(luminance, 1 / 1.2f - 1);
42           if (std::isfinite(ratio)) {
43             red *= ratio;
44             green *= ratio;
45             blue *= ratio;
46           }
47         }
48       },
49       "HlgInverseOOTF");
50 }
51 
52 }  // namespace
53 }  // namespace jxl
54 
main(int argc,const char ** argv)55 int main(int argc, const char** argv) {
56   jxl::ThreadPoolInternal pool;
57 
58   jpegxl::tools::CommandLineParser parser;
59   float max_nits = 0;
60   parser.AddOptionValue('m', "max_nits", "nits",
61                         "maximum luminance in the image", &max_nits,
62                         &jpegxl::tools::ParseFloat, 0);
63   const char* input_filename = nullptr;
64   auto input_filename_option = parser.AddPositionalOption(
65       "input", true, "input image", &input_filename, 0);
66   const char* output_filename = nullptr;
67   auto output_filename_option = parser.AddPositionalOption(
68       "output", true, "output image", &output_filename, 0);
69 
70   if (!parser.Parse(argc, argv)) {
71     fprintf(stderr, "See -h for help.\n");
72     return EXIT_FAILURE;
73   }
74 
75   if (parser.HelpFlagPassed()) {
76     parser.PrintHelp();
77     return EXIT_SUCCESS;
78   }
79 
80   if (!parser.GetOption(input_filename_option)->matched()) {
81     fprintf(stderr, "Missing input filename.\nSee -h for help.\n");
82     return EXIT_FAILURE;
83   }
84   if (!parser.GetOption(output_filename_option)->matched()) {
85     fprintf(stderr, "Missing output filename.\nSee -h for help.\n");
86     return EXIT_FAILURE;
87   }
88 
89   jxl::CodecInOut image;
90   jxl::ColorHints color_hints;
91   color_hints.Add("color_space", "RGB_D65_202_Rel_PeQ");
92   JXL_CHECK(jxl::SetFromFile(input_filename, color_hints, &image, &pool));
93   if (max_nits > 0) {
94     image.metadata.m.SetIntensityTarget(max_nits);
95   }
96   JXL_CHECK(jxl::ToneMapTo({0, 1000}, &image, &pool));
97   JXL_CHECK(jxl::HlgInverseOOTF(&image.Main(), &pool));
98 
99   jxl::ColorEncoding hlg;
100   hlg.SetColorSpace(jxl::ColorSpace::kRGB);
101   hlg.primaries = jxl::Primaries::k2100;
102   hlg.white_point = jxl::WhitePoint::kD65;
103   hlg.tf.SetTransferFunction(jxl::TransferFunction::kHLG);
104   JXL_CHECK(hlg.CreateICC());
105   JXL_CHECK(image.TransformTo(hlg, &pool));
106   image.metadata.m.color_encoding = hlg;
107   JXL_CHECK(jxl::EncodeToFile(image, output_filename, &pool));
108 }
109