summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorjiyong.min <jiyong.min@samsung.com>2022-12-07 10:34:18 +0900
committerjiyong.min <jiyong.min@samsung.com>2022-12-07 13:37:38 +0900
commit8f303a6e2069fd39246decb4fe7aecb221cb134a (patch)
tree64704d2db44568e6a99cd4b8f159e9e94bbaefbc /examples
parentb2051fff838fd13eda203439f58679cbefea065e (diff)
parent7fa2aaed0a5c855460b77fb1fedcc01591ff6470 (diff)
downloadlibjxl-accepted/tizen/unified/20221216.024040.tar.gz
libjxl-accepted/tizen/unified/20221216.024040.tar.bz2
libjxl-accepted/tizen/unified/20221216.024040.zip
Change-Id: Ib06199c1a967d1c08974f2e95f085ade02c5fb72
Diffstat (limited to 'examples')
-rw-r--r--examples/CMakeLists.txt6
-rw-r--r--examples/decode_exif_metadata.cc173
-rw-r--r--examples/decode_oneshot.cc7
-rw-r--r--examples/decode_progressive.cc238
-rw-r--r--examples/encode_oneshot.cc8
-rw-r--r--examples/examples.cmake12
-rw-r--r--examples/jxlinfo.c317
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;
-}