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)
|
if(KIMAGEFORMATS_JXL)
|
||||||
pkg_check_modules(LibJXL IMPORTED_TARGET libjxl>=0.7.0)
|
pkg_check_modules(LibJXL IMPORTED_TARGET libjxl>=0.7.0)
|
||||||
pkg_check_modules(LibJXLThreads IMPORTED_TARGET libjxl_threads>=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()
|
endif()
|
||||||
add_feature_info(LibJXL LibJXL_FOUND "required for the QImage plugin for JPEG XL images")
|
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)
|
if (LibJXL_FOUND AND LibJXLThreads_FOUND)
|
||||||
kimageformats_add_plugin(kimg_jxl SOURCES jxl.cpp)
|
kimageformats_add_plugin(kimg_jxl SOURCES jxl.cpp)
|
||||||
target_link_libraries(kimg_jxl PRIVATE PkgConfig::LibJXL PkgConfig::LibJXLThreads)
|
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()
|
endif()
|
||||||
|
|
||||||
##################################
|
##################################
|
||||||
|
@ -14,6 +14,11 @@
|
|||||||
|
|
||||||
#include <jxl/encode.h>
|
#include <jxl/encode.h>
|
||||||
#include <jxl/thread_parallel_runner.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>
|
#include <string.h>
|
||||||
|
|
||||||
// Avoid rotation on buggy Qts (see also https://bugreports.qt.io/browse/QTBUG-126575)
|
// Avoid rotation on buggy Qts (see also https://bugreports.qt.io/browse/QTBUG-126575)
|
||||||
@ -247,9 +252,20 @@ bool QJpegXLHandler::countALLFrames()
|
|||||||
return false;
|
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;
|
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);
|
JxlColorEncodingSetToSRGB(&color_encoding, is_gray ? JXL_TRUE : JXL_FALSE);
|
||||||
JxlDecoderSetPreferredColorProfile(m_decoder, &color_encoding);
|
JxlDecoderSetPreferredColorProfile(m_decoder, &color_encoding);
|
||||||
}
|
}
|
||||||
@ -260,7 +276,7 @@ bool QJpegXLHandler::countALLFrames()
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_input_pixel_format.endianness = JXL_NATIVE_ENDIAN;
|
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;
|
m_input_pixel_format.num_channels = is_gray ? 1 : 4;
|
||||||
|
|
||||||
if (m_basicinfo.bits_per_sample > 8) { // high bit depth
|
if (m_basicinfo.bits_per_sample > 8) { // high bit depth
|
||||||
@ -269,13 +285,11 @@ bool QJpegXLHandler::countALLFrames()
|
|||||||
#else
|
#else
|
||||||
bool is_fp = m_basicinfo.exponent_bits_per_sample > 0 && m_basicinfo.num_color_channels == 3;
|
bool is_fp = m_basicinfo.exponent_bits_per_sample > 0 && m_basicinfo.num_color_channels == 3;
|
||||||
#endif
|
#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) {
|
if (is_gray) {
|
||||||
m_input_pixel_format.data_type = JXL_TYPE_UINT16;
|
m_input_pixel_format.data_type = JXL_TYPE_UINT16;
|
||||||
m_input_image_format = m_target_image_format = QImage::Format_Grayscale16;
|
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) {
|
} else if (m_basicinfo.bits_per_sample > 16 && is_fp) {
|
||||||
m_input_pixel_format.data_type = JXL_TYPE_FLOAT;
|
m_input_pixel_format.data_type = JXL_TYPE_FLOAT;
|
||||||
m_input_image_format = QImage::Format_RGBA32FPx4;
|
m_input_image_format = QImage::Format_RGBA32FPx4;
|
||||||
@ -285,6 +299,7 @@ bool QJpegXLHandler::countALLFrames()
|
|||||||
else
|
else
|
||||||
m_target_image_format = QImage::Format_RGBX32FPx4;
|
m_target_image_format = QImage::Format_RGBX32FPx4;
|
||||||
} else {
|
} 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_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;
|
m_input_image_format = is_fp ? QImage::Format_RGBA16FPx4 : QImage::Format_RGBA64;
|
||||||
if (loadalpha)
|
if (loadalpha)
|
||||||
@ -294,12 +309,13 @@ bool QJpegXLHandler::countALLFrames()
|
|||||||
}
|
}
|
||||||
} else { // 8bit depth
|
} else { // 8bit depth
|
||||||
m_input_pixel_format.data_type = JXL_TYPE_UINT8;
|
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) {
|
if (is_gray) {
|
||||||
m_input_image_format = m_target_image_format = QImage::Format_Grayscale8;
|
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 {
|
} else {
|
||||||
m_input_image_format = QImage::Format_RGBA8888;
|
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) {
|
if (loadalpha) {
|
||||||
m_target_image_format = QImage::Format_ARGB32;
|
m_target_image_format = QImage::Format_ARGB32;
|
||||||
} else {
|
} else {
|
||||||
@ -631,7 +647,8 @@ bool QJpegXLHandler::write(const QImage &image)
|
|||||||
|
|
||||||
QByteArray iccprofile;
|
QByteArray iccprofile;
|
||||||
QColorSpace tmpcs = image.colorSpace();
|
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
|
// no profile or Qt-unsupported ICC profile
|
||||||
iccprofile = tmpcs.iccProfile();
|
iccprofile = tmpcs.iccProfile();
|
||||||
// note: lossless encoding requires uses_original_profile = JXL_TRUE
|
// note: lossless encoding requires uses_original_profile = JXL_TRUE
|
||||||
@ -766,8 +783,7 @@ bool QJpegXLHandler::write(const QImage &image)
|
|||||||
auto cs = image.colorSpace();
|
auto cs = image.colorSpace();
|
||||||
if (cs.isValid() && cs.colorModel() == QColorSpace::ColorModel::Cmyk && image.format() == QImage::Format_CMYK8888) {
|
if (cs.isValid() && cs.colorModel() == QColorSpace::ColorModel::Cmyk && image.format() == QImage::Format_CMYK8888) {
|
||||||
tmpimage = image.convertedToColorSpace(QColorSpace(QColorSpace::SRgb), tmpformat);
|
tmpimage = image.convertedToColorSpace(QColorSpace(QColorSpace::SRgb), tmpformat);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
tmpimage = image.convertToFormat(tmpformat);
|
tmpimage = image.convertToFormat(tmpformat);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@ -943,7 +959,6 @@ QVariant QJpegXLHandler::option(ImageOption option) const
|
|||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
switch (option) {
|
switch (option) {
|
||||||
case Size:
|
case Size:
|
||||||
return QSize(m_basicinfo.xsize, m_basicinfo.ysize);
|
return QSize(m_basicinfo.xsize, m_basicinfo.ysize);
|
||||||
@ -1154,13 +1169,7 @@ bool QJpegXLHandler::rewind()
|
|||||||
|
|
||||||
JxlDecoderCloseInput(m_decoder);
|
JxlDecoderCloseInput(m_decoder);
|
||||||
|
|
||||||
if (m_basicinfo.uses_original_profile) {
|
if (m_basicinfo.uses_original_profile == JXL_FALSE && m_basicinfo.have_animation == JXL_FALSE) {
|
||||||
if (JxlDecoderSubscribeEvents(m_decoder, JXL_DEC_FULL_IMAGE) != JXL_DEC_SUCCESS) {
|
|
||||||
qWarning("ERROR: JxlDecoderSubscribeEvents failed");
|
|
||||||
m_parseState = ParseJpegXLError;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (JxlDecoderSubscribeEvents(m_decoder, JXL_DEC_COLOR_ENCODING | JXL_DEC_FULL_IMAGE) != JXL_DEC_SUCCESS) {
|
if (JxlDecoderSubscribeEvents(m_decoder, JXL_DEC_COLOR_ENCODING | JXL_DEC_FULL_IMAGE) != JXL_DEC_SUCCESS) {
|
||||||
qWarning("ERROR: JxlDecoderSubscribeEvents failed");
|
qWarning("ERROR: JxlDecoderSubscribeEvents failed");
|
||||||
m_parseState = ParseJpegXLError;
|
m_parseState = ParseJpegXLError;
|
||||||
@ -1174,9 +1183,28 @@ bool QJpegXLHandler::rewind()
|
|||||||
return false;
|
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;
|
JxlColorEncoding color_encoding;
|
||||||
JxlColorEncodingSetToSRGB(&color_encoding, JXL_FALSE);
|
JxlColorEncodingSetToSRGB(&color_encoding, is_gray ? JXL_TRUE : JXL_FALSE);
|
||||||
JxlDecoderSetPreferredColorProfile(m_decoder, &color_encoding);
|
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;
|
return true;
|
||||||
|
Loading…
Reference in New Issue
Block a user