Add ability to import JXL images
This commit is contained in:
parent
11240bc97d
commit
dfc82c403c
@ -552,6 +552,11 @@ if(WITH_SYSTEM_KLT)
|
||||
find_package(KLT REQUIRED)
|
||||
endif()
|
||||
|
||||
pkg_check_modules(JXL IMPORTED_TARGET libjxl libjxl_threads)
|
||||
if(JXL)
|
||||
set(JXL_LIBRARIES jxl jxl_threads)
|
||||
endif()
|
||||
|
||||
# Check for libcanberra-gtk3 (sound events on Linux):
|
||||
if(UNIX AND (NOT APPLE))
|
||||
option(USE_LIBCANBERRA "Build with libcanberra" ON)
|
||||
|
@ -12,8 +12,8 @@ MultiUser=true
|
||||
|
||||
[File Browser]
|
||||
# Image filename extensions to be looked for, and their corresponding search state (0/1 -> skip/include)
|
||||
ParseExtensions=3fr;arw;arq;cr2;cr3;crf;crw;dcr;dng;fff;iiq;jpg;jpeg;kdc;mef;mos;mrw;nef;nrw;orf;ori;pef;png;raf;raw;rw2;rwl;rwz;sr2;srf;srw;tif;tiff;x3f;
|
||||
ParseExtensionsEnabled=1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;0;1;1;1;1;1;1;1;1;1;1;1;
|
||||
ParseExtensions=3fr;arw;arq;cr2;cr3;crf;crw;dcr;dng;fff;iiq;jpg;jpeg;kdc;mef;mos;mrw;nef;nrw;orf;ori;pef;png;raf;raw;rw2;rwl;rwz;sr2;srf;srw;tif;tiff;x3f;jxl;
|
||||
ParseExtensionsEnabled=1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;
|
||||
|
||||
[Output]
|
||||
PathTemplate=%p1/converted/%f
|
||||
|
@ -13,8 +13,8 @@ UseSystemTheme=false
|
||||
|
||||
[File Browser]
|
||||
# Image filename extensions to be looked for, and their corresponding search state (0/1 -> skip/include)
|
||||
ParseExtensions=3fr;arw;arq;cr2;cr3;crf;crw;dcr;dng;fff;iiq;jpg;jpeg;kdc;mef;mos;mrw;nef;nrw;orf;ori;pef;png;raf;raw;rw2;rwl;rwz;sr2;srf;srw;tif;tiff;x3f;
|
||||
ParseExtensionsEnabled=1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;0;1;1;1;1;1;1;1;1;1;1;1;
|
||||
ParseExtensions=3fr;arw;arq;cr2;cr3;crf;crw;dcr;dng;fff;iiq;jpg;jpeg;kdc;mef;mos;mrw;nef;nrw;orf;ori;pef;png;raf;raw;rw2;rwl;rwz;sr2;srf;srw;tif;tiff;x3f;jxl;
|
||||
ParseExtensionsEnabled=1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;
|
||||
|
||||
[Output]
|
||||
PathTemplate=%p1/converted/%f
|
||||
|
@ -14,8 +14,8 @@ UseSystemTheme=false
|
||||
|
||||
[File Browser]
|
||||
# Image filename extensions to be looked for, and their corresponding search state (0/1 -> skip/include)
|
||||
ParseExtensions=3fr;arw;arq;cr2;cr3;crf;crw;dcr;dng;fff;iiq;jpg;jpeg;kdc;mef;mos;mrw;nef;nrw;orf;ori;pef;png;raf;raw;rw2;rwl;rwz;sr2;srf;srw;tif;tiff;x3f;
|
||||
ParseExtensionsEnabled=1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;0;1;1;1;1;1;1;1;1;1;1;1;
|
||||
ParseExtensions=3fr;arw;arq;cr2;cr3;crf;crw;dcr;dng;fff;iiq;jpg;jpeg;kdc;mef;mos;mrw;nef;nrw;orf;ori;pef;png;raf;raw;rw2;rwl;rwz;sr2;srf;srw;tif;tiff;x3f;jxl;
|
||||
ParseExtensionsEnabled=1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;
|
||||
|
||||
[Output]
|
||||
PathTemplate=%p1/converted/%f
|
||||
|
@ -246,6 +246,7 @@ target_link_libraries(rtengine
|
||||
${RSVG_LIBRARIES}
|
||||
${KLT_LIBRARIES}
|
||||
${EXIV2_LIBRARIES}
|
||||
${JXL_LIBRARIES}
|
||||
)
|
||||
|
||||
if(OpenMP_FOUND)
|
||||
|
@ -24,13 +24,20 @@
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <glib/gstdio.h>
|
||||
#include <png.h>
|
||||
#include <tiff.h>
|
||||
#include <tiffio.h>
|
||||
|
||||
#ifdef JXL
|
||||
#include <fstream>
|
||||
#include "jxl/decode.h"
|
||||
#include "jxl/decode_cxx.h"
|
||||
#include "jxl/resizable_parallel_runner.h"
|
||||
#include "jxl/resizable_parallel_runner_cxx.h"
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
@ -822,6 +829,161 @@ int ImageIO::loadTIFF (const Glib::ustring &fname)
|
||||
return IMIO_SUCCESS;
|
||||
}
|
||||
|
||||
#ifdef JXL
|
||||
#define _PROFILE_ JXL_COLOR_PROFILE_TARGET_ORIGINAL
|
||||
|
||||
// adapted from libjxl
|
||||
int ImageIO::loadJxl(const Glib::ustring &fname)
|
||||
{
|
||||
if (pl) {
|
||||
pl->setProgressStr("PROGRESSBAR_LOADJXL");
|
||||
pl->setProgress(0.0);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> icc_profile;
|
||||
|
||||
gpointer buffer = nullptr;
|
||||
size_t buffer_size = 0;
|
||||
|
||||
JxlBasicInfo info = {};
|
||||
JxlPixelFormat format = {};
|
||||
|
||||
format.num_channels = 3;
|
||||
format.data_type = JXL_TYPE_FLOAT;
|
||||
format.endianness = JXL_NATIVE_ENDIAN;
|
||||
format.align = 0;
|
||||
|
||||
// get file contents
|
||||
std::ifstream instream(fname.c_str(), std::ios::in | std::ios::binary);
|
||||
std::vector<uint8_t> compressed(
|
||||
(std::istreambuf_iterator<char>(instream)),
|
||||
std::istreambuf_iterator<char>());
|
||||
instream.close();
|
||||
|
||||
|
||||
// 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)) {
|
||||
g_printerr("Error: JxlDecoderSubscribeEvents failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (JXL_DEC_SUCCESS !=
|
||||
JxlDecoderSetParallelRunner(dec.get(), JxlResizableParallelRunner,
|
||||
runner.get())) {
|
||||
g_printerr("Error: JxlDecoderSetParallelRunner failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// grand decode loop...
|
||||
JxlDecoderSetInput(dec.get(), compressed.data(), compressed.size());
|
||||
|
||||
while (true) {
|
||||
JxlDecoderStatus status = JxlDecoderProcessInput(dec.get());
|
||||
|
||||
if (status == JXL_DEC_BASIC_INFO) {
|
||||
if (JXL_DEC_SUCCESS !=
|
||||
JxlDecoderGetBasicInfo(dec.get(), &info)) {
|
||||
g_printerr("Error: JxlDecoderGetBasicInfo failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
JxlResizableParallelRunnerSetThreads(
|
||||
runner.get(), JxlResizableParallelRunnerSuggestThreads(
|
||||
info.xsize, info.ysize));
|
||||
} else if (status == JXL_DEC_COLOR_ENCODING) {
|
||||
// check for ICC profile
|
||||
deleteLoadedProfileData();
|
||||
embProfile = nullptr;
|
||||
size_t icc_size = 0;
|
||||
|
||||
if (JXL_DEC_SUCCESS !=
|
||||
JxlDecoderGetICCProfileSize(dec.get(), &format,
|
||||
_PROFILE_, &icc_size)) {
|
||||
g_printerr("Warning: JxlDecoderGetICCProfileSize failed\n");
|
||||
}
|
||||
|
||||
if (icc_size > 0) {
|
||||
icc_profile.resize(icc_size);
|
||||
if (JXL_DEC_SUCCESS !=
|
||||
JxlDecoderGetColorAsICCProfile(
|
||||
dec.get(), &format, _PROFILE_,
|
||||
icc_profile.data(), icc_profile.size())) {
|
||||
g_printerr(
|
||||
"Warning: JxlDecoderGetColorAsICCProfile failed\n");
|
||||
} else {
|
||||
embProfile = cmsOpenProfileFromMem(icc_profile.data(),
|
||||
icc_profile.size());
|
||||
}
|
||||
} else {
|
||||
g_printerr("Warning: Empty ICC data.\n");
|
||||
}
|
||||
} else if (status == JXL_DEC_NEED_IMAGE_OUT_BUFFER) {
|
||||
format.data_type = JXL_TYPE_FLOAT;
|
||||
if (JXL_DEC_SUCCESS != JxlDecoderImageOutBufferSize(
|
||||
dec.get(), &format, &buffer_size)) {
|
||||
g_printerr("Error: JxlDecoderImageOutBufferSize failed\n");
|
||||
return false;
|
||||
}
|
||||
buffer = g_malloc(buffer_size);
|
||||
if (JXL_DEC_SUCCESS != JxlDecoderSetImageOutBuffer(dec.get(), &format,
|
||||
buffer, buffer_size)) {
|
||||
g_printerr("Error: JxlDecoderSetImageOutBuffer failed\n");
|
||||
g_free(buffer);
|
||||
return false;
|
||||
}
|
||||
} else if (status == JXL_DEC_FULL_IMAGE ||
|
||||
status == JXL_DEC_FRAME) {
|
||||
// Nothing to do. If the image is an animation, more full frames
|
||||
// may be decoded. This example only keeps the first one.
|
||||
} else if (status == JXL_DEC_SUCCESS) {
|
||||
// All decoding successfully finished.
|
||||
// It's not required to call JxlDecoderReleaseInput(dec.get())
|
||||
// since the decoder will be destroyed.
|
||||
break;
|
||||
} else if (status == JXL_DEC_NEED_MORE_INPUT) {
|
||||
g_printerr("Error: Already provided all input\n");
|
||||
return false;
|
||||
} else if (status == JXL_DEC_ERROR) {
|
||||
g_printerr("Error: Decoder error\n");
|
||||
return false;
|
||||
} else {
|
||||
g_printerr("Error: Unknown decoder status\n");
|
||||
return false;
|
||||
}
|
||||
} // end grand decode loop
|
||||
|
||||
unsigned int width = info.xsize;
|
||||
unsigned int height = info.ysize;
|
||||
|
||||
allocate(width, height);
|
||||
|
||||
int line_length = width * 3 * 4;
|
||||
|
||||
for (size_t row = 0; row < height; ++row) {
|
||||
setScanline (row, ((const unsigned char*)buffer) + (row * line_length), 32);
|
||||
|
||||
if (pl && !(row % 100)) {
|
||||
pl->setProgress ((double)(row) / height);
|
||||
}
|
||||
}
|
||||
|
||||
g_free(buffer);
|
||||
|
||||
if (pl) {
|
||||
pl->setProgressStr ("PROGRESSBAR_READY");
|
||||
pl->setProgress (1.0);
|
||||
}
|
||||
|
||||
return IMIO_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
int ImageIO::loadPPMFromMemory(const char* buffer, int width, int height, bool swap, int bps)
|
||||
{
|
||||
allocate (width, height);
|
||||
@ -1310,6 +1472,10 @@ int ImageIO::load (const Glib::ustring &fname)
|
||||
return loadPNG (fname);
|
||||
} else if (hasJpegExtension(fname)) {
|
||||
return loadJPEG (fname);
|
||||
#ifdef JXL
|
||||
} else if (hasJxlExtension(fname)) {
|
||||
return loadJxl(fname);
|
||||
#endif
|
||||
} else if (hasTiffExtension(fname)) {
|
||||
return loadTIFF (fname);
|
||||
} else {
|
||||
|
@ -90,6 +90,10 @@ public:
|
||||
int load (const Glib::ustring &fname);
|
||||
int save (const Glib::ustring &fname) const;
|
||||
|
||||
#ifdef JXL
|
||||
int loadJxl (const Glib::ustring &fname);
|
||||
#endif
|
||||
|
||||
int loadPNG (const Glib::ustring &fname);
|
||||
int loadJPEG (const Glib::ustring &fname);
|
||||
int loadTIFF (const Glib::ustring &fname);
|
||||
|
@ -90,6 +90,12 @@ void StdImageSource::getSampleFormat (const Glib::ustring &fname, IIOSampleForma
|
||||
if (result == IMIO_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
#ifdef JXL
|
||||
} else if (hasJxlExtension(fname)) {
|
||||
sFormat = IIOSF_FLOAT32;
|
||||
sArrangement = IIOSA_CHUNKY;
|
||||
return;
|
||||
#endif
|
||||
} else if (hasTiffExtension(fname)) {
|
||||
int result = ImageIO::getTIFFSampleFormat (fname, sFormat, sArrangement);
|
||||
|
||||
|
@ -237,6 +237,14 @@ bool hasJpegExtension(const Glib::ustring& filename)
|
||||
return extension == "jpg" || extension == "jpeg";
|
||||
}
|
||||
|
||||
#ifdef JXL
|
||||
bool hasJxlExtension(const Glib::ustring& filename)
|
||||
{
|
||||
const Glib::ustring extension = getFileExtension(filename);
|
||||
return extension == "jxl";
|
||||
}
|
||||
#endif
|
||||
|
||||
bool hasTiffExtension(const Glib::ustring& filename)
|
||||
{
|
||||
const Glib::ustring extension = getFileExtension(filename);
|
||||
|
@ -52,6 +52,11 @@ bool hasTiffExtension(const Glib::ustring& filename);
|
||||
// Return true if file has .png extension (ignoring case)
|
||||
bool hasPngExtension(const Glib::ustring& filename);
|
||||
|
||||
#ifdef JXL
|
||||
// Return true if file has .jxl extension (ignoring case)
|
||||
bool hasJxlExtension(const Glib::ustring& filename);
|
||||
#endif
|
||||
|
||||
void swab(const void* from, void* to, ssize_t n);
|
||||
|
||||
}
|
||||
|
@ -707,7 +707,7 @@ int processLineParams ( int argc, char **argv )
|
||||
isRaw = true;
|
||||
Glib::ustring ext = getExtension (inputFile);
|
||||
|
||||
if (ext.lowercase() == "jpg" || ext.lowercase() == "jpeg" || ext.lowercase() == "tif" || ext.lowercase() == "tiff" || ext.lowercase() == "png") {
|
||||
if (ext.lowercase() == "jpg" || ext.lowercase() == "jpeg" || ext.lowercase() == "tif" || ext.lowercase() == "tiff" || ext.lowercase() == "png" || ext.lowercase() == "jxl") {
|
||||
isRaw = false;
|
||||
}
|
||||
|
||||
|
@ -212,6 +212,12 @@ void Thumbnail::_generateThumbnailImage ()
|
||||
if (tpp) {
|
||||
cfs.format = FT_Jpeg;
|
||||
}
|
||||
} else if (ext == "jxl") {
|
||||
tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, -1, pparams->wb.equal);
|
||||
|
||||
if (tpp) {
|
||||
cfs.format = FT_Png;
|
||||
}
|
||||
} else if (ext == "png") {
|
||||
tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, -1, pparams->wb.equal, pparams->wb.observer);
|
||||
|
||||
@ -255,6 +261,15 @@ void Thumbnail::_generateThumbnailImage ()
|
||||
}
|
||||
}
|
||||
|
||||
if (!tpp) {
|
||||
// try a custom loader
|
||||
tpp = rtengine::Thumbnail::loadFromImage(fname, tw, th, -1, pparams->wb.equal, true);
|
||||
if (tpp) {
|
||||
cfs.format = FT_Custom;
|
||||
infoFromImage(fname);
|
||||
}
|
||||
}
|
||||
|
||||
if (tpp) {
|
||||
tpp->getAutoWBMultipliers(cfs.redAWBMul, cfs.greenAWBMul, cfs.blueAWBMul);
|
||||
_saveThumbnail ();
|
||||
|
Loading…
x
Reference in New Issue
Block a user