15#include <jxl/encode.h>
16#include <jxl/thread_parallel_runner.h>
19QJpegXLHandler::QJpegXLHandler()
20 : m_parseState(ParseJpegXLNotParsed)
22 , m_currentimage_index(0)
23 , m_previousimage_index(-1)
26 , m_next_image_delay(0)
27 , m_input_image_format(
QImage::Format_Invalid)
28 , m_target_image_format(
QImage::Format_Invalid)
33QJpegXLHandler::~QJpegXLHandler()
36 JxlThreadParallelRunnerDestroy(m_runner);
39 JxlDecoderDestroy(m_decoder);
43bool QJpegXLHandler::canRead()
const
45 if (m_parseState == ParseJpegXLNotParsed && !canRead(device())) {
49 if (m_parseState != ParseJpegXLError) {
52 if (m_parseState == ParseJpegXLFinished) {
61bool QJpegXLHandler::canRead(
QIODevice *device)
67 if (header.
size() < 12) {
71 JxlSignature signature = JxlSignatureCheck(
reinterpret_cast<const uint8_t *
>(header.
constData()), header.
size());
72 if (signature == JXL_SIG_CODESTREAM || signature == JXL_SIG_CONTAINER) {
78bool QJpegXLHandler::ensureParsed()
const
80 if (m_parseState == ParseJpegXLSuccess || m_parseState == ParseJpegXLBasicInfoParsed || m_parseState == ParseJpegXLFinished) {
83 if (m_parseState == ParseJpegXLError) {
87 QJpegXLHandler *that =
const_cast<QJpegXLHandler *
>(
this);
89 return that->ensureDecoder();
92bool QJpegXLHandler::ensureALLCounted()
const
94 if (!ensureParsed()) {
98 if (m_parseState == ParseJpegXLSuccess || m_parseState == ParseJpegXLFinished) {
102 QJpegXLHandler *that =
const_cast<QJpegXLHandler *
>(
this);
104 return that->countALLFrames();
107bool QJpegXLHandler::ensureDecoder()
113 m_rawData = device()->
readAll();
115 if (m_rawData.isEmpty()) {
119 JxlSignature signature = JxlSignatureCheck(
reinterpret_cast<const uint8_t *
>(m_rawData.constData()), m_rawData.size());
120 if (signature != JXL_SIG_CODESTREAM && signature != JXL_SIG_CONTAINER) {
121 m_parseState = ParseJpegXLError;
125 m_decoder = JxlDecoderCreate(
nullptr);
127 qWarning(
"ERROR: JxlDecoderCreate failed");
128 m_parseState = ParseJpegXLError;
133 if (!m_runner && num_worker_threads >= 4) {
136 num_worker_threads = num_worker_threads / 2;
137 num_worker_threads = qBound(2, num_worker_threads, 64);
138 m_runner = JxlThreadParallelRunnerCreate(
nullptr, num_worker_threads);
140 if (JxlDecoderSetParallelRunner(m_decoder, JxlThreadParallelRunner, m_runner) != JXL_DEC_SUCCESS) {
141 qWarning(
"ERROR: JxlDecoderSetParallelRunner failed");
142 m_parseState = ParseJpegXLError;
147 if (JxlDecoderSetInput(m_decoder,
reinterpret_cast<const uint8_t *
>(m_rawData.constData()), m_rawData.size()) != JXL_DEC_SUCCESS) {
148 qWarning(
"ERROR: JxlDecoderSetInput failed");
149 m_parseState = ParseJpegXLError;
153 JxlDecoderCloseInput(m_decoder);
155 JxlDecoderStatus
status = JxlDecoderSubscribeEvents(m_decoder, JXL_DEC_BASIC_INFO | JXL_DEC_COLOR_ENCODING | JXL_DEC_FRAME);
156 if (
status == JXL_DEC_ERROR) {
157 qWarning(
"ERROR: JxlDecoderSubscribeEvents failed");
158 m_parseState = ParseJpegXLError;
162 status = JxlDecoderProcessInput(m_decoder);
163 if (
status == JXL_DEC_ERROR) {
164 qWarning(
"ERROR: JXL decoding failed");
165 m_parseState = ParseJpegXLError;
168 if (
status == JXL_DEC_NEED_MORE_INPUT) {
169 qWarning(
"ERROR: JXL data incomplete");
170 m_parseState = ParseJpegXLError;
174 status = JxlDecoderGetBasicInfo(m_decoder, &m_basicinfo);
175 if (
status != JXL_DEC_SUCCESS) {
176 qWarning(
"ERROR: JXL basic info not available");
177 m_parseState = ParseJpegXLError;
181 if (m_basicinfo.xsize == 0 || m_basicinfo.ysize == 0) {
182 qWarning(
"ERROR: JXL image has zero dimensions");
183 m_parseState = ParseJpegXLError;
187 if (m_basicinfo.xsize > 65535 || m_basicinfo.ysize > 65535) {
188 qWarning(
"JXL image (%dx%d) is too large", m_basicinfo.xsize, m_basicinfo.ysize);
189 m_parseState = ParseJpegXLError;
193 if (
sizeof(
void *) <= 4) {
197 if (m_basicinfo.xsize > ((8192 * 8192) / m_basicinfo.ysize)) {
198 qWarning(
"JXL image (%dx%d) is too large for 32bit build of the plug-in", m_basicinfo.xsize, m_basicinfo.ysize);
199 m_parseState = ParseJpegXLError;
206 if (m_basicinfo.xsize > ((16384 * 16384) / m_basicinfo.ysize)) {
207 qWarning(
"JXL image (%dx%d) is bigger than security limit 256 megapixels", m_basicinfo.xsize, m_basicinfo.ysize);
208 m_parseState = ParseJpegXLError;
213 m_parseState = ParseJpegXLBasicInfoParsed;
217bool QJpegXLHandler::countALLFrames()
219 if (m_parseState != ParseJpegXLBasicInfoParsed) {
223 JxlDecoderStatus
status = JxlDecoderProcessInput(m_decoder);
224 if (
status != JXL_DEC_COLOR_ENCODING) {
225 qWarning(
"Unexpected event %d instead of JXL_DEC_COLOR_ENCODING",
status);
226 m_parseState = ParseJpegXLError;
230 JxlColorEncoding color_encoding;
231 if (m_basicinfo.uses_original_profile == JXL_FALSE) {
232 JxlColorEncodingSetToSRGB(&color_encoding, JXL_FALSE);
233 JxlDecoderSetPreferredColorProfile(m_decoder, &color_encoding);
238 if (m_basicinfo.alpha_bits > 0) {
244 m_input_pixel_format.endianness = JXL_NATIVE_ENDIAN;
245 m_input_pixel_format.align = 0;
246 m_input_pixel_format.num_channels = 4;
248 if (m_basicinfo.bits_per_sample > 8) {
249 m_input_pixel_format.data_type = JXL_TYPE_UINT16;
250 m_buffer_size = 8 * (size_t)m_basicinfo.xsize * (
size_t)m_basicinfo.ysize;
259 m_input_pixel_format.data_type = JXL_TYPE_UINT8;
260 m_buffer_size = 4 * (size_t)m_basicinfo.xsize * (
size_t)m_basicinfo.ysize;
270 status = JxlDecoderGetColorAsEncodedProfile(m_decoder,
271#
if JPEGXL_NUMERIC_VERSION < JPEGXL_COMPUTE_NUMERIC_VERSION(0, 9, 0)
272 &m_input_pixel_format,
274 JXL_COLOR_PROFILE_TARGET_DATA,
277 if (
status == JXL_DEC_SUCCESS && color_encoding.color_space == JXL_COLOR_SPACE_RGB && color_encoding.white_point == JXL_WHITE_POINT_D65
278 && color_encoding.primaries == JXL_PRIMARIES_SRGB && color_encoding.transfer_function == JXL_TRANSFER_FUNCTION_SRGB) {
282 if (JxlDecoderGetICCProfileSize(m_decoder,
283#
if JPEGXL_NUMERIC_VERSION < JPEGXL_COMPUTE_NUMERIC_VERSION(0, 9, 0)
284 &m_input_pixel_format,
286 JXL_COLOR_PROFILE_TARGET_DATA,
288 == JXL_DEC_SUCCESS) {
291 if (JxlDecoderGetColorAsICCProfile(m_decoder,
292#
if JPEGXL_NUMERIC_VERSION < JPEGXL_COMPUTE_NUMERIC_VERSION(0, 9, 0)
293 &m_input_pixel_format,
295 JXL_COLOR_PROFILE_TARGET_DATA,
296 reinterpret_cast<uint8_t *
>(icc_data.data()),
298 == JXL_DEC_SUCCESS) {
301 if (!m_colorspace.isValid()) {
302 qWarning(
"JXL image has Qt-unsupported or invalid ICC profile!");
305 qWarning(
"Failed to obtain data from JPEG XL decoder");
308 qWarning(
"Empty ICC data");
311 qWarning(
"no ICC, other color profile");
315 if (m_basicinfo.have_animation) {
316 JxlFrameHeader frame_header;
319 for (
status = JxlDecoderProcessInput(m_decoder);
status != JXL_DEC_SUCCESS;
status = JxlDecoderProcessInput(m_decoder)) {
320 if (
status != JXL_DEC_FRAME) {
323 qWarning(
"ERROR: JXL decoding failed");
325 case JXL_DEC_NEED_MORE_INPUT:
326 qWarning(
"ERROR: JXL data incomplete");
329 qWarning(
"Unexpected event %d instead of JXL_DEC_FRAME",
status);
332 m_parseState = ParseJpegXLError;
336 if (JxlDecoderGetFrameHeader(m_decoder, &frame_header) != JXL_DEC_SUCCESS) {
337 qWarning(
"ERROR: JxlDecoderGetFrameHeader failed");
338 m_parseState = ParseJpegXLError;
342 if (m_basicinfo.animation.tps_denominator > 0 && m_basicinfo.animation.tps_numerator > 0) {
343 delay = (int)(0.5 + 1000.0 * frame_header.duration * m_basicinfo.animation.tps_denominator / m_basicinfo.animation.tps_numerator);
348 m_framedelays.append(delay);
351 if (m_framedelays.isEmpty()) {
352 qWarning(
"no frames loaded by the JXL plug-in");
353 m_parseState = ParseJpegXLError;
357 if (m_framedelays.count() == 1) {
358 qWarning(
"JXL file was marked as animation but it has only one frame.");
359 m_basicinfo.have_animation = JXL_FALSE;
362 m_framedelays.resize(1);
363 m_framedelays[0] = 0;
370 m_next_image_delay = m_framedelays[0];
371 m_parseState = ParseJpegXLSuccess;
375bool QJpegXLHandler::decode_one_frame()
377 JxlDecoderStatus
status = JxlDecoderProcessInput(m_decoder);
378 if (
status != JXL_DEC_NEED_IMAGE_OUT_BUFFER) {
379 qWarning(
"Unexpected event %d instead of JXL_DEC_NEED_IMAGE_OUT_BUFFER",
status);
380 m_parseState = ParseJpegXLError;
384 m_current_image = imageAlloc(m_basicinfo.xsize, m_basicinfo.ysize, m_input_image_format);
385 if (m_current_image.isNull()) {
386 qWarning(
"Memory cannot be allocated");
387 m_parseState = ParseJpegXLError;
391 m_current_image.setColorSpace(m_colorspace);
393 if (JxlDecoderSetImageOutBuffer(m_decoder, &m_input_pixel_format, m_current_image.bits(), m_buffer_size) != JXL_DEC_SUCCESS) {
394 qWarning(
"ERROR: JxlDecoderSetImageOutBuffer failed");
395 m_parseState = ParseJpegXLError;
399 status = JxlDecoderProcessInput(m_decoder);
400 if (
status != JXL_DEC_FULL_IMAGE) {
401 qWarning(
"Unexpected event %d instead of JXL_DEC_FULL_IMAGE",
status);
402 m_parseState = ParseJpegXLError;
406 if (m_target_image_format != m_input_image_format) {
407 m_current_image.convertTo(m_target_image_format);
410 m_next_image_delay = m_framedelays[m_currentimage_index];
411 m_previousimage_index = m_currentimage_index;
413 if (m_framedelays.count() > 1) {
414 m_currentimage_index++;
416 if (m_currentimage_index >= m_framedelays.count()) {
422 m_parseState = ParseJpegXLFinished;
424 m_parseState = ParseJpegXLSuccess;
428 m_parseState = ParseJpegXLFinished;
434bool QJpegXLHandler::read(
QImage *image)
436 if (!ensureALLCounted()) {
440 if (m_currentimage_index == m_previousimage_index) {
441 *image = m_current_image;
442 return jumpToNextImage();
445 if (decode_one_frame()) {
446 *image = m_current_image;
453bool QJpegXLHandler::write(
const QImage &image)
456 qWarning(
"No image data to save");
461 if ((image.
width() > 65535) || (image.
height() > 65535)) {
462 qWarning(
"Image (%dx%d) is too large to save!", image.
width(), image.
height());
466 if (
sizeof(
void *) <= 4) {
467 if (image.
width() > ((8192 * 8192) / image.
height())) {
468 qWarning(
"Image (%dx%d) is too large save via 32bit build of JXL plug-in", image.
width(), image.
height());
472 if (image.
width() > ((16384 * 16384) / image.
height())) {
473 qWarning(
"Image (%dx%d) will not be saved because it has more than 256 megapixels", image.
width(), image.
height());
478 qWarning(
"Image has zero dimension!");
505 if (image.
depth() > 32) {
513 JxlEncoder *encoder = JxlEncoderCreate(
nullptr);
515 qWarning(
"Failed to create Jxl encoder");
519 if (m_quality > 100) {
521 }
else if (m_quality < 0) {
525 JxlBasicInfo output_info;
526 JxlEncoderInitBasicInfo(&output_info);
528 bool convert_color_profile;
533 convert_color_profile =
true;
535 convert_color_profile =
false;
538 convert_color_profile =
false;
540 if (iccprofile.
size() > 0 || m_quality == 100) {
541 output_info.uses_original_profile = JXL_TRUE;
545 if (save_depth == 16 && (image.
hasAlphaChannel() || output_info.uses_original_profile)) {
546 output_info.have_container = JXL_TRUE;
547 JxlEncoderUseContainer(encoder, JXL_TRUE);
548 JxlEncoderSetCodestreamLevel(encoder, 10);
551 void *runner =
nullptr;
554 if (num_worker_threads > 1) {
555 runner = JxlThreadParallelRunnerCreate(
nullptr, num_worker_threads);
556 if (JxlEncoderSetParallelRunner(encoder, JxlThreadParallelRunner, runner) != JXL_ENC_SUCCESS) {
557 qWarning(
"JxlEncoderSetParallelRunner failed");
558 JxlThreadParallelRunnerDestroy(runner);
559 JxlEncoderDestroy(encoder);
564 JxlPixelFormat pixel_format;
568 pixel_format.endianness = JXL_NATIVE_ENDIAN;
569 pixel_format.align = 0;
571 output_info.orientation = JXL_ORIENT_IDENTITY;
572 output_info.num_color_channels = 3;
573 output_info.animation.tps_numerator = 10;
574 output_info.animation.tps_denominator = 1;
576 if (save_depth > 8) {
577 pixel_format.data_type = JXL_TYPE_UINT16;
579 output_info.bits_per_sample = 16;
583 pixel_format.num_channels = 4;
584 output_info.alpha_bits = 16;
585 output_info.num_extra_channels = 1;
588 pixel_format.num_channels = 3;
589 output_info.alpha_bits = 0;
592 pixel_format.data_type = JXL_TYPE_UINT8;
594 output_info.bits_per_sample = 8;
598 pixel_format.num_channels = 4;
599 output_info.alpha_bits = 8;
600 output_info.num_extra_channels = 1;
603 pixel_format.num_channels = 3;
604 output_info.alpha_bits = 0;
611 const size_t xsize = tmpimage.
width();
612 const size_t ysize = tmpimage.
height();
613 const size_t buffer_size = (save_depth > 8) ? (2 * pixel_format.num_channels * xsize * ysize) : (pixel_format.num_channels * xsize * ysize);
615 if (xsize == 0 || ysize == 0 || tmpimage.
isNull()) {
616 qWarning(
"Unable to allocate memory for output image");
618 JxlThreadParallelRunnerDestroy(runner);
620 JxlEncoderDestroy(encoder);
624 output_info.xsize = tmpimage.
width();
625 output_info.ysize = tmpimage.
height();
627 status = JxlEncoderSetBasicInfo(encoder, &output_info);
628 if (
status != JXL_ENC_SUCCESS) {
629 qWarning(
"JxlEncoderSetBasicInfo failed!");
631 JxlThreadParallelRunnerDestroy(runner);
633 JxlEncoderDestroy(encoder);
637 if (!convert_color_profile && iccprofile.
size() > 0) {
638 status = JxlEncoderSetICCProfile(encoder,
reinterpret_cast<const uint8_t *
>(iccprofile.
constData()), iccprofile.
size());
639 if (
status != JXL_ENC_SUCCESS) {
640 qWarning(
"JxlEncoderSetICCProfile failed!");
642 JxlThreadParallelRunnerDestroy(runner);
644 JxlEncoderDestroy(encoder);
648 JxlColorEncoding color_profile;
649 JxlColorEncodingSetToSRGB(&color_profile, JXL_FALSE);
651 status = JxlEncoderSetColorEncoding(encoder, &color_profile);
652 if (
status != JXL_ENC_SUCCESS) {
653 qWarning(
"JxlEncoderSetColorEncoding failed!");
655 JxlThreadParallelRunnerDestroy(runner);
657 JxlEncoderDestroy(encoder);
662 JxlEncoderFrameSettings *encoder_options = JxlEncoderFrameSettingsCreate(encoder,
nullptr);
664 JxlEncoderSetFrameDistance(encoder_options, (100.0f - m_quality) / 10.0f);
666 JxlEncoderSetFrameLossless(encoder_options, (m_quality == 100) ? JXL_TRUE : JXL_FALSE);
668 if (image.
hasAlphaChannel() || ((save_depth == 8) && (xsize % 4 == 0))) {
669 status = JxlEncoderAddImageFrame(encoder_options, &pixel_format,
static_cast<const void *
>(tmpimage.
constBits()), buffer_size);
671 if (save_depth > 8) {
672 uint16_t *tmp_buffer =
new (std::nothrow) uint16_t[3 * xsize * ysize];
674 qWarning(
"Memory allocation error");
676 JxlThreadParallelRunnerDestroy(runner);
678 JxlEncoderDestroy(encoder);
682 uint16_t *dest_pixels = tmp_buffer;
683 for (
int y = 0; y < tmpimage.
height(); y++) {
684 const uint16_t *src_pixels =
reinterpret_cast<const uint16_t *
>(tmpimage.
constScanLine(y));
685 for (
int x = 0; x < tmpimage.
width(); x++) {
687 *dest_pixels = *src_pixels;
691 *dest_pixels = *src_pixels;
695 *dest_pixels = *src_pixels;
700 status = JxlEncoderAddImageFrame(encoder_options, &pixel_format,
static_cast<const void *
>(tmp_buffer), buffer_size);
703 uchar *tmp_buffer8 =
new (std::nothrow) uchar[3 * xsize * ysize];
705 qWarning(
"Memory allocation error");
707 JxlThreadParallelRunnerDestroy(runner);
709 JxlEncoderDestroy(encoder);
713 uchar *dest_pixels8 = tmp_buffer8;
714 const size_t rowbytes = 3 * xsize;
715 for (
int y = 0; y < tmpimage.
height(); y++) {
717 dest_pixels8 += rowbytes;
719 status = JxlEncoderAddImageFrame(encoder_options, &pixel_format,
static_cast<const void *
>(tmp_buffer8), buffer_size);
720 delete[] tmp_buffer8;
724 if (
status == JXL_ENC_ERROR) {
725 qWarning(
"JxlEncoderAddImageFrame failed!");
727 JxlThreadParallelRunnerDestroy(runner);
729 JxlEncoderDestroy(encoder);
733 JxlEncoderCloseInput(encoder);
735 std::vector<uint8_t> compressed;
736 compressed.resize(4096);
741 next_out = compressed.data() + offset;
742 avail_out = compressed.size() - offset;
743 status = JxlEncoderProcessOutput(encoder, &next_out, &avail_out);
745 if (
status == JXL_ENC_NEED_MORE_OUTPUT) {
746 offset = next_out - compressed.data();
747 compressed.resize(compressed.size() * 2);
748 }
else if (
status == JXL_ENC_ERROR) {
749 qWarning(
"JxlEncoderProcessOutput failed!");
751 JxlThreadParallelRunnerDestroy(runner);
753 JxlEncoderDestroy(encoder);
756 }
while (
status != JXL_ENC_SUCCESS);
759 JxlThreadParallelRunnerDestroy(runner);
761 JxlEncoderDestroy(encoder);
763 compressed.resize(next_out - compressed.data());
765 if (compressed.size() > 0) {
766 qint64 write_status = device()->
write(
reinterpret_cast<const char *
>(compressed.data()), compressed.size());
768 if (write_status > 0) {
770 }
else if (write_status == -1) {
771 qWarning(
"Write error: %s\n", qUtf8Printable(device()->errorString()));
778QVariant QJpegXLHandler::option(ImageOption option)
const
780 if (option == Quality) {
784 if (!supportsOption(option) || !ensureParsed()) {
790 return QSize(m_basicinfo.xsize, m_basicinfo.ysize);
792 if (m_basicinfo.have_animation) {
802void QJpegXLHandler::setOption(ImageOption option,
const QVariant &value)
806 m_quality = value.
toInt();
807 if (m_quality > 100) {
809 }
else if (m_quality < 0) {
819bool QJpegXLHandler::supportsOption(ImageOption option)
const
821 return option == Quality || option == Size || option ==
Animation;
824int QJpegXLHandler::imageCount()
const
826 if (!ensureParsed()) {
830 if (m_parseState == ParseJpegXLBasicInfoParsed) {
831 if (!m_basicinfo.have_animation) {
835 if (!ensureALLCounted()) {
840 if (!m_framedelays.isEmpty()) {
841 return m_framedelays.count();
846int QJpegXLHandler::currentImageNumber()
const
848 if (m_parseState == ParseJpegXLNotParsed) {
852 if (m_parseState == ParseJpegXLError || m_parseState == ParseJpegXLBasicInfoParsed || !m_decoder) {
856 return m_currentimage_index;
859bool QJpegXLHandler::jumpToNextImage()
861 if (!ensureALLCounted()) {
865 if (m_framedelays.count() > 1) {
866 m_currentimage_index++;
868 if (m_currentimage_index >= m_framedelays.count()) {
873 JxlDecoderSkipFrames(m_decoder, 1);
877 m_parseState = ParseJpegXLSuccess;
881bool QJpegXLHandler::jumpToImage(
int imageNumber)
883 if (!ensureALLCounted()) {
887 if (imageNumber < 0 || imageNumber >= m_framedelays.count()) {
891 if (imageNumber == m_currentimage_index) {
892 m_parseState = ParseJpegXLSuccess;
896 if (imageNumber > m_currentimage_index) {
897 JxlDecoderSkipFrames(m_decoder, imageNumber - m_currentimage_index);
898 m_currentimage_index = imageNumber;
899 m_parseState = ParseJpegXLSuccess;
907 if (imageNumber > 0) {
908 JxlDecoderSkipFrames(m_decoder, imageNumber);
910 m_currentimage_index = imageNumber;
911 m_parseState = ParseJpegXLSuccess;
915int QJpegXLHandler::nextImageDelay()
const
917 if (!ensureALLCounted()) {
921 if (m_framedelays.count() < 2) {
925 return m_next_image_delay;
928int QJpegXLHandler::loopCount()
const
930 if (!ensureParsed()) {
934 if (m_basicinfo.have_animation) {
935 return (m_basicinfo.animation.num_loops > 0) ? m_basicinfo.animation.num_loops - 1 : -1;
941bool QJpegXLHandler::rewind()
943 m_currentimage_index = 0;
945 JxlDecoderReleaseInput(m_decoder);
946 JxlDecoderRewind(m_decoder);
948 if (JxlDecoderSetParallelRunner(m_decoder, JxlThreadParallelRunner, m_runner) != JXL_DEC_SUCCESS) {
949 qWarning(
"ERROR: JxlDecoderSetParallelRunner failed");
950 m_parseState = ParseJpegXLError;
955 if (JxlDecoderSetInput(m_decoder,
reinterpret_cast<const uint8_t *
>(m_rawData.constData()), m_rawData.size()) != JXL_DEC_SUCCESS) {
956 qWarning(
"ERROR: JxlDecoderSetInput failed");
957 m_parseState = ParseJpegXLError;
961 JxlDecoderCloseInput(m_decoder);
963 if (m_basicinfo.uses_original_profile) {
964 if (JxlDecoderSubscribeEvents(m_decoder, JXL_DEC_FULL_IMAGE) != JXL_DEC_SUCCESS) {
965 qWarning(
"ERROR: JxlDecoderSubscribeEvents failed");
966 m_parseState = ParseJpegXLError;
970 if (JxlDecoderSubscribeEvents(m_decoder, JXL_DEC_COLOR_ENCODING | JXL_DEC_FULL_IMAGE) != JXL_DEC_SUCCESS) {
971 qWarning(
"ERROR: JxlDecoderSubscribeEvents failed");
972 m_parseState = ParseJpegXLError;
976 JxlDecoderStatus
status = JxlDecoderProcessInput(m_decoder);
977 if (
status != JXL_DEC_COLOR_ENCODING) {
978 qWarning(
"Unexpected event %d instead of JXL_DEC_COLOR_ENCODING",
status);
979 m_parseState = ParseJpegXLError;
983 JxlColorEncoding color_encoding;
984 JxlColorEncodingSetToSRGB(&color_encoding, JXL_FALSE);
985 JxlDecoderSetPreferredColorProfile(m_decoder, &color_encoding);
993 if (format ==
"jxl") {
1005 if (device->
isReadable() && QJpegXLHandler::canRead(device)) {
1024#include "moc_jxl_p.cpp"
Q_SCRIPTABLE CaptureState status()
QFlags< Capability > Capabilities
const char * constData() const const
bool isEmpty() const const
qsizetype size() const const
QColorSpace fromIccProfile(const QByteArray &iccProfile)
QByteArray iccProfile() const const
bool isValid() const const
Primaries primaries() const const
TransferFunction transferFunction() const const
QColorSpace colorSpace() const const
const uchar * constBits() const const
const uchar * constScanLine(int i) const const
QImage convertedToColorSpace(const QColorSpace &colorSpace) const const
bool hasAlphaChannel() const const
bool isNull() const const
void setDevice(QIODevice *device)
virtual void setOption(ImageOption option, const QVariant &value)
bool isOpen() const const
bool isReadable() const const
bool isWritable() const const
QByteArray peek(qint64 maxSize)
qint64 write(const QByteArray &data)
int toInt(bool *ok) const const