jxl_decompressor.cc (3472B)
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 "tools/wasm_demo/jxl_decompressor.h" 7 8 #include <jxl/thread_parallel_runner_cxx.h> 9 10 #include <cstring> 11 #include <memory> 12 13 #include "lib/extras/dec/jxl.h" 14 #include "tools/wasm_demo/no_png.h" 15 16 extern "C" { 17 18 namespace { 19 20 struct DecompressorOutputPrivate { 21 // Due to "Standard Layout" rules it is guaranteed that address of the entity 22 // and its first non-static member are the same. 23 DecompressorOutput output; 24 }; 25 26 void MaybeMakeCicp(const jxl::extras::PackedPixelFile& ppf, 27 std::vector<uint8_t>* cicp) { 28 cicp->clear(); 29 const JxlColorEncoding& clr = ppf.color_encoding; 30 uint8_t color_primaries = 0; 31 uint8_t transfer_function = static_cast<uint8_t>(clr.transfer_function); 32 33 if (clr.color_space != JXL_COLOR_SPACE_RGB) { 34 return; 35 } 36 if (clr.primaries == JXL_PRIMARIES_P3) { 37 if (clr.white_point == JXL_WHITE_POINT_D65) { 38 color_primaries = 12; 39 } else if (clr.white_point == JXL_WHITE_POINT_DCI) { 40 color_primaries = 11; 41 } else { 42 return; 43 } 44 } else if (clr.primaries != JXL_PRIMARIES_CUSTOM && 45 clr.white_point == JXL_WHITE_POINT_D65) { 46 color_primaries = static_cast<uint8_t>(clr.primaries); 47 } else { 48 return; 49 } 50 if (clr.transfer_function == JXL_TRANSFER_FUNCTION_UNKNOWN || 51 clr.transfer_function == JXL_TRANSFER_FUNCTION_GAMMA) { 52 return; 53 } 54 55 cicp->resize(4); 56 cicp->at(0) = color_primaries; // Colour Primaries 57 cicp->at(1) = transfer_function; // Transfer Function 58 cicp->at(2) = 0; // Matrix Coefficients 59 cicp->at(3) = 1; // Video Full Range Flag 60 } 61 62 } // namespace 63 64 DecompressorOutput* jxlDecompress(const uint8_t* input, size_t input_size) { 65 DecompressorOutputPrivate* self = new DecompressorOutputPrivate(); 66 67 if (!self) { 68 return nullptr; 69 } 70 71 auto report_error = [&](uint32_t code, const char* text) { 72 fprintf(stderr, "%s\n", text); 73 delete self; 74 return reinterpret_cast<DecompressorOutput*>(code); 75 }; 76 77 auto thread_pool = JxlThreadParallelRunnerMake(nullptr, 4); 78 void* runner = thread_pool.get(); 79 80 jxl::extras::JXLDecompressParams dparams; 81 JxlPixelFormat format = {/* num_channels */ 3, JXL_TYPE_UINT16, 82 JXL_BIG_ENDIAN, /* align */ 0}; 83 dparams.accepted_formats.push_back(format); 84 dparams.runner = JxlThreadParallelRunner; 85 dparams.runner_opaque = runner; 86 jxl::extras::PackedPixelFile ppf; 87 88 if (!jxl::extras::DecodeImageJXL(input, input_size, dparams, nullptr, &ppf)) { 89 return report_error(1, "failed to decode jxl"); 90 } 91 92 // Just 1-st frame. 93 const auto& image = ppf.frames[0].color; 94 std::vector<uint8_t> cicp; 95 MaybeMakeCicp(ppf, &cicp); 96 self->output.data = WrapPixelsToPng( 97 image.xsize, image.ysize, (format.data_type == JXL_TYPE_UINT16) ? 16 : 8, 98 /* has_alpha */ false, reinterpret_cast<const uint8_t*>(image.pixels()), 99 ppf.icc, cicp, &self->output.size); 100 if (!self->output.data) { 101 return report_error(2, "failed to encode png"); 102 } 103 104 return &self->output; 105 } 106 107 void jxlCleanup(DecompressorOutput* output) { 108 if (output == nullptr) return; 109 DecompressorOutputPrivate* self = 110 reinterpret_cast<DecompressorOutputPrivate*>(output); 111 if (self->output.data) { 112 free(self->output.data); 113 } 114 delete self; 115 } 116 117 } // extern "C"