diff options
author | jiyong.min <jiyong.min@samsung.com> | 2022-12-07 10:34:18 +0900 |
---|---|---|
committer | jiyong.min <jiyong.min@samsung.com> | 2022-12-07 13:37:38 +0900 |
commit | 8f303a6e2069fd39246decb4fe7aecb221cb134a (patch) | |
tree | 64704d2db44568e6a99cd4b8f159e9e94bbaefbc /examples | |
parent | b2051fff838fd13eda203439f58679cbefea065e (diff) | |
parent | 7fa2aaed0a5c855460b77fb1fedcc01591ff6470 (diff) | |
download | libjxl-accepted/tizen/unified/20221216.024040.tar.gz libjxl-accepted/tizen/unified/20221216.024040.tar.bz2 libjxl-accepted/tizen/unified/20221216.024040.zip |
Bump to 0.7.0accepted/tizen/unified/20221216.024040
Change-Id: Ib06199c1a967d1c08974f2e95f085ade02c5fb72
Diffstat (limited to 'examples')
-rw-r--r-- | examples/CMakeLists.txt | 6 | ||||
-rw-r--r-- | examples/decode_exif_metadata.cc | 173 | ||||
-rw-r--r-- | examples/decode_oneshot.cc | 7 | ||||
-rw-r--r-- | examples/decode_progressive.cc | 238 | ||||
-rw-r--r-- | examples/encode_oneshot.cc | 8 | ||||
-rw-r--r-- | examples/examples.cmake | 12 | ||||
-rw-r--r-- | examples/jxlinfo.c | 317 |
7 files changed, 427 insertions, 334 deletions
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 64510e5..88dc27c 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -19,12 +19,12 @@ pkg_check_modules(JxlThreads REQUIRED IMPORTED_TARGET libjxl_threads) add_executable(decode_oneshot decode_oneshot.cc) target_link_libraries(decode_oneshot PkgConfig::Jxl PkgConfig::JxlThreads) +add_executable(decode_progressive decode_progressive.cc) +target_link_libraries(decode_progressive PkgConfig::Jxl PkgConfig::JxlThreads) + add_executable(encode_oneshot encode_oneshot.cc) target_link_libraries(encode_oneshot PkgConfig::Jxl PkgConfig::JxlThreads) -add_executable(jxlinfo jxlinfo.c) -target_link_libraries(jxlinfo PkgConfig::Jxl) - # Building a static binary with the static libjxl dependencies. How to load # static library configs from pkg-config and how to build static binaries diff --git a/examples/decode_exif_metadata.cc b/examples/decode_exif_metadata.cc new file mode 100644 index 0000000..adfe5f8 --- /dev/null +++ b/examples/decode_exif_metadata.cc @@ -0,0 +1,173 @@ +// Copyright (c) the JPEG XL Project Authors. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This C++ example decodes a JPEG XL image in one shot (all input bytes +// available at once). The example outputs the pixels and color information to a +// floating point image and an ICC profile on disk. + +#include <limits.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +#include <vector> + +#include "jxl/decode.h" +#include "jxl/decode_cxx.h" + +bool DecodeJpegXlExif(const uint8_t* jxl, size_t size, + std::vector<uint8_t>* exif) { + auto dec = JxlDecoderMake(nullptr); + + // We're only interested in the Exif boxes in this example, so don't + // subscribe to events related to pixel data. + if (JXL_DEC_SUCCESS != JxlDecoderSubscribeEvents(dec.get(), JXL_DEC_BOX)) { + fprintf(stderr, "JxlDecoderSubscribeEvents failed\n"); + return false; + } + bool support_decompression = true; + if (JXL_DEC_SUCCESS != JxlDecoderSetDecompressBoxes(dec.get(), JXL_TRUE)) { + fprintf(stderr, + "NOTE: decompressing brob boxes not supported with the currently " + "used jxl library.\n"); + support_decompression = false; + } + + JxlDecoderSetInput(dec.get(), jxl, size); + JxlDecoderCloseInput(dec.get()); + + const constexpr size_t kChunkSize = 65536; + size_t output_pos = 0; + + for (;;) { + JxlDecoderStatus status = JxlDecoderProcessInput(dec.get()); + if (status == JXL_DEC_ERROR) { + fprintf(stderr, "Decoder error\n"); + return false; + } else if (status == JXL_DEC_NEED_MORE_INPUT) { + fprintf(stderr, "Error, already provided all input\n"); + return false; + } else if (status == JXL_DEC_BOX) { + if (!exif->empty()) { + size_t remaining = JxlDecoderReleaseBoxBuffer(dec.get()); + exif->resize(exif->size() - remaining); + // No need to wait for JXL_DEC_SUCCESS or decode other boxes. + return true; + } + JxlBoxType type; + if (JXL_DEC_SUCCESS != + JxlDecoderGetBoxType(dec.get(), type, support_decompression)) { + fprintf(stderr, "Error, failed to get box type\n"); + return false; + } + if (!memcmp(type, "Exif", 4)) { + exif->resize(kChunkSize); + JxlDecoderSetBoxBuffer(dec.get(), exif->data(), exif->size()); + } + } else if (status == JXL_DEC_BOX_NEED_MORE_OUTPUT) { + size_t remaining = JxlDecoderReleaseBoxBuffer(dec.get()); + output_pos += kChunkSize - remaining; + exif->resize(exif->size() + kChunkSize); + JxlDecoderSetBoxBuffer(dec.get(), exif->data() + output_pos, + exif->size() - output_pos); + } else if (status == JXL_DEC_SUCCESS) { + if (!exif->empty()) { + size_t remaining = JxlDecoderReleaseBoxBuffer(dec.get()); + exif->resize(exif->size() - remaining); + return true; + } + return true; + } else { + fprintf(stderr, "Unknown decoder status\n"); + return false; + } + } +} + +bool LoadFile(const char* filename, std::vector<uint8_t>* out) { + FILE* file = fopen(filename, "rb"); + if (!file) { + return false; + } + + if (fseek(file, 0, SEEK_END) != 0) { + fclose(file); + return false; + } + + long size = ftell(file); + // Avoid invalid file or directory. + if (size >= LONG_MAX || size < 0) { + fclose(file); + return false; + } + + if (fseek(file, 0, SEEK_SET) != 0) { + fclose(file); + return false; + } + + out->resize(size); + size_t readsize = fread(out->data(), 1, size, file); + if (fclose(file) != 0) { + return false; + } + + return readsize == static_cast<size_t>(size); +} + +bool WriteFile(const char* filename, const uint8_t* data, size_t size) { + FILE* file = fopen(filename, "wb"); + if (!file) { + fprintf(stderr, "Could not open %s for writing", filename); + return false; + } + fwrite(data, 1, size, file); + if (fclose(file) != 0) { + return false; + } + return true; +} + +int main(int argc, char* argv[]) { + if (argc != 3) { + fprintf(stderr, + "Usage: %s <jxl> <exif>\n" + "Where:\n" + " jxl = input JPEG XL image filename\n" + " exif = output exif filename\n" + "Output files will be overwritten.\n", + argv[0]); + return 1; + } + + const char* jxl_filename = argv[1]; + const char* exif_filename = argv[2]; + + std::vector<uint8_t> jxl; + if (!LoadFile(jxl_filename, &jxl)) { + fprintf(stderr, "couldn't load %s\n", jxl_filename); + return 1; + } + + std::vector<uint8_t> exif; + if (!DecodeJpegXlExif(jxl.data(), jxl.size(), &exif)) { + fprintf(stderr, "Error while decoding the jxl file\n"); + return 1; + } + if (exif.empty()) { + printf("No exif data present in this image\n"); + } else { + // TODO(lode): the exif box data contains the 4-byte TIFF header at the + // beginning, check whether this is desired to be part of the output, or + // should be removed. + if (!WriteFile(exif_filename, exif.data(), exif.size())) { + fprintf(stderr, "Error while writing the exif file\n"); + return 1; + } + printf("Successfully wrote %s\n", exif_filename); + } + return 0; +} diff --git a/examples/decode_oneshot.cc b/examples/decode_oneshot.cc index 360c8d2..932193f 100644 --- a/examples/decode_oneshot.cc +++ b/examples/decode_oneshot.cc @@ -7,6 +7,7 @@ // available at once). The example outputs the pixels and color information to a // floating point image and an ICC profile on disk. +#include <inttypes.h> #include <limits.h> #include <stdint.h> #include <stdio.h> @@ -51,6 +52,7 @@ bool DecodeJpegXlOneShot(const uint8_t* jxl, size_t size, JxlPixelFormat format = {4, JXL_TYPE_FLOAT, JXL_NATIVE_ENDIAN, 0}; JxlDecoderSetInput(dec.get(), jxl, size); + JxlDecoderCloseInput(dec.get()); for (;;) { JxlDecoderStatus status = JxlDecoderProcessInput(dec.get()); @@ -96,8 +98,9 @@ bool DecodeJpegXlOneShot(const uint8_t* jxl, size_t size, return false; } if (buffer_size != *xsize * *ysize * 16) { - fprintf(stderr, "Invalid out buffer size %zu %zu\n", buffer_size, - *xsize * *ysize * 16); + fprintf(stderr, "Invalid out buffer size %" PRIu64 " %" PRIu64 "\n", + static_cast<uint64_t>(buffer_size), + static_cast<uint64_t>(*xsize * *ysize * 16)); return false; } pixels->resize(*xsize * *ysize * 4); diff --git a/examples/decode_progressive.cc b/examples/decode_progressive.cc new file mode 100644 index 0000000..77d2a0f --- /dev/null +++ b/examples/decode_progressive.cc @@ -0,0 +1,238 @@ +// Copyright (c) the JPEG XL Project Authors. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This C++ example decodes a JPEG XL image progressively (input bytes are +// passed in chunks). The example outputs the intermediate steps to PAM files. + +#include <inttypes.h> +#include <limits.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +#include <vector> + +#include "jxl/decode.h" +#include "jxl/decode_cxx.h" +#include "jxl/resizable_parallel_runner.h" +#include "jxl/resizable_parallel_runner_cxx.h" + +bool WritePAM(const char* filename, const uint8_t* buffer, size_t w, size_t h) { + FILE* fp = fopen(filename, "wb"); + if (!fp) { + fprintf(stderr, "Could not open %s for writing", filename); + return false; + } + fprintf(fp, + "P7\nWIDTH %" PRIu64 "\nHEIGHT %" PRIu64 + "\nDEPTH 4\nMAXVAL 255\nTUPLTYPE " + "RGB_ALPHA\nENDHDR\n", + static_cast<uint64_t>(w), static_cast<uint64_t>(h)); + fwrite(buffer, 1, w * h * 4, fp); + if (fclose(fp) != 0) { + return false; + } + return true; +} + +/** Decodes JPEG XL image to 8-bit integer RGBA pixels and an ICC Profile, in a + * progressive way, saving the intermediate steps. + */ +bool DecodeJpegXlProgressive(const uint8_t* jxl, size_t size, + const char* filename, size_t chunksize) { + std::vector<uint8_t> pixels; + std::vector<uint8_t> icc_profile; + size_t xsize = 0, ysize = 0; + + // Multi-threaded parallel runner. + auto runner = JxlResizableParallelRunnerMake(nullptr); + + auto dec = JxlDecoderMake(nullptr); + if (JXL_DEC_SUCCESS != + JxlDecoderSubscribeEvents(dec.get(), JXL_DEC_BASIC_INFO | + JXL_DEC_COLOR_ENCODING | + JXL_DEC_FULL_IMAGE)) { + fprintf(stderr, "JxlDecoderSubscribeEvents failed\n"); + return false; + } + + if (JXL_DEC_SUCCESS != JxlDecoderSetParallelRunner(dec.get(), + JxlResizableParallelRunner, + runner.get())) { + fprintf(stderr, "JxlDecoderSetParallelRunner failed\n"); + return false; + } + + JxlBasicInfo info; + JxlPixelFormat format = {4, JXL_TYPE_UINT8, JXL_NATIVE_ENDIAN, 0}; + + size_t seen = 0; + JxlDecoderSetInput(dec.get(), jxl, chunksize); + size_t remaining = chunksize; + + for (;;) { + JxlDecoderStatus status = JxlDecoderProcessInput(dec.get()); + + if (status == JXL_DEC_ERROR) { + fprintf(stderr, "Decoder error\n"); + return false; + } else if (status == JXL_DEC_NEED_MORE_INPUT || status == JXL_DEC_SUCCESS || + status == JXL_DEC_FULL_IMAGE) { + seen += remaining - JxlDecoderReleaseInput(dec.get()); + printf("Flushing after %" PRIu64 " bytes\n", static_cast<uint64_t>(seen)); + if (status == JXL_DEC_NEED_MORE_INPUT && + JXL_DEC_SUCCESS != JxlDecoderFlushImage(dec.get())) { + printf("flush error (no preview yet)\n"); + } else { + char fname[1024]; + if (snprintf(fname, 1024, "%s-%" PRIu64 ".pam", filename, + static_cast<uint64_t>(seen)) >= 1024) { + fprintf(stderr, "Filename too long\n"); + return false; + }; + if (!WritePAM(fname, pixels.data(), xsize, ysize)) { + fprintf(stderr, "Error writing progressive output\n"); + } + } + remaining = size - seen; + if (remaining > chunksize) remaining = chunksize; + if (remaining == 0) { + if (status == JXL_DEC_NEED_MORE_INPUT) { + fprintf(stderr, "Error, already provided all input\n"); + return false; + } else { + return true; + } + } + JxlDecoderSetInput(dec.get(), jxl + seen, remaining); + } else if (status == JXL_DEC_BASIC_INFO) { + if (JXL_DEC_SUCCESS != JxlDecoderGetBasicInfo(dec.get(), &info)) { + fprintf(stderr, "JxlDecoderGetBasicInfo failed\n"); + return false; + } + xsize = info.xsize; + ysize = info.ysize; + JxlResizableParallelRunnerSetThreads( + runner.get(), + JxlResizableParallelRunnerSuggestThreads(info.xsize, info.ysize)); + } else if (status == JXL_DEC_COLOR_ENCODING) { + // Get the ICC color profile of the pixel data + size_t icc_size; + if (JXL_DEC_SUCCESS != + JxlDecoderGetICCProfileSize(dec.get(), &format, + JXL_COLOR_PROFILE_TARGET_ORIGINAL, + &icc_size)) { + fprintf(stderr, "JxlDecoderGetICCProfileSize failed\n"); + return false; + } + icc_profile.resize(icc_size); + if (JXL_DEC_SUCCESS != JxlDecoderGetColorAsICCProfile( + dec.get(), &format, + JXL_COLOR_PROFILE_TARGET_ORIGINAL, + icc_profile.data(), icc_profile.size())) { + fprintf(stderr, "JxlDecoderGetColorAsICCProfile failed\n"); + return false; + } + } else if (status == JXL_DEC_NEED_IMAGE_OUT_BUFFER) { + size_t buffer_size; + if (JXL_DEC_SUCCESS != + JxlDecoderImageOutBufferSize(dec.get(), &format, &buffer_size)) { + fprintf(stderr, "JxlDecoderImageOutBufferSize failed\n"); + return false; + } + if (buffer_size != xsize * ysize * 4) { + fprintf(stderr, "Invalid out buffer size %" PRIu64 " != %" PRIu64 "\n", + static_cast<uint64_t>(buffer_size), + static_cast<uint64_t>(xsize * ysize * 4)); + return false; + } + pixels.resize(xsize * ysize * 4); + void* pixels_buffer = (void*)pixels.data(); + size_t pixels_buffer_size = pixels.size() * sizeof(float); + if (JXL_DEC_SUCCESS != JxlDecoderSetImageOutBuffer(dec.get(), &format, + pixels_buffer, + pixels_buffer_size)) { + fprintf(stderr, "JxlDecoderSetImageOutBuffer failed\n"); + return false; + } + } else { + fprintf(stderr, "Unknown decoder status\n"); + return false; + } + } +} + +bool LoadFile(const char* filename, std::vector<uint8_t>* out) { + FILE* file = fopen(filename, "rb"); + if (!file) { + return false; + } + + if (fseek(file, 0, SEEK_END) != 0) { + fclose(file); + return false; + } + + long size = ftell(file); + // Avoid invalid file or directory. + if (size >= LONG_MAX || size < 0) { + fclose(file); + return false; + } + + if (fseek(file, 0, SEEK_SET) != 0) { + fclose(file); + return false; + } + + out->resize(size); + size_t readsize = fread(out->data(), 1, size, file); + if (fclose(file) != 0) { + return false; + } + + return readsize == static_cast<size_t>(size); +} + +int main(int argc, char* argv[]) { + if (argc < 3) { + fprintf( + stderr, + "Usage: %s <jxl> <basename> [chunksize]\n" + "Where:\n" + " jxl = input JPEG XL image filename\n" + " basename = prefix of output filenames\n" + " chunksize = loads chunksize bytes at a time and writes\n" + " intermediate results to basename-[bytes loaded].pam\n" + "Output files will be overwritten.\n", + argv[0]); + return 1; + } + + const char* jxl_filename = argv[1]; + const char* png_filename = argv[2]; + + std::vector<uint8_t> jxl; + if (!LoadFile(jxl_filename, &jxl)) { + fprintf(stderr, "couldn't load %s\n", jxl_filename); + return 1; + } + size_t chunksize = jxl.size(); + if (argc > 3) { + long cs = atol(argv[3]); + if (cs < 100) { + fprintf(stderr, "Chunk size is too low, try at least 100 bytes\n"); + return 1; + } + chunksize = cs; + } + + if (!DecodeJpegXlProgressive(jxl.data(), jxl.size(), png_filename, + chunksize)) { + fprintf(stderr, "Error while decoding the jxl file\n"); + return 1; + } + return 0; +} diff --git a/examples/encode_oneshot.cc b/examples/encode_oneshot.cc index e3c9fdb..f1cd9ab 100644 --- a/examples/encode_oneshot.cc +++ b/examples/encode_oneshot.cc @@ -183,13 +183,17 @@ bool EncodeJxlOneshot(const std::vector<float>& pixels, const uint32_t xsize, return false; } + JxlEncoderFrameSettings* frame_settings = + JxlEncoderFrameSettingsCreate(enc.get(), nullptr); + if (JXL_ENC_SUCCESS != - JxlEncoderAddImageFrame(JxlEncoderOptionsCreate(enc.get(), nullptr), - &pixel_format, (void*)pixels.data(), + JxlEncoderAddImageFrame(frame_settings, &pixel_format, + (void*)pixels.data(), sizeof(float) * pixels.size())) { fprintf(stderr, "JxlEncoderAddImageFrame failed\n"); return false; } + JxlEncoderCloseInput(enc.get()); compressed->resize(64); uint8_t* next_out = compressed->data(); diff --git a/examples/examples.cmake b/examples/examples.cmake index 726727c..fd15957 100644 --- a/examples/examples.cmake +++ b/examples/examples.cmake @@ -5,15 +5,7 @@ add_executable(decode_oneshot ${CMAKE_CURRENT_LIST_DIR}/decode_oneshot.cc) target_link_libraries(decode_oneshot jxl_dec jxl_threads) +add_executable(decode_progressive ${CMAKE_CURRENT_LIST_DIR}/decode_progressive.cc) +target_link_libraries(decode_progressive jxl_dec jxl_threads) add_executable(encode_oneshot ${CMAKE_CURRENT_LIST_DIR}/encode_oneshot.cc) target_link_libraries(encode_oneshot jxl jxl_threads) - -add_executable(jxlinfo ${CMAKE_CURRENT_LIST_DIR}/jxlinfo.c) -target_link_libraries(jxlinfo jxl) - -if(NOT ${SANITIZER} STREQUAL "none") - # Linking a C test binary with the C++ JPEG XL implementation when using - # address sanitizer is not well supported by clang 9, so force using clang++ - # for linking this test if a sanitizer is used. - set_target_properties(jxlinfo PROPERTIES LINKER_LANGUAGE CXX) -endif() # SANITIZER != "none" diff --git a/examples/jxlinfo.c b/examples/jxlinfo.c deleted file mode 100644 index 5827974..0000000 --- a/examples/jxlinfo.c +++ /dev/null @@ -1,317 +0,0 @@ -// Copyright (c) the JPEG XL Project Authors. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// This example prints information from the main codestream header. - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "jxl/decode.h" - -int PrintBasicInfo(FILE* file) { - uint8_t* data = NULL; - size_t data_size = 0; - // In how large chunks to read from the file and try decoding the basic info. - const size_t chunk_size = 64; - - JxlDecoder* dec = JxlDecoderCreate(NULL); - if (!dec) { - fprintf(stderr, "JxlDecoderCreate failed\n"); - return 0; - } - - JxlDecoderSetKeepOrientation(dec, 1); - - if (JXL_DEC_SUCCESS != - JxlDecoderSubscribeEvents( - dec, JXL_DEC_BASIC_INFO | JXL_DEC_COLOR_ENCODING | JXL_DEC_FRAME)) { - fprintf(stderr, "JxlDecoderSubscribeEvents failed\n"); - JxlDecoderDestroy(dec); - return 0; - } - - JxlBasicInfo info; - int seen_basic_info = 0; - JxlFrameHeader frame_header; - - for (;;) { - // The first time, this will output JXL_DEC_NEED_MORE_INPUT because no - // input is set yet, this is ok since the input is set when handling this - // event. - JxlDecoderStatus status = JxlDecoderProcessInput(dec); - - if (status == JXL_DEC_ERROR) { - fprintf(stderr, "Decoder error\n"); - break; - } else if (status == JXL_DEC_NEED_MORE_INPUT) { - // The first time there is nothing to release and it returns 0, but that - // is ok. - size_t remaining = JxlDecoderReleaseInput(dec); - // move any remaining bytes to the front if necessary - if (remaining != 0) { - memmove(data, data + data_size - remaining, remaining); - } - // resize the buffer to append one more chunk of data - // TODO(lode): avoid unnecessary reallocations - data = (uint8_t*)realloc(data, remaining + chunk_size); - // append bytes read from the file behind the remaining bytes - size_t read_size = fread(data + remaining, 1, chunk_size, file); - if (read_size == 0 && feof(file)) { - fprintf(stderr, "Unexpected EOF\n"); - break; - } - data_size = remaining + read_size; - JxlDecoderSetInput(dec, data, data_size); - } else if (status == JXL_DEC_SUCCESS) { - // Finished all processing. - break; - } else if (status == JXL_DEC_BASIC_INFO) { - if (JXL_DEC_SUCCESS != JxlDecoderGetBasicInfo(dec, &info)) { - fprintf(stderr, "JxlDecoderGetBasicInfo failed\n"); - break; - } - - seen_basic_info = 1; - - printf("dimensions: %ux%u\n", info.xsize, info.ysize); - printf("have_container: %d\n", info.have_container); - printf("uses_original_profile: %d\n", info.uses_original_profile); - printf("bits_per_sample: %d\n", info.bits_per_sample); - if (info.exponent_bits_per_sample) - printf("float, with exponent_bits_per_sample: %d\n", - info.exponent_bits_per_sample); - if (info.intensity_target != 255.f || info.min_nits != 0.f || - info.relative_to_max_display != 0 || - info.relative_to_max_display != 0.f) { - printf("intensity_target: %f\n", info.intensity_target); - printf("min_nits: %f\n", info.min_nits); - printf("relative_to_max_display: %d\n", info.relative_to_max_display); - printf("linear_below: %f\n", info.linear_below); - } - printf("have_preview: %d\n", info.have_preview); - if (info.have_preview) { - printf("preview xsize: %u\n", info.preview.xsize); - printf("preview ysize: %u\n", info.preview.ysize); - } - printf("have_animation: %d\n", info.have_animation); - if (info.have_animation) { - printf("ticks per second (numerator / denominator): %u / %u\n", - info.animation.tps_numerator, info.animation.tps_denominator); - printf("num_loops: %u\n", info.animation.num_loops); - printf("have_timecodes: %d\n", info.animation.have_timecodes); - } - const char* const orientation_string[8] = { - "Normal", "Flipped horizontally", - "Upside down", "Flipped vertically", - "Transposed", "90 degrees clockwise", - "Anti-Transposed", "90 degrees counter-clockwise"}; - if (info.orientation > 0 && info.orientation < 9) { - printf("orientation: %d (%s)\n", info.orientation, - orientation_string[info.orientation - 1]); - } else { - fprintf(stderr, "Invalid orientation\n"); - } - printf("num_extra_channels: %d\n", info.num_extra_channels); - - const char* const ec_type_names[7] = {"Alpha", "Depth", - "Spot color", "Selection mask", - "K (of CMYK)", "CFA (Bayer data)", - "Thermal"}; - for (uint32_t i = 0; i < info.num_extra_channels; i++) { - JxlExtraChannelInfo extra; - if (JXL_DEC_SUCCESS != JxlDecoderGetExtraChannelInfo(dec, i, &extra)) { - fprintf(stderr, "JxlDecoderGetExtraChannelInfo failed\n"); - break; - } - printf("extra channel %u:\n", i); - printf(" type: %s\n", - (extra.type < 7 ? ec_type_names[extra.type] - : (extra.type == JXL_CHANNEL_OPTIONAL - ? "Unknown but can be ignored" - : "Unknown, please update your libjxl"))); - printf(" bits_per_sample: %u\n", extra.bits_per_sample); - if (extra.exponent_bits_per_sample > 0) { - printf(" float, with exponent_bits_per_sample: %u\n", - extra.exponent_bits_per_sample); - } - if (extra.dim_shift > 0) { - printf(" dim_shift: %u (upsampled %ux)\n", extra.dim_shift, - 1 << extra.dim_shift); - } - if (extra.name_length) { - char* name = malloc(extra.name_length + 1); - if (JXL_DEC_SUCCESS != JxlDecoderGetExtraChannelName( - dec, i, name, extra.name_length + 1)) { - fprintf(stderr, "JxlDecoderGetExtraChannelName failed\n"); - free(name); - break; - } - free(name); - printf(" name: %s\n", name); - } - if (extra.type == JXL_CHANNEL_ALPHA) - printf(" alpha_premultiplied: %d (%s)\n", extra.alpha_premultiplied, - extra.alpha_premultiplied ? "Premultiplied" - : "Non-premultiplied"); - if (extra.type == JXL_CHANNEL_SPOT_COLOR) { - printf(" spot_color: (%f, %f, %f) with opacity %f\n", - extra.spot_color[0], extra.spot_color[1], extra.spot_color[2], - extra.spot_color[3]); - } - if (extra.type == JXL_CHANNEL_CFA) - printf(" cfa_channel: %u\n", extra.cfa_channel); - } - } else if (status == JXL_DEC_COLOR_ENCODING) { - JxlPixelFormat format = {4, JXL_TYPE_FLOAT, JXL_LITTLE_ENDIAN, 0}; - printf("color profile:\n"); - - JxlColorEncoding color_encoding; - if (JXL_DEC_SUCCESS == - JxlDecoderGetColorAsEncodedProfile(dec, &format, - JXL_COLOR_PROFILE_TARGET_ORIGINAL, - &color_encoding)) { - printf(" format: JPEG XL encoded color profile\n"); - const char* const cs_string[4] = {"RGB color", "Grayscale", "XYB", - "Unknown"}; - const char* const wp_string[12] = {"", "D65", "Custom", "", "", "", - "", "", "", "", "E", "P3"}; - const char* const pr_string[12] = { - "", "sRGB", "Custom", "", "", "", "", "", "", "Rec.2100", "", "P3"}; - const char* const tf_string[19] = { - "", "709", "Unknown", "", "", "", "", "", "Linear", "", - "", "", "", "sRGB", "", "", "PQ", "DCI", "HLG"}; - const char* const ri_string[4] = {"Perceptual", "Relative", - "Saturation", "Absolute"}; - printf(" color_space: %d (%s)\n", color_encoding.color_space, - cs_string[color_encoding.color_space]); - printf(" white_point: %d (%s)\n", color_encoding.white_point, - wp_string[color_encoding.white_point]); - if (color_encoding.white_point == JXL_WHITE_POINT_CUSTOM) { - printf(" white_point XY: %f %f\n", color_encoding.white_point_xy[0], - color_encoding.white_point_xy[1]); - } - if (color_encoding.color_space == JXL_COLOR_SPACE_RGB || - color_encoding.color_space == JXL_COLOR_SPACE_UNKNOWN) { - printf(" primaries: %d (%s)\n", color_encoding.primaries, - pr_string[color_encoding.primaries]); - if (color_encoding.primaries == JXL_PRIMARIES_CUSTOM) { - printf(" red primaries XY: %f %f\n", - color_encoding.primaries_red_xy[0], - color_encoding.primaries_red_xy[1]); - printf(" green primaries XY: %f %f\n", - color_encoding.primaries_green_xy[0], - color_encoding.primaries_green_xy[1]); - printf(" blue primaries XY: %f %f\n", - color_encoding.primaries_blue_xy[0], - color_encoding.primaries_blue_xy[1]); - } - } - if (color_encoding.transfer_function == JXL_TRANSFER_FUNCTION_GAMMA) { - printf(" transfer_function: gamma: %f\n", color_encoding.gamma); - } else { - printf(" transfer_function: %d (%s)\n", - color_encoding.transfer_function, - tf_string[color_encoding.transfer_function]); - } - printf(" rendering_intent: %d (%s)\n", color_encoding.rendering_intent, - ri_string[color_encoding.rendering_intent]); - - } else { - // The profile is not in JPEG XL encoded form, get as ICC profile - // instead. - printf(" format: ICC profile\n"); - size_t profile_size; - if (JXL_DEC_SUCCESS != - JxlDecoderGetICCProfileSize(dec, &format, - JXL_COLOR_PROFILE_TARGET_ORIGINAL, - &profile_size)) { - fprintf(stderr, "JxlDecoderGetICCProfileSize failed\n"); - continue; - } - printf(" ICC profile size: %zu\n", profile_size); - if (profile_size < 132) { - fprintf(stderr, "ICC profile too small\n"); - continue; - } - uint8_t* profile = (uint8_t*)malloc(profile_size); - if (JXL_DEC_SUCCESS != - JxlDecoderGetColorAsICCProfile(dec, &format, - JXL_COLOR_PROFILE_TARGET_ORIGINAL, - profile, profile_size)) { - fprintf(stderr, "JxlDecoderGetColorAsICCProfile failed\n"); - free(profile); - continue; - } - printf(" CMM type: \"%.4s\"\n", profile + 4); - printf(" color space: \"%.4s\"\n", profile + 16); - printf(" rendering intent: %d\n", (int)profile[67]); - free(profile); - } - - } else if (status == JXL_DEC_FRAME) { - if (JXL_DEC_SUCCESS != JxlDecoderGetFrameHeader(dec, &frame_header)) { - fprintf(stderr, "JxlDecoderGetFrameHeader failed\n"); - break; - } - printf("frame:\n"); - if (frame_header.name_length) { - char* name = malloc(frame_header.name_length + 1); - if (JXL_DEC_SUCCESS != - JxlDecoderGetFrameName(dec, name, frame_header.name_length + 1)) { - fprintf(stderr, "JxlDecoderGetFrameName failed\n"); - free(name); - break; - } - free(name); - printf(" name: %s\n", name); - } - float ms = frame_header.duration * 1000.f * - info.animation.tps_denominator / info.animation.tps_numerator; - if (info.have_animation) { - printf(" Duration: %u ticks (%f ms)\n", frame_header.duration, ms); - if (info.animation.have_timecodes) { - printf(" Time code: %X\n", frame_header.timecode); - } - } - - // This is the last expected event, no need to read the rest of the file. - } else { - fprintf(stderr, "Unexpected decoder status\n"); - break; - } - } - - JxlDecoderDestroy(dec); - free(data); - - return seen_basic_info; -} - -int main(int argc, char* argv[]) { - if (argc != 2) { - fprintf(stderr, - "Usage: %s <jxl>\n" - "Where:\n" - " jxl = input JPEG XL image filename\n", - argv[0]); - return 1; - } - - const char* jxl_filename = argv[1]; - - FILE* file = fopen(jxl_filename, "rb"); - if (!file) { - fprintf(stderr, "Failed to read file %s\n", jxl_filename); - return 1; - } - - if (!PrintBasicInfo(file)) { - fprintf(stderr, "Couldn't print basic info\n"); - return 1; - } - - return 0; -} |