jxl: Do not rewind after reading final frame

This commit is contained in:
Daniel Novomeský
2026-08-18 08:48:40 +00:00
parent 09452b0964
commit 458257b7a3
2 changed files with 32 additions and 34 deletions
+32 -33
View File
@@ -60,7 +60,7 @@ Q_LOGGING_CATEGORY(LOG_JXLPLUGIN, "kf.imageformats.plugins.jxl", QtWarningMsg)
void *QtJXLMemoryManagerAlloc(void *opaque, size_t size) void *QtJXLMemoryManagerAlloc(void *opaque, size_t size)
{ {
if (opaque) { if (opaque) {
size_t maxBytes = *(size_t*)opaque; size_t maxBytes = *(size_t *)opaque;
if (maxBytes && size > maxBytes) if (maxBytes && size > maxBytes)
return NULL; return NULL;
} }
@@ -75,8 +75,7 @@ void QtJXLMemoryManagerFree(void *, void *address)
QJpegXLHandler::QJpegXLHandler() QJpegXLHandler::QJpegXLHandler()
: m_parseState(ParseJpegXLNotParsed) : m_parseState(ParseJpegXLNotParsed)
, m_quality(90) , m_quality(90)
, m_currentimage_index(0) , m_currentimage_index(-1)
, m_previousimage_index(-1)
, m_transformations(QImageIOHandler::TransformationNone) , m_transformations(QImageIOHandler::TransformationNone)
, m_decoder(nullptr) , m_decoder(nullptr)
, m_runner(nullptr) , m_runner(nullptr)
@@ -183,11 +182,7 @@ bool QJpegXLHandler::ensureDecoder()
} }
// Creating a simple memory manager // Creating a simple memory manager
JxlMemoryManager memory_manager = { JxlMemoryManager memory_manager = {.opaque = &m_maxBytes, .alloc = QtJXLMemoryManagerAlloc, .free = QtJXLMemoryManagerFree};
.opaque = &m_maxBytes,
.alloc = QtJXLMemoryManagerAlloc,
.free = QtJXLMemoryManagerFree
};
// Creating the decoder (it makes a deep copy of memory manager) // Creating the decoder (it makes a deep copy of memory manager)
m_decoder = JxlDecoderCreate(&memory_manager); m_decoder = JxlDecoderCreate(&memory_manager);
if (!m_decoder) { if (!m_decoder) {
@@ -817,17 +812,11 @@ bool QJpegXLHandler::decode_one_frame()
exif.updateImageMetadata(m_current_image); exif.updateImageMetadata(m_current_image);
} }
m_currentimage_index++;
m_next_image_delay = m_framedelays[m_currentimage_index]; m_next_image_delay = m_framedelays[m_currentimage_index];
m_previousimage_index = m_currentimage_index;
if (m_framedelays.count() > 1) { if (m_framedelays.count() > 1) {
m_currentimage_index++; if (m_currentimage_index >= m_framedelays.count() - 1) {
if (m_currentimage_index >= m_framedelays.count()) {
if (!rewind()) {
return false;
}
// all frames in animation have been read // all frames in animation have been read
m_parseState = ParseJpegXLFinished; m_parseState = ParseJpegXLFinished;
} else { } else {
@@ -847,9 +836,9 @@ bool QJpegXLHandler::read(QImage *image)
return false; return false;
} }
if (m_currentimage_index == m_previousimage_index) { if (m_parseState == ParseJpegXLFinished) {
*image = m_current_image; // at the end already
return jumpToNextImage(); return false;
} }
if (decode_one_frame()) { if (decode_one_frame()) {
@@ -1757,19 +1746,26 @@ bool QJpegXLHandler::jumpToNextImage()
} }
if (m_framedelays.count() > 1) { if (m_framedelays.count() > 1) {
m_currentimage_index++; if (m_currentimage_index >= (m_framedelays.count() - 1)) {
// we are already at the last frame
if (m_currentimage_index >= m_framedelays.count()) { return false;
if (!rewind()) {
return false;
}
} else { } else {
m_currentimage_index++;
m_next_image_delay = m_framedelays[m_currentimage_index];
JxlDecoderSkipFrames(m_decoder, 1); JxlDecoderSkipFrames(m_decoder, 1);
if (m_currentimage_index >= (m_framedelays.count() - 1)) {
// last frame reached but no more reading is possible
m_parseState = ParseJpegXLFinished;
} else {
m_parseState = ParseJpegXLSuccess;
}
return true;
} }
} }
m_parseState = ParseJpegXLSuccess; // static image, there is no next frame
return true; return false;
} }
bool QJpegXLHandler::jumpToImage(int imageNumber) bool QJpegXLHandler::jumpToImage(int imageNumber)
@@ -1782,14 +1778,17 @@ bool QJpegXLHandler::jumpToImage(int imageNumber)
return false; return false;
} }
if (imageNumber == m_currentimage_index) { const int next_image_index = m_currentimage_index + 1;
if (imageNumber == next_image_index) {
// This the already the next image to read, no action
m_parseState = ParseJpegXLSuccess; m_parseState = ParseJpegXLSuccess;
return true; return true;
} }
if (imageNumber > m_currentimage_index) { if (imageNumber > next_image_index) {
JxlDecoderSkipFrames(m_decoder, imageNumber - m_currentimage_index); JxlDecoderSkipFrames(m_decoder, imageNumber - next_image_index);
m_currentimage_index = imageNumber; m_currentimage_index = imageNumber - 1;
m_parseState = ParseJpegXLSuccess; m_parseState = ParseJpegXLSuccess;
return true; return true;
} }
@@ -1801,7 +1800,7 @@ bool QJpegXLHandler::jumpToImage(int imageNumber)
if (imageNumber > 0) { if (imageNumber > 0) {
JxlDecoderSkipFrames(m_decoder, imageNumber); JxlDecoderSkipFrames(m_decoder, imageNumber);
} }
m_currentimage_index = imageNumber; m_currentimage_index = imageNumber - 1;
m_parseState = ParseJpegXLSuccess; m_parseState = ParseJpegXLSuccess;
return true; return true;
} }
@@ -1834,7 +1833,7 @@ int QJpegXLHandler::loopCount() const
bool QJpegXLHandler::rewind() bool QJpegXLHandler::rewind()
{ {
m_currentimage_index = 0; m_currentimage_index = -1;
JxlDecoderReleaseInput(m_decoder); JxlDecoderReleaseInput(m_decoder);
JxlDecoderRewind(m_decoder); JxlDecoderRewind(m_decoder);
-1
View File
@@ -65,7 +65,6 @@ private:
ParseJpegXLState m_parseState; ParseJpegXLState m_parseState;
int m_quality; int m_quality;
int m_currentimage_index; int m_currentimage_index;
int m_previousimage_index;
QImageIOHandler::Transformations m_transformations; QImageIOHandler::Transformations m_transformations;
QByteArray m_rawData; QByteArray m_rawData;