GifDecoder.java 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  1. package eu.mjdev.desktop.helpers.gif;
  2. import java.net.*;
  3. import java.io.*;
  4. import java.util.*;
  5. import java.awt.*;
  6. import java.awt.image.*;
  7. @SuppressWarnings("ALL")
  8. public class GifDecoder {
  9. public static final int STATUS_OK = 0;
  10. public static final int STATUS_FORMAT_ERROR = 1;
  11. public static final int STATUS_OPEN_ERROR = 2;
  12. protected BufferedInputStream in;
  13. protected int status;
  14. protected int width;
  15. protected int height;
  16. protected boolean gctFlag;
  17. protected int gctSize;
  18. protected int loopCount = 1;
  19. protected int[] gct;
  20. protected int[] lct;
  21. protected int[] act;
  22. protected int bgIndex;
  23. protected int bgColor;
  24. protected int lastBgColor;
  25. protected int pixelAspect;
  26. protected boolean lctFlag;
  27. protected boolean interlace;
  28. protected int lctSize;
  29. protected int ix, iy, iw, ih;
  30. protected Rectangle lastRect;
  31. protected BufferedImage image;
  32. protected BufferedImage lastImage;
  33. protected byte[] block = new byte[256];
  34. protected int blockSize = 0;
  35. protected int dispose = 0;
  36. protected int lastDispose = 0;
  37. protected boolean transparency = false;
  38. protected int delay = 0;
  39. protected int transIndex;
  40. protected static final int MaxStackSize = 4096;
  41. protected short[] prefix;
  42. protected byte[] suffix;
  43. protected byte[] pixelStack;
  44. protected byte[] pixels;
  45. protected ArrayList frames;
  46. protected int frameCount;
  47. static class GifFrame {
  48. public GifFrame(BufferedImage im, int del) {
  49. image = im;
  50. delay = del;
  51. }
  52. public BufferedImage image;
  53. public int delay;
  54. }
  55. public int getDelay(int n) {
  56. delay = -1;
  57. if ((n >= 0) && (n < frameCount)) {
  58. delay = ((GifFrame) frames.get(n)).delay;
  59. }
  60. return delay;
  61. }
  62. public int getFrameCount() {
  63. return frameCount;
  64. }
  65. public BufferedImage getImage() {
  66. return getFrame(0);
  67. }
  68. public int getLoopCount() {
  69. return loopCount;
  70. }
  71. protected void setPixels() {
  72. int[] dest = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
  73. if (lastDispose > 0) {
  74. if (lastDispose == 3) {
  75. int n = frameCount - 2;
  76. if (n > 0) {
  77. lastImage = getFrame(n - 1);
  78. } else {
  79. lastImage = null;
  80. }
  81. }
  82. if (lastImage != null) {
  83. int[] prev = ((DataBufferInt) lastImage.getRaster().getDataBuffer()).getData();
  84. System.arraycopy(prev, 0, dest, 0, width * height);
  85. if (lastDispose == 2) {
  86. Graphics2D g = image.createGraphics();
  87. Color c;
  88. if (transparency) {
  89. c = new Color(0, 0, 0, 0);
  90. } else {
  91. c = new Color(lastBgColor);
  92. }
  93. g.setColor(c);
  94. g.setComposite(AlphaComposite.Src);
  95. g.fill(lastRect);
  96. g.dispose();
  97. }
  98. }
  99. }
  100. int pass = 1;
  101. int inc = 8;
  102. int iline = 0;
  103. for (int i = 0; i < ih; i++) {
  104. int line = i;
  105. if (interlace) {
  106. if (iline >= ih) {
  107. pass++;
  108. switch (pass) {
  109. case 2:
  110. iline = 4;
  111. break;
  112. case 3:
  113. iline = 2;
  114. inc = 4;
  115. break;
  116. case 4:
  117. iline = 1;
  118. inc = 2;
  119. }
  120. }
  121. line = iline;
  122. iline += inc;
  123. }
  124. line += iy;
  125. if (line < height) {
  126. int k = line * width;
  127. int dx = k + ix;
  128. int dlim = dx + iw;
  129. if ((k + width) < dlim) {
  130. dlim = k + width;
  131. }
  132. int sx = i * iw;
  133. while (dx < dlim) {
  134. int index = ((int) pixels[sx++]) & 0xff;
  135. int c = act[index];
  136. if (c != 0) {
  137. dest[dx] = c;
  138. }
  139. dx++;
  140. }
  141. }
  142. }
  143. }
  144. public BufferedImage getFrame(int n) {
  145. BufferedImage im = null;
  146. if ((n >= 0) && (n < frameCount)) {
  147. im = ((GifFrame) frames.get(n)).image;
  148. }
  149. return im;
  150. }
  151. public Dimension getFrameSize() {
  152. return new Dimension(width, height);
  153. }
  154. public int read(BufferedInputStream is) {
  155. init();
  156. if (is != null) {
  157. in = is;
  158. readHeader();
  159. if (!err()) {
  160. readContents();
  161. if (frameCount < 0) {
  162. status = STATUS_FORMAT_ERROR;
  163. }
  164. }
  165. } else {
  166. status = STATUS_OPEN_ERROR;
  167. }
  168. try {
  169. if (is != null) is.close();
  170. } catch (IOException e) {
  171. // no op
  172. }
  173. return status;
  174. }
  175. public int read(InputStream is) {
  176. init();
  177. if (is != null) {
  178. if (!(is instanceof BufferedInputStream))
  179. is = new BufferedInputStream(is);
  180. in = (BufferedInputStream) is;
  181. readHeader();
  182. if (!err()) {
  183. readContents();
  184. if (frameCount < 0) {
  185. status = STATUS_FORMAT_ERROR;
  186. }
  187. }
  188. } else {
  189. status = STATUS_OPEN_ERROR;
  190. }
  191. try {
  192. if(is != null) is.close();
  193. } catch (IOException e) {
  194. // no op
  195. }
  196. return status;
  197. }
  198. public int read(String name) {
  199. status = STATUS_OK;
  200. try {
  201. name = name.trim().toLowerCase();
  202. //noinspection IndexOfReplaceableByContains
  203. if ((name.indexOf("file:") >= 0) || (name.indexOf(":/") > 0)) {
  204. URL url = new URL(name);
  205. in = new BufferedInputStream(url.openStream());
  206. } else {
  207. in = new BufferedInputStream(new FileInputStream(name));
  208. }
  209. status = read(in);
  210. } catch (IOException e) {
  211. status = STATUS_OPEN_ERROR;
  212. }
  213. return status;
  214. }
  215. protected void decodeImageData() {
  216. int NullCode = -1;
  217. int npix = iw * ih;
  218. int available,
  219. clear,
  220. code_mask,
  221. code_size,
  222. end_of_information,
  223. in_code,
  224. old_code,
  225. bits,
  226. code,
  227. count,
  228. i,
  229. datum,
  230. data_size,
  231. first,
  232. top,
  233. bi,
  234. pi;
  235. if ((pixels == null) || (pixels.length < npix)) {
  236. pixels = new byte[npix]; // allocate new pixel array
  237. }
  238. if (prefix == null) prefix = new short[MaxStackSize];
  239. if (suffix == null) suffix = new byte[MaxStackSize];
  240. if (pixelStack == null) pixelStack = new byte[MaxStackSize + 1];
  241. data_size = read();
  242. clear = 1 << data_size;
  243. end_of_information = clear + 1;
  244. available = clear + 2;
  245. old_code = NullCode;
  246. code_size = data_size + 1;
  247. code_mask = (1 << code_size) - 1;
  248. for (code = 0; code < clear; code++) {
  249. prefix[code] = 0;
  250. suffix[code] = (byte) code;
  251. }
  252. datum = bits = count = first = top = pi = bi = 0;
  253. for (i = 0; i < npix; ) {
  254. if (top == 0) {
  255. if (bits < code_size) {
  256. if (count == 0) {
  257. count = readBlock();
  258. if (count <= 0)
  259. break;
  260. bi = 0;
  261. }
  262. datum += (((int) block[bi]) & 0xff) << bits;
  263. bits += 8;
  264. bi++;
  265. count--;
  266. continue;
  267. }
  268. code = datum & code_mask;
  269. datum >>= code_size;
  270. bits -= code_size;
  271. if ((code > available) || (code == end_of_information))
  272. break;
  273. if (code == clear) {
  274. code_size = data_size + 1;
  275. code_mask = (1 << code_size) - 1;
  276. available = clear + 2;
  277. old_code = NullCode;
  278. continue;
  279. }
  280. if (old_code == NullCode) {
  281. pixelStack[top++] = suffix[code];
  282. old_code = code;
  283. first = code;
  284. continue;
  285. }
  286. in_code = code;
  287. if (code == available) {
  288. pixelStack[top++] = (byte) first;
  289. code = old_code;
  290. }
  291. while (code > clear) {
  292. pixelStack[top++] = suffix[code];
  293. code = prefix[code];
  294. }
  295. first = ((int) suffix[code]) & 0xff;
  296. if (available >= MaxStackSize) {
  297. pixelStack[top++] = (byte) first;
  298. continue;
  299. }
  300. pixelStack[top++] = (byte) first;
  301. prefix[available] = (short) old_code;
  302. suffix[available] = (byte) first;
  303. available++;
  304. if (((available & code_mask) == 0)
  305. && (available < MaxStackSize)) {
  306. code_size++;
  307. code_mask += available;
  308. }
  309. old_code = in_code;
  310. }
  311. top--;
  312. pixels[pi++] = pixelStack[top];
  313. i++;
  314. }
  315. for (i = pi; i < npix; i++) {
  316. pixels[i] = 0;
  317. }
  318. }
  319. protected boolean err() {
  320. return status != STATUS_OK;
  321. }
  322. protected void init() {
  323. status = STATUS_OK;
  324. frameCount = 0;
  325. frames = new ArrayList();
  326. gct = null;
  327. lct = null;
  328. }
  329. protected int read() {
  330. int curByte = 0;
  331. try {
  332. curByte = in.read();
  333. } catch (IOException e) {
  334. status = STATUS_FORMAT_ERROR;
  335. }
  336. return curByte;
  337. }
  338. protected int readBlock() {
  339. blockSize = read();
  340. int n = 0;
  341. if (blockSize > 0) {
  342. try {
  343. int count;
  344. while (n < blockSize) {
  345. count = in.read(block, n, blockSize - n);
  346. if (count == -1)
  347. break;
  348. n += count;
  349. }
  350. } catch (IOException e) {
  351. // no op
  352. }
  353. if (n < blockSize) {
  354. status = STATUS_FORMAT_ERROR;
  355. }
  356. }
  357. return n;
  358. }
  359. protected int[] readColorTable(int ncolors) {
  360. int nbytes = 3 * ncolors;
  361. int[] tab = null;
  362. byte[] c = new byte[nbytes];
  363. int n = 0;
  364. try {
  365. n = in.read(c);
  366. } catch (IOException e) {
  367. // no op
  368. }
  369. if (n < nbytes) {
  370. status = STATUS_FORMAT_ERROR;
  371. } else {
  372. tab = new int[256]; // max size to avoid bounds checks
  373. int i = 0;
  374. int j = 0;
  375. while (i < ncolors) {
  376. int r = ((int) c[j++]) & 0xff;
  377. int g = ((int) c[j++]) & 0xff;
  378. int b = ((int) c[j++]) & 0xff;
  379. tab[i++] = 0xff000000 | (r << 16) | (g << 8) | b;
  380. }
  381. }
  382. return tab;
  383. }
  384. protected void readContents() {
  385. boolean done = false;
  386. while (!(done || err())) {
  387. int code = read();
  388. switch (code) {
  389. case 0x2C:
  390. readImage();
  391. break;
  392. case 0x21:
  393. code = read();
  394. switch (code) {
  395. case 0xf9:
  396. readGraphicControlExt();
  397. break;
  398. case 0xff:
  399. readBlock();
  400. String app = "";
  401. for (int i = 0; i < 11; i++) {
  402. app += (char) block[i];
  403. }
  404. if (app.equals("NETSCAPE2.0")) {
  405. readNetscapeExt();
  406. } else
  407. skip();
  408. break;
  409. default:
  410. skip();
  411. }
  412. break;
  413. case 0x3b:
  414. done = true;
  415. break;
  416. case 0x00:
  417. break;
  418. default:
  419. status = STATUS_FORMAT_ERROR;
  420. }
  421. }
  422. }
  423. protected void readGraphicControlExt() {
  424. read();
  425. int packed = read();
  426. dispose = (packed & 0x1c) >> 2;
  427. if (dispose == 0) {
  428. dispose = 1;
  429. }
  430. transparency = (packed & 1) != 0;
  431. delay = readShort() * 10;
  432. transIndex = read();
  433. read();
  434. }
  435. protected void readHeader() {
  436. String id = "";
  437. for (int i = 0; i < 6; i++) {
  438. id += (char) read();
  439. }
  440. if (!id.startsWith("GIF")) {
  441. status = STATUS_FORMAT_ERROR;
  442. return;
  443. }
  444. readLSD();
  445. if (gctFlag && !err()) {
  446. gct = readColorTable(gctSize);
  447. bgColor = gct[bgIndex];
  448. }
  449. }
  450. protected void readImage() {
  451. ix = readShort();
  452. iy = readShort();
  453. iw = readShort();
  454. ih = readShort();
  455. int packed = read();
  456. lctFlag = (packed & 0x80) != 0;
  457. interlace = (packed & 0x40) != 0;
  458. lctSize = 2 << (packed & 7);
  459. if (lctFlag) {
  460. lct = readColorTable(lctSize);
  461. act = lct;
  462. } else {
  463. act = gct;
  464. if (bgIndex == transIndex)
  465. bgColor = 0;
  466. }
  467. int save = 0;
  468. if (transparency) {
  469. save = act[transIndex];
  470. act[transIndex] = 0;
  471. }
  472. if (act == null) {
  473. status = STATUS_FORMAT_ERROR;
  474. }
  475. if (err()) return;
  476. decodeImageData();
  477. skip();
  478. if (err()) return;
  479. frameCount++;
  480. image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE);
  481. setPixels();
  482. frames.add(new GifFrame(image, delay));
  483. if (transparency) {
  484. act[transIndex] = save;
  485. }
  486. resetFrame();
  487. }
  488. protected void readLSD() {
  489. width = readShort();
  490. height = readShort();
  491. int packed = read();
  492. gctFlag = (packed & 0x80) != 0;
  493. gctSize = 2 << (packed & 7);
  494. bgIndex = read();
  495. pixelAspect = read();
  496. }
  497. protected void readNetscapeExt() {
  498. do {
  499. readBlock();
  500. if (block[0] == 1) {
  501. int b1 = ((int) block[1]) & 0xff;
  502. int b2 = ((int) block[2]) & 0xff;
  503. loopCount = (b2 << 8) | b1;
  504. }
  505. } while ((blockSize > 0) && !err());
  506. }
  507. protected int readShort() {
  508. return read() | (read() << 8);
  509. }
  510. protected void resetFrame() {
  511. lastDispose = dispose;
  512. lastRect = new Rectangle(ix, iy, iw, ih);
  513. lastImage = image;
  514. lastBgColor = bgColor;
  515. int dispose = 0;
  516. boolean transparency = false;
  517. int delay = 0;
  518. lct = null;
  519. }
  520. protected void skip() {
  521. do {
  522. readBlock();
  523. } while ((blockSize > 0) && !err());
  524. }
  525. }