PageRenderTime 52ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/IJ_Mobile/src/loci/formats/in/GIFReader.java

https://github.com/msteptoe/FURI_Code
Java | 534 lines | 363 code | 90 blank | 81 comment | 81 complexity | 92d6e9b4da7333542537a89b88f1b816 MD5 | raw file
  1. /*
  2. * #%L
  3. * OME SCIFIO package for reading and converting scientific file formats.
  4. * %%
  5. * Copyright (C) 2005 - 2012 Open Microscopy Environment:
  6. * - Board of Regents of the University of Wisconsin-Madison
  7. * - Glencoe Software, Inc.
  8. * - University of Dundee
  9. * %%
  10. * Redistribution and use in source and binary forms, with or without
  11. * modification, are permitted provided that the following conditions are met:
  12. *
  13. * 1. Redistributions of source code must retain the above copyright notice,
  14. * this list of conditions and the following disclaimer.
  15. * 2. Redistributions in binary form must reproduce the above copyright notice,
  16. * this list of conditions and the following disclaimer in the documentation
  17. * and/or other materials provided with the distribution.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  20. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  21. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  22. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
  23. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  24. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  25. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  26. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  27. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  28. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  29. * POSSIBILITY OF SUCH DAMAGE.
  30. *
  31. * The views and conclusions contained in the software and documentation are
  32. * those of the authors and should not be interpreted as representing official
  33. * policies, either expressed or implied, of any organization.
  34. * #L%
  35. */
  36. package loci.formats.in;
  37. import java.io.IOException;
  38. import java.util.Arrays;
  39. import java.util.Vector;
  40. import loci.common.RandomAccessInputStream;
  41. import loci.formats.CoreMetadata;
  42. import loci.formats.FormatException;
  43. import loci.formats.FormatReader;
  44. import loci.formats.FormatTools;
  45. import loci.formats.MetadataTools;
  46. import loci.formats.meta.MetadataStore;
  47. /**
  48. * GIFReader is the file format reader for Graphics Interchange Format
  49. * (GIF) files. Much of this code was adapted from the Animated GIF Reader
  50. * plugin for ImageJ (http://rsb.info.nih.gov/ij).
  51. *
  52. * <dl><dt><b>Source code:</b></dt>
  53. * <dd><a href="http://trac.openmicroscopy.org.uk/ome/browser/bioformats.git/components/bio-formats/src/loci/formats/in/GIFReader.java">Trac</a>,
  54. * <a href="http://git.openmicroscopy.org/?p=bioformats.git;a=blob;f=components/bio-formats/src/loci/formats/in/GIFReader.java;hb=HEAD">Gitweb</a></dd></dl>
  55. */
  56. public class GIFReader extends FormatReader {
  57. // -- Constants --
  58. public static final String GIF_MAGIC_STRING = "GIF";
  59. /** Maximum buffer size. */
  60. private static final int MAX_STACK_SIZE = 4096;
  61. private static final int IMAGE_SEPARATOR = 0x2c;
  62. private static final int EXTENSION = 0x21;
  63. private static final int END = 0x3b;
  64. private static final int GRAPHICS = 0xf9;
  65. // -- Fields --
  66. /** Global color table. */
  67. private int[] gct;
  68. /** Active color table. */
  69. private int[] act;
  70. /** Interlace flag. */
  71. private boolean interlace;
  72. /** Current image rectangle. */
  73. private int ix, iy, iw, ih;
  74. /** Current data block. */
  75. private byte[] dBlock = new byte[256];
  76. /** Block size. */
  77. private int blockSize = 0;
  78. private int dispose = 0;
  79. private int lastDispose = 0;
  80. /** Use transparent color. */
  81. private boolean transparency = false;
  82. /** Transparent color index. */
  83. private int transIndex;
  84. // LZW working arrays
  85. private short[] prefix;
  86. private byte[] suffix;
  87. private byte[] pixelStack;
  88. private byte[] pixels;
  89. private Vector<byte[]> images;
  90. private Vector<int[]> colorTables;
  91. // -- Constructor --
  92. /** Constructs a new GIF reader. */
  93. public GIFReader() {
  94. super("Graphics Interchange Format", "gif");
  95. domains = new String[] {FormatTools.GRAPHICS_DOMAIN};
  96. }
  97. // -- IFormatReader API methods --
  98. /* @see loci.formats.IFormatReader#isThisType(RandomAccessInputStream) */
  99. public boolean isThisType(RandomAccessInputStream stream) throws IOException {
  100. final int blockLen = GIF_MAGIC_STRING.length();
  101. if (!FormatTools.validStream(stream, blockLen, false)) return false;
  102. return stream.readString(blockLen).startsWith(GIF_MAGIC_STRING);
  103. }
  104. /* @see loci.formats.IFormatReader#get8BitLookupTable() */
  105. public byte[][] get8BitLookupTable() throws FormatException, IOException {
  106. FormatTools.assertId(currentId, true, 1);
  107. byte[][] table = new byte[3][act.length];
  108. for (int i=0; i<act.length; i++) {
  109. table[0][i] = (byte) ((act[i] >> 16) & 0xff);
  110. table[1][i] = (byte) ((act[i] >> 8) & 0xff);
  111. table[2][i] = (byte) (act[i] & 0xff);
  112. }
  113. return table;
  114. }
  115. /**
  116. * @see loci.formats.IFormatReader#openBytes(int, byte[], int, int, int, int)
  117. */
  118. public byte[] openBytes(int no, byte[] buf, int x, int y, int w, int h)
  119. throws FormatException, IOException
  120. {
  121. FormatTools.checkPlaneParameters(this, no, buf.length, x, y, w, h);
  122. act = colorTables.get(no);
  123. byte[] b = images.get(no);
  124. if (no > 0 && transparency) {
  125. byte[] prev = images.get(no - 1);
  126. int idx = transIndex;
  127. if (idx >= 127) idx = 0;
  128. for (int i=0; i<b.length; i++) {
  129. if ((act[b[i] & 0xff] & 0xffffff) == idx) {
  130. b[i] = prev[i];
  131. }
  132. }
  133. images.setElementAt(b, no);
  134. }
  135. for (int row=0; row<h; row++) {
  136. System.arraycopy(b, (row + y) * getSizeX() + x, buf, row*w, w);
  137. }
  138. return buf;
  139. }
  140. /* @see loci.formats.IFormatReader#close(boolean) */
  141. public void close(boolean fileOnly) throws IOException {
  142. super.close(fileOnly);
  143. if (!fileOnly) {
  144. interlace = transparency = false;
  145. ix = iy = iw = ih = blockSize = 0;
  146. dispose = lastDispose = transIndex = 0;
  147. gct = act;
  148. prefix = null;
  149. suffix = pixelStack = pixels = null;
  150. images = null;
  151. colorTables = null;
  152. Arrays.fill(dBlock, (byte) 0);
  153. }
  154. }
  155. // -- Internal FormatReader API methods --
  156. /* @see loci.formats.FormatReader#initFile(String) */
  157. protected void initFile(String id) throws FormatException, IOException {
  158. super.initFile(id);
  159. LOGGER.info("Verifying GIF format");
  160. in = new RandomAccessInputStream(id);
  161. in.order(true);
  162. images = new Vector<byte[]>();
  163. colorTables = new Vector<int[]>();
  164. String ident = in.readString(6);
  165. if (!ident.startsWith(GIF_MAGIC_STRING)) {
  166. throw new FormatException("Not a valid GIF file.");
  167. }
  168. LOGGER.info("Reading dimensions");
  169. CoreMetadata m = core.get(0);
  170. m.sizeX = in.readShort();
  171. m.sizeY = in.readShort();
  172. int packed = in.read() & 0xff;
  173. boolean gctFlag = (packed & 0x80) != 0;
  174. int gctSize = 2 << (packed & 7);
  175. in.skipBytes(2);
  176. addGlobalMeta("Global lookup table size", gctSize);
  177. if (gctFlag) {
  178. gct = readLut(gctSize);
  179. }
  180. LOGGER.info("Reading data blocks");
  181. boolean done = false;
  182. while (!done) {
  183. int code = in.read() & 0xff;
  184. switch (code) {
  185. case IMAGE_SEPARATOR:
  186. readImageBlock();
  187. break;
  188. case EXTENSION:
  189. code = in.read() & 0xff;
  190. switch (code) {
  191. case GRAPHICS:
  192. in.skipBytes(1);
  193. packed = in.read() & 0xff;
  194. dispose = (packed & 0x1c) >> 1;
  195. transparency = (packed & 1) != 0;
  196. in.skipBytes(2);
  197. transIndex = in.read() & 0xff;
  198. in.skipBytes(1);
  199. break;
  200. default:
  201. if (readBlock() == -1) {
  202. done = true;
  203. break;
  204. }
  205. skipBlocks();
  206. }
  207. break;
  208. case END:
  209. done = true;
  210. break;
  211. }
  212. }
  213. act = colorTables.get(0);
  214. LOGGER.info("Populating metadata");
  215. m.sizeZ = 1;
  216. m.sizeC = 1;
  217. m.sizeT = getImageCount();
  218. m.dimensionOrder = "XYCTZ";
  219. m.rgb = false;
  220. m.littleEndian = true;
  221. m.interleaved = true;
  222. m.metadataComplete = true;
  223. m.indexed = true;
  224. m.falseColor = false;
  225. m.pixelType = FormatTools.UINT8;
  226. // populate metadata store
  227. MetadataStore store = makeFilterMetadata();
  228. MetadataTools.populatePixels(store, this);
  229. }
  230. // -- Helper methods --
  231. /** Reads the next variable length block. */
  232. private int readBlock() throws IOException {
  233. if (in.getFilePointer() == in.length()) return -1;
  234. blockSize = in.read() & 0xff;
  235. int n = 0;
  236. int count;
  237. if (blockSize > 0) {
  238. try {
  239. while (n < blockSize) {
  240. count = in.read(dBlock, n, blockSize - n);
  241. if (count == -1) break;
  242. n += count;
  243. }
  244. }
  245. catch (IOException e) {
  246. LOGGER.trace("Truncated block", e);
  247. }
  248. }
  249. return n;
  250. }
  251. /** Decodes LZW image data into a pixel array. Adapted from ImageMagick. */
  252. private void decodeImageData() throws IOException {
  253. int nullCode = -1;
  254. int npix = iw * ih;
  255. if (pixels == null || pixels.length < npix) pixels = new byte[npix];
  256. if (prefix == null) prefix = new short[MAX_STACK_SIZE];
  257. if (suffix == null) suffix = new byte[MAX_STACK_SIZE];
  258. if (pixelStack == null) pixelStack = new byte[MAX_STACK_SIZE + 1];
  259. // initialize GIF data stream decoder
  260. int dataSize = in.read() & 0xff;
  261. int clear = 1 << dataSize;
  262. int eoi = clear + 1;
  263. int available = clear + 2;
  264. int oldCode = nullCode;
  265. int codeSize = dataSize + 1;
  266. int codeMask = (1 << codeSize) - 1;
  267. int code = 0, inCode = 0;
  268. for (code=0; code<clear; code++) {
  269. prefix[code] = 0;
  270. suffix[code] = (byte) code;
  271. }
  272. // decode GIF pixel stream
  273. int datum = 0, first = 0, top = 0, pi = 0, bi = 0, bits = 0, count = 0;
  274. int i = 0;
  275. for (i=0; i<npix;) {
  276. if (top == 0) {
  277. if (bits < codeSize) {
  278. if (count == 0) {
  279. count = readBlock();
  280. if (count <= 0) break;
  281. bi = 0;
  282. }
  283. datum += (dBlock[bi] & 0xff) << bits;
  284. bits += 8;
  285. bi++;
  286. count--;
  287. continue;
  288. }
  289. // get the next code
  290. code = datum & codeMask;
  291. datum >>= codeSize;
  292. bits -= codeSize;
  293. // interpret the code
  294. if ((code > available) || (code == eoi)) {
  295. break;
  296. }
  297. if (code == clear) {
  298. // reset the decoder
  299. codeSize = dataSize + 1;
  300. codeMask = (1 << codeSize) - 1;
  301. available = clear + 2;
  302. oldCode = nullCode;
  303. continue;
  304. }
  305. if (oldCode == nullCode) {
  306. pixelStack[top++] = suffix[code];
  307. oldCode = code;
  308. first = code;
  309. continue;
  310. }
  311. inCode = code;
  312. if (code == available) {
  313. pixelStack[top++] = (byte) first;
  314. code = oldCode;
  315. }
  316. while (code > clear) {
  317. pixelStack[top++] = suffix[code];
  318. code = prefix[code];
  319. }
  320. first = suffix[code] & 0xff;
  321. if (available >= MAX_STACK_SIZE) break;
  322. pixelStack[top++] = (byte) first;
  323. prefix[available] = (short) oldCode;
  324. suffix[available] = (byte) first;
  325. available++;
  326. if (((available & codeMask) == 0) && (available < MAX_STACK_SIZE)) {
  327. codeSize++;
  328. codeMask += available;
  329. }
  330. oldCode = inCode;
  331. }
  332. top--;
  333. pixels[pi++] = pixelStack[top];
  334. i++;
  335. }
  336. for (i=pi; i<npix; i++) pixels[i] = 0;
  337. setPixels();
  338. }
  339. private void setPixels() {
  340. // expose destination image's pixels as an int array
  341. byte[] dest = new byte[getSizeX() * getSizeY()];
  342. int lastImage = -1;
  343. // fill in starting image contents based on last image's dispose code
  344. if (lastDispose > 0) {
  345. if (lastDispose == 3) { // use image before last
  346. int n = getImageCount() - 2;
  347. if (n > 0) lastImage = n - 1;
  348. }
  349. if (lastImage != -1) {
  350. byte[] prev = images.get(lastImage);
  351. System.arraycopy(prev, 0, dest, 0, getSizeX() * getSizeY());
  352. }
  353. }
  354. // copy each source line to the appropriate place in the destination
  355. int pass = 1;
  356. int inc = 8;
  357. int iline = 0;
  358. for (int i=0; i<ih; i++) {
  359. int line = i;
  360. if (interlace) {
  361. if (iline >= ih) {
  362. pass++;
  363. switch (pass) {
  364. case 2:
  365. iline = 4;
  366. break;
  367. case 3:
  368. iline = 2;
  369. inc = 4;
  370. break;
  371. case 4:
  372. iline = 1;
  373. inc = 2;
  374. break;
  375. }
  376. }
  377. line = iline;
  378. iline += inc;
  379. }
  380. line += iy;
  381. if (line < getSizeY()) {
  382. int k = line * getSizeX();
  383. int dx = k + ix; // start of line in dest
  384. int dlim = dx + iw; // end of dest line
  385. if ((k + getSizeX()) < dlim) dlim = k + getSizeX();
  386. int sx = i * iw; // start of line in source
  387. while (dx < dlim) {
  388. // map color and insert in destination
  389. int index = pixels[sx++] & 0xff;
  390. dest[dx++] = (byte) index;
  391. }
  392. }
  393. }
  394. colorTables.add(act);
  395. images.add(dest);
  396. }
  397. private void skipBlocks() throws IOException {
  398. int check = 0;
  399. do { check = readBlock(); }
  400. while (blockSize > 0 && check != -1);
  401. }
  402. private void readImageBlock() throws FormatException, IOException {
  403. ix = in.readShort();
  404. iy = in.readShort();
  405. iw = in.readShort();
  406. ih = in.readShort();
  407. int packed = in.read();
  408. boolean lctFlag = (packed & 0x80) != 0;
  409. interlace = (packed & 0x40) != 0;
  410. int lctSize = 2 << (packed & 7);
  411. act = lctFlag ? readLut(lctSize) : gct;
  412. int save = 0;
  413. if (transparency) {
  414. save = act[transIndex];
  415. act[transIndex] = 0;
  416. }
  417. if (act == null) throw new FormatException("Color table not found.");
  418. decodeImageData();
  419. skipBlocks();
  420. core.get(0).imageCount++;
  421. if (transparency) act[transIndex] = save;
  422. lastDispose = dispose;
  423. }
  424. /** Read a color lookup table of the specified size. */
  425. private int[] readLut(int size) throws FormatException {
  426. int nbytes = 3 * size;
  427. byte[] c = new byte[nbytes];
  428. int n = 0;
  429. try { n = in.read(c); }
  430. catch (IOException e) { }
  431. if (n < nbytes) {
  432. throw new FormatException("Color table not found");
  433. }
  434. int[] lut = new int[256];
  435. int j = 0;
  436. for (int i=0; i<size; i++) {
  437. int r = c[j++] & 0xff;
  438. int g = c[j++] & 0xff;
  439. int b = c[j++] & 0xff;
  440. lut[i] = 0xff000000 | (r << 16) | (g << 8) | b;
  441. }
  442. return lut;
  443. }
  444. }