PageRenderTime 38ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/src/qt/qtbase/src/gui/image/qgifhandler.cpp

https://gitlab.com/x33n/phantomjs
C++ | 1218 lines | 990 code | 86 blank | 142 comment | 237 complexity | ec511b4b659af22434985ad49bd2fc89 MD5 | raw file
  1. /****************************************************************************
  2. **
  3. ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
  4. ** Contact: http://www.qt-project.org/legal
  5. **
  6. ** This file is part of the plugins of the Qt Toolkit.
  7. **
  8. ** $QT_BEGIN_LICENSE:LGPL$
  9. ** Commercial License Usage
  10. ** Licensees holding valid commercial Qt licenses may use this file in
  11. ** accordance with the commercial license agreement provided with the
  12. ** Software or, alternatively, in accordance with the terms contained in
  13. ** a written agreement between you and Digia. For licensing terms and
  14. ** conditions see http://qt.digia.com/licensing. For further information
  15. ** use the contact form at http://qt.digia.com/contact-us.
  16. **
  17. ** GNU Lesser General Public License Usage
  18. ** Alternatively, this file may be used under the terms of the GNU Lesser
  19. ** General Public License version 2.1 as published by the Free Software
  20. ** Foundation and appearing in the file LICENSE.LGPL included in the
  21. ** packaging of this file. Please review the following information to
  22. ** ensure the GNU Lesser General Public License version 2.1 requirements
  23. ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
  24. **
  25. ** In addition, as a special exception, Digia gives you certain additional
  26. ** rights. These rights are described in the Digia Qt LGPL Exception
  27. ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
  28. **
  29. ** GNU General Public License Usage
  30. ** Alternatively, this file may be used under the terms of the GNU
  31. ** General Public License version 3.0 as published by the Free Software
  32. ** Foundation and appearing in the file LICENSE.GPL included in the
  33. ** packaging of this file. Please review the following information to
  34. ** ensure the GNU General Public License version 3.0 requirements will be
  35. ** met: http://www.gnu.org/copyleft/gpl.html.
  36. **
  37. **
  38. ** $QT_END_LICENSE$
  39. **
  40. ** WARNING:
  41. ** A separate license from Unisys may be required to use the gif
  42. ** reader. See http://www.unisys.com/about__unisys/lzw/
  43. ** for information from Unisys
  44. **
  45. ****************************************************************************/
  46. #include "qgifhandler_p.h"
  47. #include <qimage.h>
  48. #include <qiodevice.h>
  49. #include <qvariant.h>
  50. QT_BEGIN_NAMESPACE
  51. #define Q_TRANSPARENT 0x00ffffff
  52. // avoid going through QImage::scanLine() which calls detach
  53. #define FAST_SCAN_LINE(bits, bpl, y) (bits + (y) * bpl)
  54. /*
  55. Incremental image decoder for GIF image format.
  56. This subclass of QImageFormat decodes GIF format images,
  57. including animated GIFs. Internally in
  58. */
  59. class QGIFFormat {
  60. public:
  61. QGIFFormat();
  62. ~QGIFFormat();
  63. int decode(QImage *image, const uchar* buffer, int length,
  64. int *nextFrameDelay, int *loopCount);
  65. static void scan(QIODevice *device, QVector<QSize> *imageSizes, int *loopCount);
  66. bool newFrame;
  67. bool partialNewFrame;
  68. private:
  69. void fillRect(QImage *image, int x, int y, int w, int h, QRgb col);
  70. inline QRgb color(uchar index) const;
  71. // GIF specific stuff
  72. QRgb* globalcmap;
  73. QRgb* localcmap;
  74. QImage backingstore;
  75. unsigned char hold[16];
  76. bool gif89;
  77. int count;
  78. int ccount;
  79. int expectcount;
  80. enum State {
  81. Header,
  82. LogicalScreenDescriptor,
  83. GlobalColorMap,
  84. LocalColorMap,
  85. Introducer,
  86. ImageDescriptor,
  87. TableImageLZWSize,
  88. ImageDataBlockSize,
  89. ImageDataBlock,
  90. ExtensionLabel,
  91. GraphicControlExtension,
  92. ApplicationExtension,
  93. NetscapeExtensionBlockSize,
  94. NetscapeExtensionBlock,
  95. SkipBlockSize,
  96. SkipBlock,
  97. Done,
  98. Error
  99. } state;
  100. int gncols;
  101. int lncols;
  102. int ncols;
  103. int lzwsize;
  104. bool lcmap;
  105. int swidth, sheight;
  106. int width, height;
  107. int left, top, right, bottom;
  108. enum Disposal { NoDisposal, DoNotChange, RestoreBackground, RestoreImage };
  109. Disposal disposal;
  110. bool disposed;
  111. int trans_index;
  112. bool gcmap;
  113. int bgcol;
  114. int interlace;
  115. int accum;
  116. int bitcount;
  117. enum { max_lzw_bits=12 }; // (poor-compiler's static const int)
  118. int code_size, clear_code, end_code, max_code_size, max_code;
  119. int firstcode, oldcode, incode;
  120. short* table[2];
  121. short* stack;
  122. short *sp;
  123. bool needfirst;
  124. int x, y;
  125. int frame;
  126. bool out_of_bounds;
  127. bool digress;
  128. void nextY(unsigned char *bits, int bpl);
  129. void disposePrevious(QImage *image);
  130. };
  131. /*!
  132. Constructs a QGIFFormat.
  133. */
  134. QGIFFormat::QGIFFormat()
  135. {
  136. globalcmap = 0;
  137. localcmap = 0;
  138. lncols = 0;
  139. gncols = 0;
  140. disposal = NoDisposal;
  141. out_of_bounds = false;
  142. disposed = true;
  143. frame = -1;
  144. state = Header;
  145. count = 0;
  146. lcmap = false;
  147. newFrame = false;
  148. partialNewFrame = false;
  149. table[0] = 0;
  150. table[1] = 0;
  151. stack = 0;
  152. }
  153. /*!
  154. Destroys a QGIFFormat.
  155. */
  156. QGIFFormat::~QGIFFormat()
  157. {
  158. if (globalcmap) delete[] globalcmap;
  159. if (localcmap) delete[] localcmap;
  160. delete [] stack;
  161. }
  162. void QGIFFormat::disposePrevious(QImage *image)
  163. {
  164. if (out_of_bounds) {
  165. // flush anything that survived
  166. // ### Changed: QRect(0, 0, swidth, sheight)
  167. }
  168. // Handle disposal of previous image before processing next one
  169. if (disposed) return;
  170. int l = qMin(swidth-1,left);
  171. int r = qMin(swidth-1,right);
  172. int t = qMin(sheight-1,top);
  173. int b = qMin(sheight-1,bottom);
  174. switch (disposal) {
  175. case NoDisposal:
  176. break;
  177. case DoNotChange:
  178. break;
  179. case RestoreBackground:
  180. if (trans_index>=0) {
  181. // Easy: we use the transparent color
  182. fillRect(image, l, t, r-l+1, b-t+1, Q_TRANSPARENT);
  183. } else if (bgcol>=0) {
  184. // Easy: we use the bgcol given
  185. fillRect(image, l, t, r-l+1, b-t+1, color(bgcol));
  186. } else {
  187. // Impossible: We don't know of a bgcol - use pixel 0
  188. QRgb *bits = (QRgb*)image->bits();
  189. fillRect(image, l, t, r-l+1, b-t+1, bits[0]);
  190. }
  191. // ### Changed: QRect(l, t, r-l+1, b-t+1)
  192. break;
  193. case RestoreImage: {
  194. if (frame >= 0) {
  195. for (int ln=t; ln<=b; ln++) {
  196. memcpy(image->scanLine(ln)+l,
  197. backingstore.scanLine(ln-t),
  198. (r-l+1)*sizeof(QRgb));
  199. }
  200. // ### Changed: QRect(l, t, r-l+1, b-t+1)
  201. }
  202. }
  203. }
  204. disposal = NoDisposal; // Until an extension says otherwise.
  205. disposed = true;
  206. }
  207. /*!
  208. This function decodes some data into image changes.
  209. Returns the number of bytes consumed.
  210. */
  211. int QGIFFormat::decode(QImage *image, const uchar *buffer, int length,
  212. int *nextFrameDelay, int *loopCount)
  213. {
  214. // We are required to state that
  215. // "The Graphics Interchange Format(c) is the Copyright property of
  216. // CompuServe Incorporated. GIF(sm) is a Service Mark property of
  217. // CompuServe Incorporated."
  218. if (!stack) {
  219. stack = new short[(1 << max_lzw_bits) * 4];
  220. table[0] = &stack[(1 << max_lzw_bits) * 2];
  221. table[1] = &stack[(1 << max_lzw_bits) * 3];
  222. }
  223. image->detach();
  224. int bpl = image->bytesPerLine();
  225. unsigned char *bits = image->bits();
  226. #define LM(l, m) (((m)<<8)|l)
  227. digress = false;
  228. const int initial = length;
  229. while (!digress && length) {
  230. length--;
  231. unsigned char ch=*buffer++;
  232. switch (state) {
  233. case Header:
  234. hold[count++]=ch;
  235. if (count==6) {
  236. // Header
  237. gif89=(hold[3]!='8' || hold[4]!='7');
  238. state=LogicalScreenDescriptor;
  239. count=0;
  240. }
  241. break;
  242. case LogicalScreenDescriptor:
  243. hold[count++]=ch;
  244. if (count==7) {
  245. // Logical Screen Descriptor
  246. swidth=LM(hold[0], hold[1]);
  247. sheight=LM(hold[2], hold[3]);
  248. gcmap=!!(hold[4]&0x80);
  249. //UNUSED: bpchan=(((hold[4]&0x70)>>3)+1);
  250. //UNUSED: gcmsortflag=!!(hold[4]&0x08);
  251. gncols=2<<(hold[4]&0x7);
  252. bgcol=(gcmap) ? hold[5] : -1;
  253. //aspect=hold[6] ? double(hold[6]+15)/64.0 : 1.0;
  254. trans_index = -1;
  255. count=0;
  256. ncols=gncols;
  257. if (gcmap) {
  258. ccount=0;
  259. state=GlobalColorMap;
  260. globalcmap = new QRgb[gncols+1]; // +1 for trans_index
  261. globalcmap[gncols] = Q_TRANSPARENT;
  262. } else {
  263. state=Introducer;
  264. }
  265. }
  266. break;
  267. case GlobalColorMap: case LocalColorMap:
  268. hold[count++]=ch;
  269. if (count==3) {
  270. QRgb rgb = qRgb(hold[0], hold[1], hold[2]);
  271. if (state == LocalColorMap) {
  272. if (ccount < lncols)
  273. localcmap[ccount] = rgb;
  274. } else {
  275. globalcmap[ccount] = rgb;
  276. }
  277. if (++ccount >= ncols) {
  278. if (state == LocalColorMap)
  279. state=TableImageLZWSize;
  280. else
  281. state=Introducer;
  282. }
  283. count=0;
  284. }
  285. break;
  286. case Introducer:
  287. hold[count++]=ch;
  288. switch (ch) {
  289. case ',':
  290. state=ImageDescriptor;
  291. break;
  292. case '!':
  293. state=ExtensionLabel;
  294. break;
  295. case ';':
  296. // ### Changed: QRect(0, 0, swidth, sheight)
  297. state=Done;
  298. break;
  299. default:
  300. digress=true;
  301. // Unexpected Introducer - ignore block
  302. state=Error;
  303. }
  304. break;
  305. case ImageDescriptor:
  306. hold[count++]=ch;
  307. if (count==10) {
  308. int newleft=LM(hold[1], hold[2]);
  309. int newtop=LM(hold[3], hold[4]);
  310. int newwidth=LM(hold[5], hold[6]);
  311. int newheight=LM(hold[7], hold[8]);
  312. // disbelieve ridiculous logical screen sizes,
  313. // unless the image frames are also large.
  314. if (swidth/10 > qMax(newwidth,200))
  315. swidth = -1;
  316. if (sheight/10 > qMax(newheight,200))
  317. sheight = -1;
  318. if (swidth <= 0)
  319. swidth = newleft + newwidth;
  320. if (sheight <= 0)
  321. sheight = newtop + newheight;
  322. QImage::Format format = trans_index >= 0 ? QImage::Format_ARGB32 : QImage::Format_RGB32;
  323. if (image->isNull()) {
  324. (*image) = QImage(swidth, sheight, format);
  325. bpl = image->bytesPerLine();
  326. bits = image->bits();
  327. memset(bits, 0, image->byteCount());
  328. }
  329. // Check if the previous attempt to create the image failed. If it
  330. // did then the image is broken and we should give up.
  331. if (image->isNull()) {
  332. state = Error;
  333. return -1;
  334. }
  335. disposePrevious(image);
  336. disposed = false;
  337. left = newleft;
  338. top = newtop;
  339. width = newwidth;
  340. height = newheight;
  341. right=qMax(0, qMin(left+width, swidth)-1);
  342. bottom=qMax(0, qMin(top+height, sheight)-1);
  343. lcmap=!!(hold[9]&0x80);
  344. interlace=!!(hold[9]&0x40);
  345. //bool lcmsortflag=!!(hold[9]&0x20);
  346. lncols=lcmap ? (2<<(hold[9]&0x7)) : 0;
  347. if (lncols) {
  348. if (localcmap)
  349. delete [] localcmap;
  350. localcmap = new QRgb[lncols+1];
  351. localcmap[lncols] = Q_TRANSPARENT;
  352. ncols = lncols;
  353. } else {
  354. ncols = gncols;
  355. }
  356. frame++;
  357. if (frame == 0) {
  358. if (left || top || width<swidth || height<sheight) {
  359. // Not full-size image - erase with bg or transparent
  360. if (trans_index >= 0) {
  361. fillRect(image, 0, 0, swidth, sheight, color(trans_index));
  362. // ### Changed: QRect(0, 0, swidth, sheight)
  363. } else if (bgcol>=0) {
  364. fillRect(image, 0, 0, swidth, sheight, color(bgcol));
  365. // ### Changed: QRect(0, 0, swidth, sheight)
  366. }
  367. }
  368. }
  369. if (disposal == RestoreImage) {
  370. int l = qMin(swidth-1,left);
  371. int r = qMin(swidth-1,right);
  372. int t = qMin(sheight-1,top);
  373. int b = qMin(sheight-1,bottom);
  374. int w = r-l+1;
  375. int h = b-t+1;
  376. if (backingstore.width() < w
  377. || backingstore.height() < h) {
  378. // We just use the backing store as a byte array
  379. backingstore = QImage(qMax(backingstore.width(), w),
  380. qMax(backingstore.height(), h),
  381. QImage::Format_RGB32);
  382. memset(bits, 0, image->byteCount());
  383. }
  384. const int dest_bpl = backingstore.bytesPerLine();
  385. unsigned char *dest_data = backingstore.bits();
  386. for (int ln=0; ln<h; ln++) {
  387. memcpy(FAST_SCAN_LINE(dest_data, dest_bpl, ln),
  388. FAST_SCAN_LINE(bits, bpl, t+ln) + l, w*sizeof(QRgb));
  389. }
  390. }
  391. count=0;
  392. if (lcmap) {
  393. ccount=0;
  394. state=LocalColorMap;
  395. } else {
  396. state=TableImageLZWSize;
  397. }
  398. x = left;
  399. y = top;
  400. accum = 0;
  401. bitcount = 0;
  402. sp = stack;
  403. firstcode = oldcode = 0;
  404. needfirst = true;
  405. out_of_bounds = left>=swidth || y>=sheight;
  406. }
  407. break;
  408. case TableImageLZWSize: {
  409. lzwsize=ch;
  410. if (lzwsize > max_lzw_bits) {
  411. state=Error;
  412. } else {
  413. code_size=lzwsize+1;
  414. clear_code=1<<lzwsize;
  415. end_code=clear_code+1;
  416. max_code_size=2*clear_code;
  417. max_code=clear_code+2;
  418. int i;
  419. for (i=0; i<clear_code; i++) {
  420. table[0][i]=0;
  421. table[1][i]=i;
  422. }
  423. state=ImageDataBlockSize;
  424. }
  425. count=0;
  426. break;
  427. } case ImageDataBlockSize:
  428. expectcount=ch;
  429. if (expectcount) {
  430. state=ImageDataBlock;
  431. } else {
  432. state=Introducer;
  433. digress = true;
  434. newFrame = true;
  435. }
  436. break;
  437. case ImageDataBlock:
  438. count++;
  439. accum|=(ch<<bitcount);
  440. bitcount+=8;
  441. while (bitcount>=code_size && state==ImageDataBlock) {
  442. int code=accum&((1<<code_size)-1);
  443. bitcount-=code_size;
  444. accum>>=code_size;
  445. if (code==clear_code) {
  446. if (!needfirst) {
  447. code_size=lzwsize+1;
  448. max_code_size=2*clear_code;
  449. max_code=clear_code+2;
  450. }
  451. needfirst=true;
  452. } else if (code==end_code) {
  453. bitcount = -32768;
  454. // Left the block end arrive
  455. } else {
  456. if (needfirst) {
  457. firstcode=oldcode=code;
  458. if (!out_of_bounds && image->height() > y && ((frame == 0) || (firstcode != trans_index)))
  459. ((QRgb*)FAST_SCAN_LINE(bits, bpl, y))[x] = color(firstcode);
  460. x++;
  461. if (x>=swidth) out_of_bounds = true;
  462. needfirst=false;
  463. if (x>=left+width) {
  464. x=left;
  465. out_of_bounds = left>=swidth || y>=sheight;
  466. nextY(bits, bpl);
  467. }
  468. } else {
  469. incode=code;
  470. if (code>=max_code) {
  471. *sp++=firstcode;
  472. code=oldcode;
  473. }
  474. while (code>=clear_code+2) {
  475. if (code >= max_code) {
  476. state = Error;
  477. return -1;
  478. }
  479. *sp++=table[1][code];
  480. if (code==table[0][code]) {
  481. state=Error;
  482. return -1;
  483. }
  484. if (sp-stack>=(1<<(max_lzw_bits))*2) {
  485. state=Error;
  486. return -1;
  487. }
  488. code=table[0][code];
  489. }
  490. if (code < 0) {
  491. state = Error;
  492. return -1;
  493. }
  494. *sp++=firstcode=table[1][code];
  495. code=max_code;
  496. if (code<(1<<max_lzw_bits)) {
  497. table[0][code]=oldcode;
  498. table[1][code]=firstcode;
  499. max_code++;
  500. if ((max_code>=max_code_size)
  501. && (max_code_size<(1<<max_lzw_bits)))
  502. {
  503. max_code_size*=2;
  504. code_size++;
  505. }
  506. }
  507. oldcode=incode;
  508. const int h = image->height();
  509. QRgb *line = 0;
  510. if (!out_of_bounds && h > y)
  511. line = (QRgb*)FAST_SCAN_LINE(bits, bpl, y);
  512. while (sp>stack) {
  513. const uchar index = *(--sp);
  514. if (!out_of_bounds && h > y && ((frame == 0) || (index != trans_index))) {
  515. line[x] = color(index);
  516. }
  517. x++;
  518. if (x>=swidth) out_of_bounds = true;
  519. if (x>=left+width) {
  520. x=left;
  521. out_of_bounds = left>=swidth || y>=sheight;
  522. nextY(bits, bpl);
  523. if (!out_of_bounds && h > y)
  524. line = (QRgb*)FAST_SCAN_LINE(bits, bpl, y);
  525. }
  526. }
  527. }
  528. }
  529. }
  530. partialNewFrame = true;
  531. if (count==expectcount) {
  532. count=0;
  533. state=ImageDataBlockSize;
  534. }
  535. break;
  536. case ExtensionLabel:
  537. switch (ch) {
  538. case 0xf9:
  539. state=GraphicControlExtension;
  540. break;
  541. case 0xff:
  542. state=ApplicationExtension;
  543. break;
  544. #if 0
  545. case 0xfe:
  546. state=CommentExtension;
  547. break;
  548. case 0x01:
  549. break;
  550. #endif
  551. default:
  552. state=SkipBlockSize;
  553. }
  554. count=0;
  555. break;
  556. case ApplicationExtension:
  557. if (count<11) hold[count]=ch;
  558. count++;
  559. if (count==hold[0]+1) {
  560. if (qstrncmp((char*)(hold+1), "NETSCAPE", 8)==0) {
  561. // Looping extension
  562. state=NetscapeExtensionBlockSize;
  563. } else {
  564. state=SkipBlockSize;
  565. }
  566. count=0;
  567. }
  568. break;
  569. case NetscapeExtensionBlockSize:
  570. expectcount=ch;
  571. count=0;
  572. if (expectcount) state=NetscapeExtensionBlock;
  573. else state=Introducer;
  574. break;
  575. case NetscapeExtensionBlock:
  576. if (count<3) hold[count]=ch;
  577. count++;
  578. if (count==expectcount) {
  579. *loopCount = hold[1]+hold[2]*256;
  580. state=SkipBlockSize; // Ignore further blocks
  581. }
  582. break;
  583. case GraphicControlExtension:
  584. if (count<5) hold[count]=ch;
  585. count++;
  586. if (count==hold[0]+1) {
  587. disposePrevious(image);
  588. disposal=Disposal((hold[1]>>2)&0x7);
  589. //UNUSED: waitforuser=!!((hold[1]>>1)&0x1);
  590. int delay=count>3 ? LM(hold[2], hold[3]) : 1;
  591. // IE and mozilla use a minimum delay of 10. With the minimum delay of 10
  592. // we are compatible to them and avoid huge loads on the app and xserver.
  593. *nextFrameDelay = (delay < 2 ? 10 : delay) * 10;
  594. bool havetrans=hold[1]&0x1;
  595. trans_index = havetrans ? hold[4] : -1;
  596. count=0;
  597. state=SkipBlockSize;
  598. }
  599. break;
  600. case SkipBlockSize:
  601. expectcount=ch;
  602. count=0;
  603. if (expectcount) state=SkipBlock;
  604. else state=Introducer;
  605. break;
  606. case SkipBlock:
  607. count++;
  608. if (count==expectcount) state=SkipBlockSize;
  609. break;
  610. case Done:
  611. digress=true;
  612. /* Netscape ignores the junk, so we do too.
  613. length++; // Unget
  614. state=Error; // More calls to this is an error
  615. */
  616. break;
  617. case Error:
  618. return -1; // Called again after done.
  619. }
  620. }
  621. return initial-length;
  622. }
  623. /*!
  624. Scans through the data stream defined by \a device and returns the image
  625. sizes found in the stream in the \a imageSizes vector.
  626. */
  627. void QGIFFormat::scan(QIODevice *device, QVector<QSize> *imageSizes, int *loopCount)
  628. {
  629. if (!device)
  630. return;
  631. qint64 oldPos = device->pos();
  632. if (!device->seek(0))
  633. return;
  634. int colorCount = 0;
  635. int localColorCount = 0;
  636. int globalColorCount = 0;
  637. int colorReadCount = 0;
  638. bool localColormap = false;
  639. bool globalColormap = false;
  640. int count = 0;
  641. int blockSize = 0;
  642. int imageWidth = 0;
  643. int imageHeight = 0;
  644. bool done = false;
  645. uchar hold[16];
  646. State state = Header;
  647. const int readBufferSize = 40960; // 40k read buffer
  648. QByteArray readBuffer(device->read(readBufferSize));
  649. if (readBuffer.isEmpty()) {
  650. device->seek(oldPos);
  651. return;
  652. }
  653. // This is a specialized version of the state machine from decode(),
  654. // which doesn't do any image decoding or mallocing, and has an
  655. // optimized way of skipping SkipBlocks, ImageDataBlocks and
  656. // Global/LocalColorMaps.
  657. while (!readBuffer.isEmpty()) {
  658. int length = readBuffer.size();
  659. const uchar *buffer = (const uchar *) readBuffer.constData();
  660. while (!done && length) {
  661. length--;
  662. uchar ch = *buffer++;
  663. switch (state) {
  664. case Header:
  665. hold[count++] = ch;
  666. if (count == 6) {
  667. state = LogicalScreenDescriptor;
  668. count = 0;
  669. }
  670. break;
  671. case LogicalScreenDescriptor:
  672. hold[count++] = ch;
  673. if (count == 7) {
  674. imageWidth = LM(hold[0], hold[1]);
  675. imageHeight = LM(hold[2], hold[3]);
  676. globalColormap = !!(hold[4] & 0x80);
  677. globalColorCount = 2 << (hold[4] & 0x7);
  678. count = 0;
  679. colorCount = globalColorCount;
  680. if (globalColormap) {
  681. int colorTableSize = 3 * globalColorCount;
  682. if (length >= colorTableSize) {
  683. // skip the global color table in one go
  684. length -= colorTableSize;
  685. buffer += colorTableSize;
  686. state = Introducer;
  687. } else {
  688. colorReadCount = 0;
  689. state = GlobalColorMap;
  690. }
  691. } else {
  692. state=Introducer;
  693. }
  694. }
  695. break;
  696. case GlobalColorMap:
  697. case LocalColorMap:
  698. hold[count++] = ch;
  699. if (count == 3) {
  700. if (++colorReadCount >= colorCount) {
  701. if (state == LocalColorMap)
  702. state = TableImageLZWSize;
  703. else
  704. state = Introducer;
  705. }
  706. count = 0;
  707. }
  708. break;
  709. case Introducer:
  710. hold[count++] = ch;
  711. switch (ch) {
  712. case 0x2c:
  713. state = ImageDescriptor;
  714. break;
  715. case 0x21:
  716. state = ExtensionLabel;
  717. break;
  718. case 0x3b:
  719. state = Done;
  720. break;
  721. default:
  722. done = true;
  723. state = Error;
  724. }
  725. break;
  726. case ImageDescriptor:
  727. hold[count++] = ch;
  728. if (count == 10) {
  729. int newLeft = LM(hold[1], hold[2]);
  730. int newTop = LM(hold[3], hold[4]);
  731. int newWidth = LM(hold[5], hold[6]);
  732. int newHeight = LM(hold[7], hold[8]);
  733. if (imageWidth/10 > qMax(newWidth,200))
  734. imageWidth = -1;
  735. if (imageHeight/10 > qMax(newHeight,200))
  736. imageHeight = -1;
  737. if (imageWidth <= 0)
  738. imageWidth = newLeft + newWidth;
  739. if (imageHeight <= 0)
  740. imageHeight = newTop + newHeight;
  741. *imageSizes << QSize(imageWidth, imageHeight);
  742. localColormap = !!(hold[9] & 0x80);
  743. localColorCount = localColormap ? (2 << (hold[9] & 0x7)) : 0;
  744. if (localColorCount)
  745. colorCount = localColorCount;
  746. else
  747. colorCount = globalColorCount;
  748. count = 0;
  749. if (localColormap) {
  750. int colorTableSize = 3 * localColorCount;
  751. if (length >= colorTableSize) {
  752. // skip the local color table in one go
  753. length -= colorTableSize;
  754. buffer += colorTableSize;
  755. state = TableImageLZWSize;
  756. } else {
  757. colorReadCount = 0;
  758. state = LocalColorMap;
  759. }
  760. } else {
  761. state = TableImageLZWSize;
  762. }
  763. }
  764. break;
  765. case TableImageLZWSize:
  766. if (ch > max_lzw_bits)
  767. state = Error;
  768. else
  769. state = ImageDataBlockSize;
  770. count = 0;
  771. break;
  772. case ImageDataBlockSize:
  773. blockSize = ch;
  774. if (blockSize) {
  775. if (length >= blockSize) {
  776. // we can skip the block in one go
  777. length -= blockSize;
  778. buffer += blockSize;
  779. count = 0;
  780. } else {
  781. state = ImageDataBlock;
  782. }
  783. } else {
  784. state = Introducer;
  785. }
  786. break;
  787. case ImageDataBlock:
  788. ++count;
  789. if (count == blockSize) {
  790. count = 0;
  791. state = ImageDataBlockSize;
  792. }
  793. break;
  794. case ExtensionLabel:
  795. switch (ch) {
  796. case 0xf9:
  797. state = GraphicControlExtension;
  798. break;
  799. case 0xff:
  800. state = ApplicationExtension;
  801. break;
  802. default:
  803. state = SkipBlockSize;
  804. }
  805. count = 0;
  806. break;
  807. case ApplicationExtension:
  808. if (count < 11)
  809. hold[count] = ch;
  810. ++count;
  811. if (count == hold[0] + 1) {
  812. if (qstrncmp((char*)(hold+1), "NETSCAPE", 8) == 0)
  813. state=NetscapeExtensionBlockSize;
  814. else
  815. state=SkipBlockSize;
  816. count = 0;
  817. }
  818. break;
  819. case GraphicControlExtension:
  820. if (count < 5)
  821. hold[count] = ch;
  822. ++count;
  823. if (count == hold[0] + 1) {
  824. count = 0;
  825. state = SkipBlockSize;
  826. }
  827. break;
  828. case NetscapeExtensionBlockSize:
  829. blockSize = ch;
  830. count = 0;
  831. if (blockSize)
  832. state = NetscapeExtensionBlock;
  833. else
  834. state = Introducer;
  835. break;
  836. case NetscapeExtensionBlock:
  837. if (count < 3)
  838. hold[count] = ch;
  839. count++;
  840. if (count == blockSize) {
  841. *loopCount = LM(hold[1], hold[2]);
  842. state = SkipBlockSize;
  843. }
  844. break;
  845. case SkipBlockSize:
  846. blockSize = ch;
  847. count = 0;
  848. if (blockSize) {
  849. if (length >= blockSize) {
  850. // we can skip the block in one go
  851. length -= blockSize;
  852. buffer += blockSize;
  853. } else {
  854. state = SkipBlock;
  855. }
  856. } else {
  857. state = Introducer;
  858. }
  859. break;
  860. case SkipBlock:
  861. ++count;
  862. if (count == blockSize)
  863. state = SkipBlockSize;
  864. break;
  865. case Done:
  866. done = true;
  867. break;
  868. case Error:
  869. device->seek(oldPos);
  870. return;
  871. }
  872. }
  873. readBuffer = device->read(readBufferSize);
  874. }
  875. device->seek(oldPos);
  876. return;
  877. }
  878. void QGIFFormat::fillRect(QImage *image, int col, int row, int w, int h, QRgb color)
  879. {
  880. if (w>0) {
  881. for (int j=0; j<h; j++) {
  882. QRgb *line = (QRgb*)image->scanLine(j+row);
  883. for (int i=0; i<w; i++)
  884. *(line+col+i) = color;
  885. }
  886. }
  887. }
  888. void QGIFFormat::nextY(unsigned char *bits, int bpl)
  889. {
  890. int my;
  891. switch (interlace) {
  892. case 0: // Non-interlaced
  893. // if (!out_of_bounds) {
  894. // ### Changed: QRect(left, y, right - left + 1, 1);
  895. // }
  896. y++;
  897. break;
  898. case 1: {
  899. int i;
  900. my = qMin(7, bottom-y);
  901. // Don't dup with transparency
  902. if (trans_index < 0) {
  903. for (i=1; i<=my; i++) {
  904. memcpy(FAST_SCAN_LINE(bits, bpl, y+i)+left*sizeof(QRgb), FAST_SCAN_LINE(bits, bpl, y)+left*sizeof(QRgb),
  905. (right-left+1)*sizeof(QRgb));
  906. }
  907. }
  908. // if (!out_of_bounds) {
  909. // ### Changed: QRect(left, y, right - left + 1, my + 1);
  910. // }
  911. // if (!out_of_bounds)
  912. // qDebug("consumer->changed(QRect(%d, %d, %d, %d))", left, y, right-left+1, my+1);
  913. y+=8;
  914. if (y>bottom) {
  915. interlace++; y=top+4;
  916. if (y > bottom) { // for really broken GIFs with bottom < 5
  917. interlace=2;
  918. y = top + 2;
  919. if (y > bottom) { // for really broken GIF with bottom < 3
  920. interlace = 0;
  921. y = top + 1;
  922. }
  923. }
  924. }
  925. } break;
  926. case 2: {
  927. int i;
  928. my = qMin(3, bottom-y);
  929. // Don't dup with transparency
  930. if (trans_index < 0) {
  931. for (i=1; i<=my; i++) {
  932. memcpy(FAST_SCAN_LINE(bits, bpl, y+i)+left*sizeof(QRgb), FAST_SCAN_LINE(bits, bpl, y)+left*sizeof(QRgb),
  933. (right-left+1)*sizeof(QRgb));
  934. }
  935. }
  936. // if (!out_of_bounds) {
  937. // ### Changed: QRect(left, y, right - left + 1, my + 1);
  938. // }
  939. y+=8;
  940. if (y>bottom) {
  941. interlace++; y=top+2;
  942. // handle broken GIF with bottom < 3
  943. if (y > bottom) {
  944. interlace = 3;
  945. y = top + 1;
  946. }
  947. }
  948. } break;
  949. case 3: {
  950. int i;
  951. my = qMin(1, bottom-y);
  952. // Don't dup with transparency
  953. if (trans_index < 0) {
  954. for (i=1; i<=my; i++) {
  955. memcpy(FAST_SCAN_LINE(bits, bpl, y+i)+left*sizeof(QRgb), FAST_SCAN_LINE(bits, bpl, y)+left*sizeof(QRgb),
  956. (right-left+1)*sizeof(QRgb));
  957. }
  958. }
  959. // if (!out_of_bounds) {
  960. // ### Changed: QRect(left, y, right - left + 1, my + 1);
  961. // }
  962. y+=4;
  963. if (y>bottom) { interlace++; y=top+1; }
  964. } break;
  965. case 4:
  966. // if (!out_of_bounds) {
  967. // ### Changed: QRect(left, y, right - left + 1, 1);
  968. // }
  969. y+=2;
  970. }
  971. // Consume bogus extra lines
  972. if (y >= sheight) out_of_bounds=true; //y=bottom;
  973. }
  974. inline QRgb QGIFFormat::color(uchar index) const
  975. {
  976. if (index > ncols)
  977. return Q_TRANSPARENT;
  978. QRgb *map = lcmap ? localcmap : globalcmap;
  979. QRgb col = map ? map[index] : 0;
  980. return index == trans_index ? col & Q_TRANSPARENT : col;
  981. }
  982. //-------------------------------------------------------------------------
  983. //-------------------------------------------------------------------------
  984. //-------------------------------------------------------------------------
  985. QGifHandler::QGifHandler()
  986. {
  987. gifFormat = new QGIFFormat;
  988. nextDelay = 100;
  989. loopCnt = -1;
  990. frameNumber = -1;
  991. scanIsCached = false;
  992. }
  993. QGifHandler::~QGifHandler()
  994. {
  995. delete gifFormat;
  996. }
  997. // Does partial decode if necessary, just to see if an image is coming
  998. bool QGifHandler::imageIsComing() const
  999. {
  1000. const int GifChunkSize = 4096;
  1001. while (!gifFormat->partialNewFrame) {
  1002. if (buffer.isEmpty()) {
  1003. buffer += device()->read(GifChunkSize);
  1004. if (buffer.isEmpty())
  1005. break;
  1006. }
  1007. int decoded = gifFormat->decode(&lastImage, (const uchar *)buffer.constData(), buffer.size(),
  1008. &nextDelay, &loopCnt);
  1009. if (decoded == -1)
  1010. break;
  1011. buffer.remove(0, decoded);
  1012. }
  1013. return gifFormat->partialNewFrame;
  1014. }
  1015. bool QGifHandler::canRead() const
  1016. {
  1017. if (canRead(device()) || imageIsComing()) {
  1018. setFormat("gif");
  1019. return true;
  1020. }
  1021. return false;
  1022. }
  1023. bool QGifHandler::canRead(QIODevice *device)
  1024. {
  1025. if (!device) {
  1026. qWarning("QGifHandler::canRead() called with no device");
  1027. return false;
  1028. }
  1029. char head[6];
  1030. if (device->peek(head, sizeof(head)) == sizeof(head))
  1031. return qstrncmp(head, "GIF87a", 6) == 0
  1032. || qstrncmp(head, "GIF89a", 6) == 0;
  1033. return false;
  1034. }
  1035. bool QGifHandler::read(QImage *image)
  1036. {
  1037. const int GifChunkSize = 4096;
  1038. while (!gifFormat->newFrame) {
  1039. if (buffer.isEmpty()) {
  1040. buffer += device()->read(GifChunkSize);
  1041. if (buffer.isEmpty())
  1042. break;
  1043. }
  1044. int decoded = gifFormat->decode(&lastImage, (const uchar *)buffer.constData(), buffer.size(),
  1045. &nextDelay, &loopCnt);
  1046. if (decoded == -1)
  1047. break;
  1048. buffer.remove(0, decoded);
  1049. }
  1050. if (gifFormat->newFrame || (gifFormat->partialNewFrame && device()->atEnd())) {
  1051. *image = lastImage;
  1052. ++frameNumber;
  1053. gifFormat->newFrame = false;
  1054. gifFormat->partialNewFrame = false;
  1055. return true;
  1056. }
  1057. return false;
  1058. }
  1059. bool QGifHandler::write(const QImage &image)
  1060. {
  1061. Q_UNUSED(image);
  1062. return false;
  1063. }
  1064. bool QGifHandler::supportsOption(ImageOption option) const
  1065. {
  1066. if (!device() || device()->isSequential())
  1067. return option == Animation;
  1068. else
  1069. return option == Size
  1070. || option == Animation;
  1071. }
  1072. QVariant QGifHandler::option(ImageOption option) const
  1073. {
  1074. if (option == Size) {
  1075. if (!scanIsCached) {
  1076. QGIFFormat::scan(device(), &imageSizes, &loopCnt);
  1077. scanIsCached = true;
  1078. }
  1079. // before the first frame is read, or we have an empty data stream
  1080. if (frameNumber == -1)
  1081. return (imageSizes.count() > 0) ? QVariant(imageSizes.at(0)) : QVariant();
  1082. // after the last frame has been read, the next size is undefined
  1083. if (frameNumber >= imageSizes.count() - 1)
  1084. return QVariant();
  1085. // and the last case: the size of the next frame
  1086. return imageSizes.at(frameNumber + 1);
  1087. } else if (option == Animation) {
  1088. return true;
  1089. }
  1090. return QVariant();
  1091. }
  1092. void QGifHandler::setOption(ImageOption option, const QVariant &value)
  1093. {
  1094. Q_UNUSED(option);
  1095. Q_UNUSED(value);
  1096. }
  1097. int QGifHandler::nextImageDelay() const
  1098. {
  1099. return nextDelay;
  1100. }
  1101. int QGifHandler::imageCount() const
  1102. {
  1103. if (!scanIsCached) {
  1104. QGIFFormat::scan(device(), &imageSizes, &loopCnt);
  1105. scanIsCached = true;
  1106. }
  1107. return imageSizes.count();
  1108. }
  1109. int QGifHandler::loopCount() const
  1110. {
  1111. if (!scanIsCached) {
  1112. QGIFFormat::scan(device(), &imageSizes, &loopCnt);
  1113. scanIsCached = true;
  1114. }
  1115. if (loopCnt == 0)
  1116. return -1;
  1117. else if (loopCnt == -1)
  1118. return 0;
  1119. else
  1120. return loopCnt;
  1121. }
  1122. int QGifHandler::currentImageNumber() const
  1123. {
  1124. return frameNumber;
  1125. }
  1126. QByteArray QGifHandler::name() const
  1127. {
  1128. return "gif";
  1129. }
  1130. QT_END_NAMESPACE