📄 qgifhandler.cpp
字号:
case ImageDataBlock: count++; accum|=(ch<<bitcount); bitcount+=8; while (bitcount>=code_size && state==ImageDataBlock) { int code=accum&((1<<code_size)-1); bitcount-=code_size; accum>>=code_size; if (code==clear_code) { if (!needfirst) { code_size=lzwsize+1; max_code_size=2*clear_code; max_code=clear_code+2; } needfirst=true; } else if (code==end_code) { bitcount = -32768; // Left the block end arrive } else { if (needfirst) { firstcode=oldcode=code; if (!out_of_bounds && image->height() > y && firstcode!=trans_index) ((QRgb*)image->scanLine(y))[x] = color(firstcode); x++; if (x>=swidth) out_of_bounds = true; needfirst=false; if (x>=left+width) { x=left; out_of_bounds = left>=swidth || y>=sheight; nextY(image); } } else { incode=code; if (code>=max_code) { *sp++=firstcode; code=oldcode; } while (code>=clear_code+2) { *sp++=table[1][code]; if (code==table[0][code]) { state=Error; break; } if (sp-stack>=(1<<(max_lzw_bits))*2) { state=Error; break; } code=table[0][code]; } *sp++=firstcode=table[1][code]; code=max_code; if (code<(1<<max_lzw_bits)) { table[0][code]=oldcode; table[1][code]=firstcode; max_code++; if ((max_code>=max_code_size) && (max_code_size<(1<<max_lzw_bits))) { max_code_size*=2; code_size++; } } oldcode=incode; const int h = image->height(); const QRgb *map = lcmap ? localcmap : globalcmap; QRgb *line = 0; if (!out_of_bounds && h > y) line = (QRgb*)image->scanLine(y); while (sp>stack) { const uchar index = *(--sp); if (!out_of_bounds && h > y && index!=trans_index) { if (index > ncols) line[x] = Q_TRANSPARENT; else line[x] = map ? map[index] : 0; } x++; if (x>=swidth) out_of_bounds = true; if (x>=left+width) { x=left; out_of_bounds = left>=swidth || y>=sheight; nextY(image); if (!out_of_bounds && h > y) line = (QRgb*)image->scanLine(y); } } } } } partialNewFrame = true; if (count==expectcount) { count=0; state=ImageDataBlockSize; } break; case ExtensionLabel: switch (ch) { case 0xf9: state=GraphicControlExtension; break; case 0xff: state=ApplicationExtension; break;#if 0 case 0xfe: state=CommentExtension; break; case 0x01: break;#endif default: state=SkipBlockSize; } count=0; break; case ApplicationExtension: if (count<11) hold[count]=ch; count++; if (count==hold[0]+1) { if (qstrncmp((char*)(hold+1), "NETSCAPE", 8)==0) { // Looping extension state=NetscapeExtensionBlockSize; } else { state=SkipBlockSize; } count=0; } break; case NetscapeExtensionBlockSize: expectcount=ch; count=0; if (expectcount) state=NetscapeExtensionBlock; else state=Introducer; break; case NetscapeExtensionBlock: if (count<3) hold[count]=ch; count++; if (count==expectcount) { *loopCount = hold[1]+hold[2]*256; state=SkipBlockSize; // Ignore further blocks } break; case GraphicControlExtension: if (count<5) hold[count]=ch; count++; if (count==hold[0]+1) { disposePrevious(image); disposal=Disposal((hold[1]>>2)&0x7); //UNUSED: waitforuser=!!((hold[1]>>1)&0x1); int delay=count>3 ? LM(hold[2], hold[3]) : 1; // IE and mozilla use a minimum delay of 10. With the minimum delay of 10 // we are compatible to them and avoid huge loads on the app and xserver. *nextFrameDelay = (delay < 2 ? 10 : delay) * 10; bool havetrans=hold[1]&0x1; trans_index = havetrans ? hold[4] : -1; count=0; state=SkipBlockSize; } break; case SkipBlockSize: expectcount=ch; count=0; if (expectcount) state=SkipBlock; else state=Introducer; break; case SkipBlock: count++; if (count==expectcount) state=SkipBlockSize; break; case Done: digress=true; /* Netscape ignores the junk, so we do too. length++; // Unget state=Error; // More calls to this is an error */ break; case Error: return -1; // Called again after done. } } return initial-length;}void QGIFFormat::fillRect(QImage *image, int col, int row, int w, int h, QRgb color){ if (w>0) { for (int j=0; j<h; j++) { QRgb *line = (QRgb*)image->scanLine(j+row); for (int i=0; i<w; i++) *(line+col+i) = color; } }}void QGIFFormat::nextY(QImage *image){ int my; switch (interlace) { case 0: // Non-interlaced // if (!out_of_bounds) { // ### Changed: QRect(left, y, right - left + 1, 1); // } y++; break; case 1: { int i; my = qMin(7, bottom-y); // Don't dup with transparency if (trans_index < 0) { for (i=1; i<=my; i++) { memcpy(image->scanLine(y+i)+left*sizeof(QRgb), image->scanLine(y)+left*sizeof(QRgb), (right-left+1)*sizeof(QRgb)); } } // if (!out_of_bounds) { // ### Changed: QRect(left, y, right - left + 1, my + 1); // }// if (!out_of_bounds)// qDebug("consumer->changed(QRect(%d, %d, %d, %d))", left, y, right-left+1, my+1); y+=8; if (y>bottom) { interlace++; y=top+4; if (y > bottom) { // for really broken GIFs with bottom < 5 interlace=2; y = top + 2; if (y > bottom) { // for really broken GIF with bottom < 3 interlace = 0; y = top + 1; } } } } break; case 2: { int i; my = qMin(3, bottom-y); // Don't dup with transparency if (trans_index < 0) { for (i=1; i<=my; i++) { memcpy(image->scanLine(y+i)+left*sizeof(QRgb), image->scanLine(y)+left*sizeof(QRgb), (right-left+1)*sizeof(QRgb)); } } // if (!out_of_bounds) { // ### Changed: QRect(left, y, right - left + 1, my + 1); // } y+=8; if (y>bottom) { interlace++; y=top+2; // handle broken GIF with bottom < 3 if (y > bottom) { interlace = 3; y = top + 1; } } } break; case 3: { int i; my = qMin(1, bottom-y); // Don't dup with transparency if (trans_index < 0) { for (i=1; i<=my; i++) { memcpy(image->scanLine(y+i)+left*sizeof(QRgb), image->scanLine(y)+left*sizeof(QRgb), (right-left+1)*sizeof(QRgb)); } } // if (!out_of_bounds) { // ### Changed: QRect(left, y, right - left + 1, my + 1); // } y+=4; if (y>bottom) { interlace++; y=top+1; } } break; case 4: // if (!out_of_bounds) { // ### Changed: QRect(left, y, right - left + 1, 1); // } y+=2; } // Consume bogus extra lines if (y >= sheight) out_of_bounds=true; //y=bottom;}inline QRgb QGIFFormat::color(uchar index) const{ if (index == trans_index || index > ncols) return Q_TRANSPARENT; QRgb *map = lcmap ? localcmap : globalcmap; return map ? map[index] : 0;}//-------------------------------------------------------------------------//-------------------------------------------------------------------------//-------------------------------------------------------------------------QGifHandler::QGifHandler(){ gifFormat = new QGIFFormat; nextDelay = 0; loopCnt = 0; frameNumber = -1; nextSize = QSize();}QGifHandler::~QGifHandler(){ delete gifFormat;}// Does partial decode if necessary, just to see if an image is comingbool QGifHandler::imageIsComing() const{ const int GifChunkSize = 4096; while (!gifFormat->partialNewFrame) { if (buffer.isEmpty()) { buffer += device()->read(GifChunkSize); if (buffer.isEmpty()) break; } int decoded = gifFormat->decode(&lastImage, (const uchar *)buffer.constData(), buffer.size(), &nextDelay, &loopCnt, &nextSize); if (decoded == -1) break; buffer.remove(0, decoded); } return gifFormat->partialNewFrame;}bool QGifHandler::canRead() const{ if (!nextDelay && canRead(device())) { setFormat("gif"); return true; } return imageIsComing();}bool QGifHandler::canRead(QIODevice *device){ if (!device) { qWarning("QGifHandler::canRead() called with no device"); return false; } char head[6]; if (device->peek(head, sizeof(head)) == sizeof(head)) return qstrncmp(head, "GIF87a", 6) == 0 || qstrncmp(head, "GIF89a", 6) == 0; return false;}bool QGifHandler::read(QImage *image){ const int GifChunkSize = 4096; while (!gifFormat->newFrame) { if (buffer.isEmpty()) { buffer += device()->read(GifChunkSize); if (buffer.isEmpty()) break; } int decoded = gifFormat->decode(&lastImage, (const uchar *)buffer.constData(), buffer.size(), &nextDelay, &loopCnt, &nextSize); if (decoded == -1) break; buffer.remove(0, decoded); } if (gifFormat->newFrame || (gifFormat->partialNewFrame && device()->atEnd())) { *image = lastImage; ++frameNumber; gifFormat->newFrame = false; gifFormat->partialNewFrame = false; return true; } return false;}bool QGifHandler::write(const QImage &image){ Q_UNUSED(image); return false;}bool QGifHandler::supportsOption(ImageOption option) const{ return option == Size || option == Animation;}QVariant QGifHandler::option(ImageOption option) const{ if (option == Size) { if (imageIsComing()) return nextSize; } else if (option == Animation) { return true; } return QVariant();}void QGifHandler::setOption(ImageOption option, const QVariant &value){ Q_UNUSED(option); Q_UNUSED(value);}int QGifHandler::nextImageDelay() const{ return nextDelay;}int QGifHandler::imageCount() const{ return 0; // Don't know}int QGifHandler::loopCount() const{ return loopCnt-1; // In GIF, loop count is iteration count, so subtract one}int QGifHandler::currentImageNumber() const{ return frameNumber;}QByteArray QGifHandler::name() const{ return "gif";}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -