diff --git a/modules/imgcodecs/src/grfmt_gif.cpp b/modules/imgcodecs/src/grfmt_gif.cpp index 5a65ae04b1..05b27e4ddd 100644 --- a/modules/imgcodecs/src/grfmt_gif.cpp +++ b/modules/imgcodecs/src/grfmt_gif.cpp @@ -4,6 +4,7 @@ #include "precomp.hpp" #include "grfmt_gif.hpp" +#include "opencv2/core/utils/logger.hpp" #ifdef HAVE_IMGCODEC_GIF namespace cv @@ -293,11 +294,12 @@ void GifDecoder::code2pixel(Mat& img, int start, int k){ bool GifDecoder::lzwDecode() { // initialization lzwMinCodeSize = m_strm.getByte(); + const int lzwMaxSize = (1 << 12); // 4096 is the maximum size of the LZW table (12 bits) int lzwCodeSize = lzwMinCodeSize + 1; int clearCode = 1 << lzwMinCodeSize; int exitCode = clearCode + 1; CV_Assert(lzwCodeSize > 2 && lzwCodeSize <= 12); - std::vector lzwExtraTable((1 << 12) + 1); + std::vector lzwExtraTable(lzwMaxSize + 1); int colorTableSize = clearCode; int lzwTableSize = exitCode; @@ -321,6 +323,7 @@ bool GifDecoder::lzwDecode() { // clear code if (!(code ^ clearCode)) { lzwExtraTable.clear(); + lzwExtraTable.resize(lzwMaxSize + 1); // reset the code size, the same as that in the initialization part lzwCodeSize = lzwMinCodeSize + 1; lzwTableSize = exitCode; @@ -341,20 +344,24 @@ bool GifDecoder::lzwDecode() { // output code // 1. renew the lzw extra table - if (code < colorTableSize) { - lzwExtraTable[lzwTableSize].suffix = (uchar)code; - lzwTableSize ++; - lzwExtraTable[lzwTableSize].prefix.clear(); - lzwExtraTable[lzwTableSize].prefix.push_back((uchar)code); - lzwExtraTable[lzwTableSize].length = 2; - } else if (code <= lzwTableSize) { - lzwExtraTable[lzwTableSize].suffix = lzwExtraTable[code].prefix[0]; - lzwTableSize ++; - lzwExtraTable[lzwTableSize].prefix = lzwExtraTable[code].prefix; - lzwExtraTable[lzwTableSize].prefix.push_back(lzwExtraTable[code].suffix); - lzwExtraTable[lzwTableSize].length = lzwExtraTable[code].length + 1; - } else { - return false; + // * notice that if the lzw table size is full, + // * we should use the old table until a clear code is encountered + if (lzwTableSize < lzwMaxSize) { + if (code < colorTableSize) { + lzwExtraTable[lzwTableSize].suffix = (uchar)code; + lzwTableSize ++; + lzwExtraTable[lzwTableSize].prefix.clear(); + lzwExtraTable[lzwTableSize].prefix.push_back((uchar)code); + lzwExtraTable[lzwTableSize].length = 2; + } else if (code <= lzwTableSize) { + lzwExtraTable[lzwTableSize].suffix = lzwExtraTable[code].prefix[0]; + lzwTableSize ++; + lzwExtraTable[lzwTableSize].prefix = lzwExtraTable[code].prefix; + lzwExtraTable[lzwTableSize].prefix.push_back(lzwExtraTable[code].suffix); + lzwExtraTable[lzwTableSize].length = lzwExtraTable[code].length + 1; + } else { + return false; + } } // 2. output to the code stream @@ -368,7 +375,7 @@ bool GifDecoder::lzwDecode() { } // check if the code size is full - if (lzwTableSize > (1 << 12)) { + if (lzwTableSize > lzwMaxSize) { return false; } @@ -402,14 +409,33 @@ bool GifDecoder::getFrameCount_() { while (type != 0x3B) { if (!(type ^ 0x21)) { // skip all kinds of the extensions - m_strm.skip(1); - int len = m_strm.getByte(); - while (len) { - m_strm.skip(len); - len = m_strm.getByte(); - if (len == 3 && m_strm.getByte() == 1) - { - m_animation.loop_count = m_strm.getWord(); + int extension = m_strm.getByte(); + // Application Extension need to be handled for the loop count + if (extension == 0xFF) { + int len = m_strm.getByte(); + while (len) { + if (len == 3) { + if (m_strm.getByte() == 0x01) { + m_animation.loop_count = m_strm.getWord(); + } else { + // this branch should not be reached in normal cases + m_strm.skip(2); + CV_LOG_WARNING(NULL, "found Unknown Application Extension"); + } + } else { + m_strm.skip(len); + } + len = m_strm.getByte(); + } + } else { + // if it does not belong to any of the extension type mentioned in the GIF Specification + if (extension != 0xF9 && extension != 0xFE && extension != 0x01) { + CV_LOG_WARNING(NULL, "found Unknown Extension Type: " + std::to_string(extension)); + } + int len = m_strm.getByte(); + while (len) { + m_strm.skip(len); + len = m_strm.getByte(); } } } else if (!(type ^ 0x2C)) {