📄 qgifimageformat.cpp
字号:
} right=QMAX( 0, left+width-1); bottom=QMAX(0, top+height-1); lcmap=!!(hold[9]&0x80); interlace=!!(hold[9]&0x40); //bool lcmsortflag=!!(hold[9]&0x20); lncols=lcmap ? (2<<(hold[9]&0x7)) : 0; if (lncols) { if ( localcmap ) delete [] localcmap; localcmap = new QRgb[lncols+1]; localcmap[lncols] = Q_TRANSPARENT; ncols = lncols; } else { ncols = gncols; } frame++; if ( frame == 0 ) { if ( left || top || width!=swidth || height!=sheight ) { // Not full-size image - erase with bg or transparent if ( trans_index >= 0 ) { fillRect(img, 0, 0, swidth, sheight, color(trans_index)); if (consumer) consumer->changed(QRect(0,0,swidth,sheight)); } else if ( bgcol>=0 ) { fillRect(img, 0, 0, swidth, sheight, color(bgcol)); if (consumer) consumer->changed(QRect(0,0,swidth,sheight)); } } } if ( disposal == RestoreImage ) { int l = QMIN(swidth-1,left); int r = QMIN(swidth-1,right); int t = QMIN(sheight-1,top); int b = QMIN(sheight-1,bottom); int w = r-l+1; int h = b-t+1; if (backingstore.width() < w || backingstore.height() < h) { // We just use the backing store as a byte array backingstore.create( QMAX(backingstore.width(), w), QMAX(backingstore.height(), h), 32); memset( img.bits(), 0, img.numBytes() ); } for (int ln=0; ln<h; ln++) { memcpy(backingstore.scanLine(ln), line[t+ln]+l, w*sizeof(QRgb)); } } count=0; if (lcmap) { ccount=0; state=LocalColorMap; } else { state=TableImageLZWSize; } x = left; y = top; accum = 0; bitcount = 0; sp = stack; needfirst = FALSE; out_of_bounds = FALSE; } break; case TableImageLZWSize: { lzwsize=ch; if ( lzwsize > max_lzw_bits ) { state=Error; } else { code_size=lzwsize+1; clear_code=1<<lzwsize; end_code=clear_code+1; max_code_size=2*clear_code; max_code=clear_code+2; int i; for (i=0; i<clear_code && i<(1<<max_lzw_bits); i++) { table[0][i]=0; table[1][i]=i; } for (i=clear_code; i<(1<<max_lzw_bits); i++) { table[0][i]=table[1][i]=0; } state=ImageDataBlockSize; } count=0; break; } case ImageDataBlockSize: expectcount=ch; if (expectcount) { state=ImageDataBlock; } else { if (consumer) { consumer->frameDone(); digress = TRUE; } state=Introducer; } break; 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) { int i; code_size=lzwsize+1; max_code_size=2*clear_code; max_code=clear_code+2; for (i=0; i<clear_code; i++) { table[0][i]=0; table[1][i]=i; } for (i=clear_code; i<(1<<max_lzw_bits); i++) { table[0][i]=table[1][i]=0; } } needfirst=TRUE; } else if (code==end_code) { bitcount = -32768; // Left the block end arrive } else { if (needfirst) { firstcode=oldcode=code; if (!out_of_bounds && line && firstcode!=trans_index) line[y][x] = color(firstcode); x++; if (x>=swidth) out_of_bounds = TRUE; needfirst=FALSE; if (x>right) { x=left; if (out_of_bounds) out_of_bounds = left>=swidth || y>=sheight; nextY(img,consumer); } } else { incode=code; if (code>=max_code) { *sp++=firstcode; code=oldcode; } while (code>=clear_code) { *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; while (sp>stack) { --sp; if (!out_of_bounds && *sp!=trans_index) line[y][x] = color(*sp); x++; if (x>=swidth) out_of_bounds = TRUE; if (x>right) { x=left; if (out_of_bounds) out_of_bounds = left>=swidth || y>=sheight; nextY(img,consumer); } } } } } 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) { int loop = hold[0]+hold[1]*256; // Why if the extension here, if it is supposed to only // play through once? We assume that the creator meant // 0, which is infinite. if (loop == 1) loop = 0; if (consumer) consumer->setLooping(loop); state=SkipBlockSize; // Ignore further blocks } break; case GraphicControlExtension: if (count<5) hold[count]=ch; count++; if (count==hold[0]+1) { disposePrevious( img, consumer ); 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 minumum delay of 10 // we are compatible to them and avoid huge loads on the app and xserver. if ( delay < 10 ) delay = 10; bool havetrans=hold[1]&0x1; trans_index = havetrans ? hold[4] : -1; if (consumer) consumer->setFramePeriod(delay*10); 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& img, int col, int row, int w, int h, QRgb color){ if (w>0) { QRgb** line = (QRgb **)img.jumpTable() + row; for (int j=0; j<h; j++) { for ( int i=0; i<w; i++ ) { *(line[j]+col+i) = color; } } }}void QGIFFormat::nextY(QImage& img, QImageConsumer* consumer){ int my; switch (interlace) { case 0: // Non-interlaced if (consumer && !out_of_bounds) consumer->changed(QRect(left, y, right-left+1, 1)); y++; break; case 1: { int i; my = QMIN(7, bottom-y); if ( trans_index < 0 ) // Don't dup with transparency for (i=1; i<=my; i++) memcpy(img.scanLine(y+i)+left, img.scanLine(y)+left, (right-left+1)*sizeof(QRgb)); if (consumer && !out_of_bounds) consumer->changed(QRect(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); if ( trans_index < 0 ) // Don't dup with transparency for (i=1; i<=my; i++) memcpy(img.scanLine(y+i)+left, img.scanLine(y)+left, (right-left+1)*sizeof(QRgb)); if (consumer && !out_of_bounds) consumer->changed(QRect(left, y, right-left+1, my+1)); y+=8; if (y>bottom) { interlace++; y=top+2; if (y > bottom) { // for really broken GIF with bottom < 3 interlace = 3; y = top + 1; } } } break; case 3: { int i; my = QMIN(1, bottom-y); if ( trans_index < 0 ) // Don't dup with transparency for (i=1; i<=my; i++) memcpy(img.scanLine(y+i)+left, img.scanLine(y)+left, (right-left+1)*sizeof(QRgb)); if (consumer && !out_of_bounds) consumer->changed(QRect(left, y, right-left+1, my+1)); y+=4; if (y>bottom) { interlace++; y=top+1; } } break; case 4: if (consumer && !out_of_bounds) consumer->changed(QRect(left, y, right-left+1, 1)); y+=2; } // Consume bogus extra lines if (y >= sheight) out_of_bounds=TRUE; //y=bottom;}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;}#endif // QT_BUILTIN_GIF_READER#endif // QT_NO_ASYNC_IMAGE_IO
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -