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