GifDecoder.cs
上传用户:lqb116
上传日期:2014-04-04
资源大小:2712k
文件大小:18k
源码类别:

P2P编程

开发平台:

C#

  1. using System;
  2. using System.Collections;
  3. using System.Drawing;
  4. using System.Drawing.Imaging;
  5. using System.IO;
  6. namespace LanMsg.Gif.Components
  7. {
  8. public class GifDecoder 
  9. {
  10. /**
  11.  * File read status: No errors.
  12.  */
  13. public static readonly int STATUS_OK = 0;
  14. /**
  15.  * File read status: Error decoding file (may be partially decoded)
  16.  */
  17. public static readonly int STATUS_FORMAT_ERROR = 1;
  18. /**
  19.  * File read status: Unable to open source.
  20.  */
  21. public static readonly int STATUS_OPEN_ERROR = 2;
  22. protected Stream inStream;
  23. protected int status;
  24. protected int width; // full image width
  25. protected int height; // full image height
  26. protected bool gctFlag; // global color table used
  27. protected int gctSize; // size of global color table
  28. protected int loopCount = 1; // iterations; 0 = repeat forever
  29. protected int[] gct; // global color table
  30. protected int[] lct; // local color table
  31. protected int[] act; // active color table
  32. protected int bgIndex; // background color index
  33. protected int bgColor; // background color
  34. protected int lastBgColor; // previous bg color
  35. protected int pixelAspect; // pixel aspect ratio
  36. protected bool lctFlag; // local color table flag
  37. protected bool interlace; // interlace flag
  38. protected int lctSize; // local color table size
  39. protected int ix, iy, iw, ih; // current image rectangle
  40. protected Rectangle lastRect; // last image rect
  41. protected Image image; // current frame
  42. protected Bitmap bitmap;
  43. protected Image lastImage; // previous frame
  44. protected byte[] block = new byte[256]; // current data block
  45. protected int blockSize = 0; // block size
  46. // last graphic control extension info
  47. protected int dispose = 0;
  48. // 0=no action; 1=leave in place; 2=restore to bg; 3=restore to prev
  49. protected int lastDispose = 0;
  50. protected bool transparency = false; // use transparent color
  51. protected int delay = 0; // delay in milliseconds
  52. protected int transIndex; // transparent color index
  53. protected static readonly int MaxStackSize = 4096;
  54. // max decoder pixel stack size
  55. // LZW decoder working arrays
  56. protected short[] prefix;
  57. protected byte[] suffix;
  58. protected byte[] pixelStack;
  59. protected byte[] pixels;
  60. protected ArrayList frames; // frames read from current file
  61. protected int frameCount;
  62. public class GifFrame 
  63. {
  64. public GifFrame( Image im, int del) 
  65. {
  66. image = im;
  67. delay = del;
  68. }
  69. public Image image;
  70. public int delay;
  71. }
  72.  
  73. /**
  74.  * Gets display duration for specified frame.
  75.  *
  76.  * @param n int index of frame
  77.  * @return delay in milliseconds
  78.  */
  79. public int GetDelay(int n) 
  80. {
  81. //
  82. delay = -1;
  83. if ((n >= 0) && (n < frameCount)) 
  84. {
  85. delay = ((GifFrame) frames[n]).delay;
  86. }
  87. return delay;
  88. }
  89. /**
  90.  * Gets the number of frames read from file.
  91.  * @return frame count
  92.  */
  93. public int GetFrameCount() 
  94. {
  95. return frameCount;
  96. }
  97. /**
  98.  * Gets the first (or only) image read.
  99.  *
  100.  * @return BufferedImage containing first frame, or null if none.
  101.  */
  102. public Image GetImage() 
  103. {
  104. return GetFrame(0);
  105. }
  106. /**
  107.  * Gets the "Netscape" iteration count, if any.
  108.  * A count of 0 means repeat indefinitiely.
  109.  *
  110.  * @return iteration count if one was specified, else 1.
  111.  */
  112. public int GetLoopCount() 
  113. {
  114. return loopCount;
  115. }
  116. /**
  117.  * Creates new frame image from current data (and previous
  118.  * frames as specified by their disposition codes).
  119.  */
  120. int [] GetPixels( Bitmap bitmap )
  121. {
  122. int [] pixels = new int [ 3 * image.Width * image.Height ];
  123. int count = 0;
  124. for (int th = 0; th < image.Height; th++)
  125. {
  126. for (int tw = 0; tw < image.Width; tw++)
  127. {
  128. Color color = bitmap.GetPixel(tw, th);
  129. pixels[count] = color.R;
  130. count++;
  131. pixels[count] = color.G;
  132. count++;
  133. pixels[count] = color.B;
  134. count++;
  135. }
  136. }
  137. return pixels;
  138. }
  139. void SetPixels( int [] pixels )
  140. {
  141. int count = 0;
  142. for (int th = 0; th < image.Height; th++)
  143. {
  144. for (int tw = 0; tw < image.Width; tw++)
  145. {
  146. Color color = Color.FromArgb( pixels[count++] );
  147. bitmap.SetPixel( tw, th, color );
  148. }
  149. }
  150. }
  151. protected void SetPixels() 
  152. {
  153. // expose destination image's pixels as int array
  154. // int[] dest =
  155. // (( int ) image.getRaster().getDataBuffer()).getData();
  156. int[] dest = GetPixels( bitmap );
  157. // fill in starting image contents based on last image's dispose code
  158. if (lastDispose > 0) 
  159. {
  160. if (lastDispose == 3) 
  161. {
  162. // use image before last
  163. int n = frameCount - 2;
  164. if (n > 0) 
  165. {
  166. lastImage = GetFrame(n - 1);
  167. else 
  168. {
  169. lastImage = null;
  170. }
  171. }
  172. if (lastImage != null) 
  173. {
  174. // int[] prev =
  175. // ((DataBufferInt) lastImage.getRaster().getDataBuffer()).getData();
  176. int[] prev = GetPixels( new Bitmap( lastImage ) );
  177. Array.Copy(prev, 0, dest, 0, width * height);
  178. // copy pixels
  179. if (lastDispose == 2) 
  180. {
  181. // fill last image rect area with background color
  182. Graphics g = Graphics.FromImage( image );
  183. Color c = Color.Empty;
  184. if (transparency) 
  185. {
  186. c = Color.FromArgb( 0, 0, 0, 0 );  // assume background is transparent
  187. else 
  188. {
  189. c = Color.FromArgb( lastBgColor ) ;
  190. // c = new Color(lastBgColor); // use given background color
  191. }
  192. Brush brush = new SolidBrush( c );
  193. g.FillRectangle( brush, lastRect );
  194. brush.Dispose();
  195. g.Dispose();
  196. }
  197. }
  198. }
  199. // copy each source line to the appropriate place in the destination
  200. int pass = 1;
  201. int inc = 8;
  202. int iline = 0;
  203. for (int i = 0; i < ih; i++) 
  204. {
  205. int line = i;
  206. if (interlace) 
  207. {
  208. if (iline >= ih) 
  209. {
  210. pass++;
  211. switch (pass) 
  212. {
  213. case 2 :
  214. iline = 4;
  215. break;
  216. case 3 :
  217. iline = 2;
  218. inc = 4;
  219. break;
  220. case 4 :
  221. iline = 1;
  222. inc = 2;
  223. break;
  224. }
  225. }
  226. line = iline;
  227. iline += inc;
  228. }
  229. line += iy;
  230. if (line < height) 
  231. {
  232. int k = line * width;
  233. int dx = k + ix; // start of line in dest
  234. int dlim = dx + iw; // end of dest line
  235. if ((k + width) < dlim) 
  236. {
  237. dlim = k + width; // past dest edge
  238. }
  239. int sx = i * iw; // start of line in source
  240. while (dx < dlim) 
  241. {
  242. // map color and insert in destination
  243. int index = ((int) pixels[sx++]) & 0xff;
  244. int c = act[index];
  245. if (c != 0) 
  246. {
  247. dest[dx] = c;
  248. }
  249. dx++;
  250. }
  251. }
  252. }
  253. SetPixels( dest );
  254. }
  255. /**
  256.  * Gets the image contents of frame n.
  257.  *
  258.  * @return BufferedImage representation of frame, or null if n is invalid.
  259.  */
  260. public Image GetFrame(int n) 
  261. {
  262. Image im = null;
  263. if ((n >= 0) && (n < frameCount)) 
  264. {
  265. im = ((GifFrame) frames[n] ).image;
  266. }
  267. return im;
  268. }
  269. /**
  270.  * Gets image size.
  271.  *
  272.  * @return GIF image dimensions
  273.  */
  274. public Size GetFrameSize() 
  275. {
  276. return new Size(width, height);
  277. }
  278. /**
  279.  * Reads GIF image from stream
  280.  *
  281.  * @param BufferedInputStream containing GIF file.
  282.  * @return read status code (0 = no errors)
  283.  */
  284. public int Read( Stream inStream ) 
  285. {
  286. Init();
  287. if ( inStream != null) 
  288. {
  289. this.inStream = inStream;
  290. ReadHeader();
  291. if (!Error()) 
  292. {
  293. ReadContents();
  294. if (frameCount < 0) 
  295. {
  296. status = STATUS_FORMAT_ERROR;
  297. }
  298. }
  299. inStream.Close();
  300. else 
  301. {
  302. status = STATUS_OPEN_ERROR;
  303. }
  304. return status;
  305. }
  306. /**
  307.  * Reads GIF file from specified file/URL source  
  308.  * (URL assumed if name contains ":/" or "file:")
  309.  *
  310.  * @param name String containing source
  311.  * @return read status code (0 = no errors)
  312.  */
  313. public int Read(String name) 
  314. {
  315. status = STATUS_OK;
  316. try 
  317. {
  318. name = name.Trim().ToLower();
  319. status = Read( new FileInfo( name ).OpenRead() );
  320. catch (IOException e) 
  321. {
  322. status = STATUS_OPEN_ERROR;
  323. }
  324. return status;
  325. }
  326. /**
  327.  * Decodes LZW image data into pixel array.
  328.  * Adapted from John Cristy's ImageMagick.
  329.  */
  330. protected void DecodeImageData() 
  331. {
  332. int NullCode = -1;
  333. int npix = iw * ih;
  334. int available, 
  335. clear,
  336. code_mask,
  337. code_size,
  338. end_of_information,
  339. in_code,
  340. old_code,
  341. bits,
  342. code,
  343. count,
  344. i,
  345. datum,
  346. data_size,
  347. first,
  348. top,
  349. bi,
  350. pi;
  351. if ((pixels == null) || (pixels.Length < npix)) 
  352. {
  353. pixels = new byte[npix]; // allocate new pixel array
  354. }
  355. if (prefix == null) prefix = new short[MaxStackSize];
  356. if (suffix == null) suffix = new byte[MaxStackSize];
  357. if (pixelStack == null) pixelStack = new byte[MaxStackSize + 1];
  358. //  Initialize GIF data stream decoder.
  359. data_size = Read();
  360. clear = 1 << data_size;
  361. end_of_information = clear + 1;
  362. available = clear + 2;
  363. old_code = NullCode;
  364. code_size = data_size + 1;
  365. code_mask = (1 << code_size) - 1;
  366. for (code = 0; code < clear; code++) 
  367. {
  368. prefix[code] = 0;
  369. suffix[code] = (byte) code;
  370. }
  371. //  Decode GIF pixel stream.
  372. datum = bits = count = first = top = pi = bi = 0;
  373. for (i = 0; i < npix;) 
  374. {
  375. if (top == 0) 
  376. {
  377. if (bits < code_size) 
  378. {
  379. //  Load bytes until there are enough bits for a code.
  380. if (count == 0) 
  381. {
  382. // Read a new data block.
  383. count = ReadBlock();
  384. if (count <= 0)
  385. break;
  386. bi = 0;
  387. }
  388. datum += (((int) block[bi]) & 0xff) << bits;
  389. bits += 8;
  390. bi++;
  391. count--;
  392. continue;
  393. }
  394. //  Get the next code.
  395. code = datum & code_mask;
  396. datum >>= code_size;
  397. bits -= code_size;
  398. //  Interpret the code
  399. if ((code > available) || (code == end_of_information))
  400. break;
  401. if (code == clear) 
  402. {
  403. //  Reset decoder.
  404. code_size = data_size + 1;
  405. code_mask = (1 << code_size) - 1;
  406. available = clear + 2;
  407. old_code = NullCode;
  408. continue;
  409. }
  410. if (old_code == NullCode) 
  411. {
  412. pixelStack[top++] = suffix[code];
  413. old_code = code;
  414. first = code;
  415. continue;
  416. }
  417. in_code = code;
  418. if (code == available) 
  419. {
  420. pixelStack[top++] = (byte) first;
  421. code = old_code;
  422. }
  423. while (code > clear) 
  424. {
  425. pixelStack[top++] = suffix[code];
  426. code = prefix[code];
  427. }
  428. first = ((int) suffix[code]) & 0xff;
  429. //  Add a new string to the string table,
  430. if (available >= MaxStackSize)
  431. break;
  432. pixelStack[top++] = (byte) first;
  433. prefix[available] = (short) old_code;
  434. suffix[available] = (byte) first;
  435. available++;
  436. if (((available & code_mask) == 0)
  437. && (available < MaxStackSize)) 
  438. {
  439. code_size++;
  440. code_mask += available;
  441. }
  442. old_code = in_code;
  443. }
  444. //  Pop a pixel off the pixel stack.
  445. top--;
  446. pixels[pi++] = pixelStack[top];
  447. i++;
  448. }
  449. for (i = pi; i < npix; i++) 
  450. {
  451. pixels[i] = 0; // clear missing pixels
  452. }
  453. }
  454. /**
  455.  * Returns true if an error was encountered during reading/decoding
  456.  */
  457. protected bool Error() 
  458. {
  459. return status != STATUS_OK;
  460. }
  461. /**
  462.  * Initializes or re-initializes reader
  463.  */
  464. protected void Init() 
  465. {
  466. status = STATUS_OK;
  467. frameCount = 0;
  468. frames = new ArrayList();
  469. gct = null;
  470. lct = null;
  471. }
  472. /**
  473.  * Reads a single byte from the input stream.
  474.  */
  475. protected int Read() 
  476. {
  477. int curByte = 0;
  478. try 
  479. {
  480. curByte = inStream.ReadByte();
  481. catch (IOException e) 
  482. {
  483. status = STATUS_FORMAT_ERROR;
  484. }
  485. return curByte;
  486. }
  487. /**
  488.  * Reads next variable length block from input.
  489.  *
  490.  * @return number of bytes stored in "buffer"
  491.  */
  492. protected int ReadBlock() 
  493. {
  494. blockSize = Read();
  495. int n = 0;
  496. if (blockSize > 0) 
  497. {
  498. try 
  499. {
  500. int count = 0;
  501. while (n < blockSize) 
  502. {
  503. count = inStream.Read(block, n, blockSize - n);
  504. if (count == -1) 
  505. break;
  506. n += count;
  507. }
  508. catch (IOException e) 
  509. {
  510. }
  511. if (n < blockSize) 
  512. {
  513. status = STATUS_FORMAT_ERROR;
  514. }
  515. }
  516. return n;
  517. }
  518. /**
  519.  * Reads color table as 256 RGB integer values
  520.  *
  521.  * @param ncolors int number of colors to read
  522.  * @return int array containing 256 colors (packed ARGB with full alpha)
  523.  */
  524. protected int[] ReadColorTable(int ncolors) 
  525. {
  526. int nbytes = 3 * ncolors;
  527. int[] tab = null;
  528. byte[] c = new byte[nbytes];
  529. int n = 0;
  530. try 
  531. {
  532. n = inStream.Read(c, 0, c.Length );
  533. catch (IOException e) 
  534. {
  535. }
  536. if (n < nbytes) 
  537. {
  538. status = STATUS_FORMAT_ERROR;
  539. else 
  540. {
  541. tab = new int[256]; // max size to avoid bounds checks
  542. int i = 0;
  543. int j = 0;
  544. while (i < ncolors) 
  545. {
  546. int r = ((int) c[j++]) & 0xff;
  547. int g = ((int) c[j++]) & 0xff;
  548. int b = ((int) c[j++]) & 0xff;
  549. tab[i++] = ( int ) ( 0xff000000 | (r << 16) | (g << 8) | b );
  550. }
  551. }
  552. return tab;
  553. }
  554. /**
  555.  * Main file parser.  Reads GIF content blocks.
  556.  */
  557. protected void ReadContents() 
  558. {
  559. // read GIF file content blocks
  560. bool done = false;
  561. while (!(done || Error())) 
  562. {
  563. int code = Read();
  564. switch (code) 
  565. {
  566. case 0x2C : // image separator
  567. ReadImage();
  568. break;
  569. case 0x21 : // extension
  570. code = Read();
  571. switch (code) 
  572. {
  573. case 0xf9 : // graphics control extension
  574. ReadGraphicControlExt();
  575. break;
  576. case 0xff : // application extension
  577. ReadBlock();
  578. String app = "";
  579. for (int i = 0; i < 11; i++) 
  580. {
  581. app += (char) block[i];
  582. }
  583. if (app.Equals("NETSCAPE2.0")) 
  584. {
  585. ReadNetscapeExt();
  586. }
  587. else
  588. Skip(); // don't care
  589. break;
  590. default : // uninteresting extension
  591. Skip();
  592. break;
  593. }
  594. break;
  595. case 0x3b : // terminator
  596. done = true;
  597. break;
  598. case 0x00 : // bad byte, but keep going and see what happens
  599. break;
  600. default :
  601. status = STATUS_FORMAT_ERROR;
  602. break;
  603. }
  604. }
  605. }
  606. /**
  607.  * Reads Graphics Control Extension values
  608.  */
  609. protected void ReadGraphicControlExt() 
  610. {
  611. Read(); // block size
  612. int packed = Read(); // packed fields
  613. dispose = (packed & 0x1c) >> 2; // disposal method
  614. if (dispose == 0) 
  615. {
  616. dispose = 1; // elect to keep old image if discretionary
  617. }
  618. transparency = (packed & 1) != 0;
  619. delay = ReadShort() * 10; // delay in milliseconds
  620. transIndex = Read(); // transparent color index
  621. Read(); // block terminator
  622. }
  623. /**
  624.  * Reads GIF file header information.
  625.  */
  626. protected void ReadHeader() 
  627. {
  628. String id = "";
  629. for (int i = 0; i < 6; i++) 
  630. {
  631. id += (char) Read();
  632. }
  633. if (!id.StartsWith("GIF")) 
  634. {
  635. status = STATUS_FORMAT_ERROR;
  636. return;
  637. }
  638. ReadLSD();
  639. if (gctFlag && !Error()) 
  640. {
  641. gct = ReadColorTable(gctSize);
  642. bgColor = gct[bgIndex];
  643. }
  644. }
  645. /**
  646.  * Reads next frame image
  647.  */
  648. protected void ReadImage() 
  649. {
  650. ix = ReadShort(); // (sub)image position & size
  651. iy = ReadShort();
  652. iw = ReadShort();
  653. ih = ReadShort();
  654. int packed = Read();
  655. lctFlag = (packed & 0x80) != 0; // 1 - local color table flag
  656. interlace = (packed & 0x40) != 0; // 2 - interlace flag
  657. // 3 - sort flag
  658. // 4-5 - reserved
  659. lctSize = 2 << (packed & 7); // 6-8 - local color table size
  660. if (lctFlag) 
  661. {
  662. lct = ReadColorTable(lctSize); // read table
  663. act = lct; // make local table active
  664. else 
  665. {
  666. act = gct; // make global table active
  667. if (bgIndex == transIndex)
  668. bgColor = 0;
  669. }
  670. int save = 0;
  671. if (transparency) 
  672. {
  673. save = act[transIndex];
  674. act[transIndex] = 0; // set transparent color if specified
  675. }
  676. if (act == null) 
  677. {
  678. status = STATUS_FORMAT_ERROR; // no color table defined
  679. }
  680. if (Error()) return;
  681. DecodeImageData(); // decode pixel data
  682. Skip();
  683. if (Error()) return;
  684. frameCount++;
  685. // create new image to receive frame data
  686. // image =
  687. // new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE);
  688. bitmap = new Bitmap( width, height );
  689. image = bitmap;
  690. SetPixels(); // transfer pixel data to image
  691. frames.Add(new GifFrame(bitmap, delay)); // add image to frame list
  692. if (transparency) 
  693. {
  694. act[transIndex] = save;
  695. }
  696. ResetFrame();
  697. }
  698. /**
  699.  * Reads Logical Screen Descriptor
  700.  */
  701. protected void ReadLSD() 
  702. {
  703. // logical screen size
  704. width = ReadShort();
  705. height = ReadShort();
  706. // packed fields
  707. int packed = Read();
  708. gctFlag = (packed & 0x80) != 0; // 1   : global color table flag
  709. // 2-4 : color resolution
  710. // 5   : gct sort flag
  711. gctSize = 2 << (packed & 7); // 6-8 : gct size
  712. bgIndex = Read(); // background color index
  713. pixelAspect = Read(); // pixel aspect ratio
  714. }
  715. /**
  716.  * Reads Netscape extenstion to obtain iteration count
  717.  */
  718. protected void ReadNetscapeExt() 
  719. {
  720. do 
  721. {
  722. ReadBlock();
  723. if (block[0] == 1) 
  724. {
  725. // loop count sub-block
  726. int b1 = ((int) block[1]) & 0xff;
  727. int b2 = ((int) block[2]) & 0xff;
  728. loopCount = (b2 << 8) | b1;
  729. }
  730. } while ((blockSize > 0) && !Error());
  731. }
  732. /**
  733.  * Reads next 16-bit value, LSB first
  734.  */
  735. protected int ReadShort() 
  736. {
  737. // read 16-bit value, LSB first
  738. return Read() | (Read() << 8);
  739. }
  740. /**
  741.  * Resets frame state for reading next image.
  742.  */
  743. protected void ResetFrame() 
  744. {
  745. lastDispose = dispose;
  746. lastRect = new Rectangle(ix, iy, iw, ih);
  747. lastImage = image;
  748. lastBgColor = bgColor;
  749. // int dispose = 0;
  750. bool transparency = false;
  751. int delay = 0;
  752. lct = null;
  753. }
  754. /**
  755.  * Skips variable length blocks up to and including
  756.  * next zero length block.
  757.  */
  758. protected void Skip() 
  759. {
  760. do 
  761. {
  762. ReadBlock();
  763. } while ((blockSize > 0) && !Error());
  764. }
  765. }
  766. }