mirror of
https://invent.kde.org/frameworks/kimageformats.git
synced 2025-05-28 00:30:23 -04:00
jxl: Disable color conversion for animations
Workaround for issue https://github.com/libjxl/libjxl/issues/3983 libjxl_cms is used for color conversion of lossy static images. Fix loading of lossy grayscale images Fix loading of grayscale images with odd width
This commit is contained in:
parent
374961dab4
commit
6558b3255a
@ -72,6 +72,7 @@ option(KIMAGEFORMATS_JXL "Enable plugin for JPEG XL format" ON)
|
||||
if(KIMAGEFORMATS_JXL)
|
||||
pkg_check_modules(LibJXL IMPORTED_TARGET libjxl>=0.7.0)
|
||||
pkg_check_modules(LibJXLThreads IMPORTED_TARGET libjxl_threads>=0.7.0)
|
||||
pkg_check_modules(LibJXLCMS IMPORTED_TARGET libjxl_cms>=0.9.0)
|
||||
endif()
|
||||
add_feature_info(LibJXL LibJXL_FOUND "required for the QImage plugin for JPEG XL images")
|
||||
|
||||
|
BIN
autotests/read/jxl/chicken16.jxl
Normal file
BIN
autotests/read/jxl/chicken16.jxl
Normal file
Binary file not shown.
BIN
autotests/read/jxl/chicken16.png
Normal file
BIN
autotests/read/jxl/chicken16.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 115 KiB |
BIN
autotests/read/jxl/chicken8.jxl
Normal file
BIN
autotests/read/jxl/chicken8.jxl
Normal file
Binary file not shown.
BIN
autotests/read/jxl/chicken8.png
Normal file
BIN
autotests/read/jxl/chicken8.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
@ -71,6 +71,13 @@ endif()
|
||||
if (LibJXL_FOUND AND LibJXLThreads_FOUND)
|
||||
kimageformats_add_plugin(kimg_jxl SOURCES jxl.cpp)
|
||||
target_link_libraries(kimg_jxl PRIVATE PkgConfig::LibJXL PkgConfig::LibJXLThreads)
|
||||
if(LibJXL_VERSION VERSION_GREATER_EQUAL "0.9.0")
|
||||
if(LibJXLCMS_FOUND)
|
||||
target_link_libraries(kimg_jxl PRIVATE PkgConfig::LibJXLCMS)
|
||||
else()
|
||||
message(SEND_ERROR "libjxl_cms was not found!")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
##################################
|
||||
|
@ -14,6 +14,11 @@
|
||||
|
||||
#include <jxl/encode.h>
|
||||
#include <jxl/thread_parallel_runner.h>
|
||||
|
||||
#if JPEGXL_NUMERIC_VERSION >= JPEGXL_COMPUTE_NUMERIC_VERSION(0, 9, 0)
|
||||
#include <jxl/cms.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
// Avoid rotation on buggy Qts (see also https://bugreports.qt.io/browse/QTBUG-126575)
|
||||
@ -247,9 +252,20 @@ bool QJpegXLHandler::countALLFrames()
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_gray = m_basicinfo.num_color_channels == 1 && m_basicinfo.num_extra_channels == 0;
|
||||
bool is_gray = m_basicinfo.num_color_channels == 1 && m_basicinfo.alpha_bits == 0;
|
||||
JxlColorEncoding color_encoding;
|
||||
if (m_basicinfo.uses_original_profile == JXL_FALSE) {
|
||||
if (m_basicinfo.uses_original_profile == JXL_FALSE && m_basicinfo.have_animation == JXL_FALSE) {
|
||||
#if JPEGXL_NUMERIC_VERSION >= JPEGXL_COMPUTE_NUMERIC_VERSION(0, 9, 0)
|
||||
const JxlCmsInterface *jxlcms = JxlGetDefaultCms();
|
||||
if (jxlcms) {
|
||||
status = JxlDecoderSetCms(m_decoder, *jxlcms);
|
||||
if (status != JXL_DEC_SUCCESS) {
|
||||
qWarning("JxlDecoderSetCms ERROR");
|
||||
}
|
||||
} else {
|
||||
qWarning("No JPEG XL CMS Interface");
|
||||
}
|
||||
#endif
|
||||
JxlColorEncodingSetToSRGB(&color_encoding, is_gray ? JXL_TRUE : JXL_FALSE);
|
||||
JxlDecoderSetPreferredColorProfile(m_decoder, &color_encoding);
|
||||
}
|
||||
@ -260,7 +276,7 @@ bool QJpegXLHandler::countALLFrames()
|
||||
}
|
||||
|
||||
m_input_pixel_format.endianness = JXL_NATIVE_ENDIAN;
|
||||
m_input_pixel_format.align = 0;
|
||||
m_input_pixel_format.align = 4;
|
||||
m_input_pixel_format.num_channels = is_gray ? 1 : 4;
|
||||
|
||||
if (m_basicinfo.bits_per_sample > 8) { // high bit depth
|
||||
@ -269,13 +285,11 @@ bool QJpegXLHandler::countALLFrames()
|
||||
#else
|
||||
bool is_fp = m_basicinfo.exponent_bits_per_sample > 0 && m_basicinfo.num_color_channels == 3;
|
||||
#endif
|
||||
m_input_pixel_format.data_type = is_fp ? JXL_TYPE_FLOAT16 : JXL_TYPE_UINT16;
|
||||
m_buffer_size = (size_t)m_basicinfo.xsize * (size_t)m_basicinfo.ysize * m_input_pixel_format.num_channels * 2;
|
||||
|
||||
if (is_gray) {
|
||||
m_input_pixel_format.data_type = JXL_TYPE_UINT16;
|
||||
m_input_image_format = m_target_image_format = QImage::Format_Grayscale16;
|
||||
m_buffer_size = (size_t)m_basicinfo.xsize * (size_t)m_basicinfo.ysize * m_input_pixel_format.num_channels * 2;
|
||||
m_buffer_size = ((size_t)m_basicinfo.ysize - 1) * (((((size_t)m_basicinfo.xsize) * 2 + 3) >> 2) << 2) + (size_t)m_basicinfo.xsize * 2;
|
||||
} else if (m_basicinfo.bits_per_sample > 16 && is_fp) {
|
||||
m_input_pixel_format.data_type = JXL_TYPE_FLOAT;
|
||||
m_input_image_format = QImage::Format_RGBA32FPx4;
|
||||
@ -285,6 +299,7 @@ bool QJpegXLHandler::countALLFrames()
|
||||
else
|
||||
m_target_image_format = QImage::Format_RGBX32FPx4;
|
||||
} else {
|
||||
m_input_pixel_format.data_type = is_fp ? JXL_TYPE_FLOAT16 : JXL_TYPE_UINT16;
|
||||
m_buffer_size = (size_t)m_basicinfo.xsize * (size_t)m_basicinfo.ysize * m_input_pixel_format.num_channels * 2;
|
||||
m_input_image_format = is_fp ? QImage::Format_RGBA16FPx4 : QImage::Format_RGBA64;
|
||||
if (loadalpha)
|
||||
@ -294,12 +309,13 @@ bool QJpegXLHandler::countALLFrames()
|
||||
}
|
||||
} else { // 8bit depth
|
||||
m_input_pixel_format.data_type = JXL_TYPE_UINT8;
|
||||
m_buffer_size = (size_t)m_basicinfo.xsize * (size_t)m_basicinfo.ysize * m_input_pixel_format.num_channels;
|
||||
|
||||
if (is_gray) {
|
||||
m_input_image_format = m_target_image_format = QImage::Format_Grayscale8;
|
||||
m_buffer_size = ((size_t)m_basicinfo.ysize - 1) * (((((size_t)m_basicinfo.xsize) + 3) >> 2) << 2) + (size_t)m_basicinfo.xsize;
|
||||
} else {
|
||||
m_input_image_format = QImage::Format_RGBA8888;
|
||||
m_buffer_size = (size_t)m_basicinfo.xsize * (size_t)m_basicinfo.ysize * m_input_pixel_format.num_channels;
|
||||
if (loadalpha) {
|
||||
m_target_image_format = QImage::Format_ARGB32;
|
||||
} else {
|
||||
@ -631,7 +647,8 @@ bool QJpegXLHandler::write(const QImage &image)
|
||||
|
||||
QByteArray iccprofile;
|
||||
QColorSpace tmpcs = image.colorSpace();
|
||||
if (!tmpcs.isValid() || tmpcs.primaries() != QColorSpace::Primaries::SRgb || tmpcs.transferFunction() != QColorSpace::TransferFunction::SRgb || m_quality == 100) {
|
||||
if (!tmpcs.isValid() || tmpcs.primaries() != QColorSpace::Primaries::SRgb || tmpcs.transferFunction() != QColorSpace::TransferFunction::SRgb
|
||||
|| m_quality == 100) {
|
||||
// no profile or Qt-unsupported ICC profile
|
||||
iccprofile = tmpcs.iccProfile();
|
||||
// note: lossless encoding requires uses_original_profile = JXL_TRUE
|
||||
@ -766,8 +783,7 @@ bool QJpegXLHandler::write(const QImage &image)
|
||||
auto cs = image.colorSpace();
|
||||
if (cs.isValid() && cs.colorModel() == QColorSpace::ColorModel::Cmyk && image.format() == QImage::Format_CMYK8888) {
|
||||
tmpimage = image.convertedToColorSpace(QColorSpace(QColorSpace::SRgb), tmpformat);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
tmpimage = image.convertToFormat(tmpformat);
|
||||
}
|
||||
#else
|
||||
@ -943,7 +959,6 @@ QVariant QJpegXLHandler::option(ImageOption option) const
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
|
||||
switch (option) {
|
||||
case Size:
|
||||
return QSize(m_basicinfo.xsize, m_basicinfo.ysize);
|
||||
@ -1154,13 +1169,7 @@ bool QJpegXLHandler::rewind()
|
||||
|
||||
JxlDecoderCloseInput(m_decoder);
|
||||
|
||||
if (m_basicinfo.uses_original_profile) {
|
||||
if (JxlDecoderSubscribeEvents(m_decoder, JXL_DEC_FULL_IMAGE) != JXL_DEC_SUCCESS) {
|
||||
qWarning("ERROR: JxlDecoderSubscribeEvents failed");
|
||||
m_parseState = ParseJpegXLError;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (m_basicinfo.uses_original_profile == JXL_FALSE && m_basicinfo.have_animation == JXL_FALSE) {
|
||||
if (JxlDecoderSubscribeEvents(m_decoder, JXL_DEC_COLOR_ENCODING | JXL_DEC_FULL_IMAGE) != JXL_DEC_SUCCESS) {
|
||||
qWarning("ERROR: JxlDecoderSubscribeEvents failed");
|
||||
m_parseState = ParseJpegXLError;
|
||||
@ -1174,9 +1183,28 @@ bool QJpegXLHandler::rewind()
|
||||
return false;
|
||||
}
|
||||
|
||||
#if JPEGXL_NUMERIC_VERSION >= JPEGXL_COMPUTE_NUMERIC_VERSION(0, 9, 0)
|
||||
const JxlCmsInterface *jxlcms = JxlGetDefaultCms();
|
||||
if (jxlcms) {
|
||||
status = JxlDecoderSetCms(m_decoder, *jxlcms);
|
||||
if (status != JXL_DEC_SUCCESS) {
|
||||
qWarning("JxlDecoderSetCms ERROR");
|
||||
}
|
||||
} else {
|
||||
qWarning("No JPEG XL CMS Interface");
|
||||
}
|
||||
#endif
|
||||
|
||||
bool is_gray = m_basicinfo.num_color_channels == 1 && m_basicinfo.alpha_bits == 0;
|
||||
JxlColorEncoding color_encoding;
|
||||
JxlColorEncodingSetToSRGB(&color_encoding, JXL_FALSE);
|
||||
JxlColorEncodingSetToSRGB(&color_encoding, is_gray ? JXL_TRUE : JXL_FALSE);
|
||||
JxlDecoderSetPreferredColorProfile(m_decoder, &color_encoding);
|
||||
} else {
|
||||
if (JxlDecoderSubscribeEvents(m_decoder, JXL_DEC_FULL_IMAGE) != JXL_DEC_SUCCESS) {
|
||||
qWarning("ERROR: JxlDecoderSubscribeEvents failed");
|
||||
m_parseState = ParseJpegXLError;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
Loading…
Reference in New Issue
Block a user