| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554 |
- package eu.mjdev.desktop.helpers.gif;
- import java.net.*;
- import java.io.*;
- import java.util.*;
- import java.awt.*;
- import java.awt.image.*;
- @SuppressWarnings("ALL")
- public class GifDecoder {
- public static final int STATUS_OK = 0;
- public static final int STATUS_FORMAT_ERROR = 1;
- public static final int STATUS_OPEN_ERROR = 2;
- protected BufferedInputStream in;
- protected int status;
- protected int width;
- protected int height;
- protected boolean gctFlag;
- protected int gctSize;
- protected int loopCount = 1;
- protected int[] gct;
- protected int[] lct;
- protected int[] act;
- protected int bgIndex;
- protected int bgColor;
- protected int lastBgColor;
- protected int pixelAspect;
- protected boolean lctFlag;
- protected boolean interlace;
- protected int lctSize;
- protected int ix, iy, iw, ih;
- protected Rectangle lastRect;
- protected BufferedImage image;
- protected BufferedImage lastImage;
- protected byte[] block = new byte[256];
- protected int blockSize = 0;
- protected int dispose = 0;
- protected int lastDispose = 0;
- protected boolean transparency = false;
- protected int delay = 0;
- protected int transIndex;
- protected static final int MaxStackSize = 4096;
- protected short[] prefix;
- protected byte[] suffix;
- protected byte[] pixelStack;
- protected byte[] pixels;
- protected ArrayList frames;
- protected int frameCount;
- static class GifFrame {
- public GifFrame(BufferedImage im, int del) {
- image = im;
- delay = del;
- }
- public BufferedImage image;
- public int delay;
- }
- public int getDelay(int n) {
- delay = -1;
- if ((n >= 0) && (n < frameCount)) {
- delay = ((GifFrame) frames.get(n)).delay;
- }
- return delay;
- }
- public int getFrameCount() {
- return frameCount;
- }
- public BufferedImage getImage() {
- return getFrame(0);
- }
- public int getLoopCount() {
- return loopCount;
- }
- protected void setPixels() {
- int[] dest = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
- if (lastDispose > 0) {
- if (lastDispose == 3) {
- int n = frameCount - 2;
- if (n > 0) {
- lastImage = getFrame(n - 1);
- } else {
- lastImage = null;
- }
- }
- if (lastImage != null) {
- int[] prev = ((DataBufferInt) lastImage.getRaster().getDataBuffer()).getData();
- System.arraycopy(prev, 0, dest, 0, width * height);
- if (lastDispose == 2) {
- Graphics2D g = image.createGraphics();
- Color c;
- if (transparency) {
- c = new Color(0, 0, 0, 0);
- } else {
- c = new Color(lastBgColor);
- }
- g.setColor(c);
- g.setComposite(AlphaComposite.Src);
- g.fill(lastRect);
- g.dispose();
- }
- }
- }
- int pass = 1;
- int inc = 8;
- int iline = 0;
- for (int i = 0; i < ih; i++) {
- int line = i;
- if (interlace) {
- if (iline >= ih) {
- pass++;
- switch (pass) {
- case 2:
- iline = 4;
- break;
- case 3:
- iline = 2;
- inc = 4;
- break;
- case 4:
- iline = 1;
- inc = 2;
- }
- }
- line = iline;
- iline += inc;
- }
- line += iy;
- if (line < height) {
- int k = line * width;
- int dx = k + ix;
- int dlim = dx + iw;
- if ((k + width) < dlim) {
- dlim = k + width;
- }
- int sx = i * iw;
- while (dx < dlim) {
- int index = ((int) pixels[sx++]) & 0xff;
- int c = act[index];
- if (c != 0) {
- dest[dx] = c;
- }
- dx++;
- }
- }
- }
- }
- public BufferedImage getFrame(int n) {
- BufferedImage im = null;
- if ((n >= 0) && (n < frameCount)) {
- im = ((GifFrame) frames.get(n)).image;
- }
- return im;
- }
- public Dimension getFrameSize() {
- return new Dimension(width, height);
- }
- public int read(BufferedInputStream is) {
- init();
- if (is != null) {
- in = is;
- readHeader();
- if (!err()) {
- readContents();
- if (frameCount < 0) {
- status = STATUS_FORMAT_ERROR;
- }
- }
- } else {
- status = STATUS_OPEN_ERROR;
- }
- try {
- if (is != null) is.close();
- } catch (IOException e) {
- // no op
- }
- return status;
- }
- public int read(InputStream is) {
- init();
- if (is != null) {
- if (!(is instanceof BufferedInputStream))
- is = new BufferedInputStream(is);
- in = (BufferedInputStream) is;
- readHeader();
- if (!err()) {
- readContents();
- if (frameCount < 0) {
- status = STATUS_FORMAT_ERROR;
- }
- }
- } else {
- status = STATUS_OPEN_ERROR;
- }
- try {
- if(is != null) is.close();
- } catch (IOException e) {
- // no op
- }
- return status;
- }
- public int read(String name) {
- status = STATUS_OK;
- try {
- name = name.trim().toLowerCase();
- //noinspection IndexOfReplaceableByContains
- if ((name.indexOf("file:") >= 0) || (name.indexOf(":/") > 0)) {
- URL url = new URL(name);
- in = new BufferedInputStream(url.openStream());
- } else {
- in = new BufferedInputStream(new FileInputStream(name));
- }
- status = read(in);
- } catch (IOException e) {
- status = STATUS_OPEN_ERROR;
- }
- return status;
- }
- protected void decodeImageData() {
- int NullCode = -1;
- int npix = iw * ih;
- int available,
- clear,
- code_mask,
- code_size,
- end_of_information,
- in_code,
- old_code,
- bits,
- code,
- count,
- i,
- datum,
- data_size,
- first,
- top,
- bi,
- pi;
- if ((pixels == null) || (pixels.length < npix)) {
- pixels = new byte[npix]; // allocate new pixel array
- }
- if (prefix == null) prefix = new short[MaxStackSize];
- if (suffix == null) suffix = new byte[MaxStackSize];
- if (pixelStack == null) pixelStack = new byte[MaxStackSize + 1];
- data_size = read();
- clear = 1 << data_size;
- end_of_information = clear + 1;
- available = clear + 2;
- old_code = NullCode;
- code_size = data_size + 1;
- code_mask = (1 << code_size) - 1;
- for (code = 0; code < clear; code++) {
- prefix[code] = 0;
- suffix[code] = (byte) code;
- }
- datum = bits = count = first = top = pi = bi = 0;
- for (i = 0; i < npix; ) {
- if (top == 0) {
- if (bits < code_size) {
- if (count == 0) {
- count = readBlock();
- if (count <= 0)
- break;
- bi = 0;
- }
- datum += (((int) block[bi]) & 0xff) << bits;
- bits += 8;
- bi++;
- count--;
- continue;
- }
- code = datum & code_mask;
- datum >>= code_size;
- bits -= code_size;
- if ((code > available) || (code == end_of_information))
- break;
- if (code == clear) {
- code_size = data_size + 1;
- code_mask = (1 << code_size) - 1;
- available = clear + 2;
- old_code = NullCode;
- continue;
- }
- if (old_code == NullCode) {
- pixelStack[top++] = suffix[code];
- old_code = code;
- first = code;
- continue;
- }
- in_code = code;
- if (code == available) {
- pixelStack[top++] = (byte) first;
- code = old_code;
- }
- while (code > clear) {
- pixelStack[top++] = suffix[code];
- code = prefix[code];
- }
- first = ((int) suffix[code]) & 0xff;
- if (available >= MaxStackSize) {
- pixelStack[top++] = (byte) first;
- continue;
- }
- pixelStack[top++] = (byte) first;
- prefix[available] = (short) old_code;
- suffix[available] = (byte) first;
- available++;
- if (((available & code_mask) == 0)
- && (available < MaxStackSize)) {
- code_size++;
- code_mask += available;
- }
- old_code = in_code;
- }
- top--;
- pixels[pi++] = pixelStack[top];
- i++;
- }
- for (i = pi; i < npix; i++) {
- pixels[i] = 0;
- }
- }
- protected boolean err() {
- return status != STATUS_OK;
- }
- protected void init() {
- status = STATUS_OK;
- frameCount = 0;
- frames = new ArrayList();
- gct = null;
- lct = null;
- }
- protected int read() {
- int curByte = 0;
- try {
- curByte = in.read();
- } catch (IOException e) {
- status = STATUS_FORMAT_ERROR;
- }
- return curByte;
- }
- protected int readBlock() {
- blockSize = read();
- int n = 0;
- if (blockSize > 0) {
- try {
- int count;
- while (n < blockSize) {
- count = in.read(block, n, blockSize - n);
- if (count == -1)
- break;
- n += count;
- }
- } catch (IOException e) {
- // no op
- }
- if (n < blockSize) {
- status = STATUS_FORMAT_ERROR;
- }
- }
- return n;
- }
- protected int[] readColorTable(int ncolors) {
- int nbytes = 3 * ncolors;
- int[] tab = null;
- byte[] c = new byte[nbytes];
- int n = 0;
- try {
- n = in.read(c);
- } catch (IOException e) {
- // no op
- }
- if (n < nbytes) {
- status = STATUS_FORMAT_ERROR;
- } else {
- tab = new int[256]; // max size to avoid bounds checks
- int i = 0;
- int j = 0;
- while (i < ncolors) {
- int r = ((int) c[j++]) & 0xff;
- int g = ((int) c[j++]) & 0xff;
- int b = ((int) c[j++]) & 0xff;
- tab[i++] = 0xff000000 | (r << 16) | (g << 8) | b;
- }
- }
- return tab;
- }
- protected void readContents() {
- boolean done = false;
- while (!(done || err())) {
- int code = read();
- switch (code) {
- case 0x2C:
- readImage();
- break;
- case 0x21:
- code = read();
- switch (code) {
- case 0xf9:
- readGraphicControlExt();
- break;
- case 0xff:
- readBlock();
- String app = "";
- for (int i = 0; i < 11; i++) {
- app += (char) block[i];
- }
- if (app.equals("NETSCAPE2.0")) {
- readNetscapeExt();
- } else
- skip();
- break;
- default:
- skip();
- }
- break;
- case 0x3b:
- done = true;
- break;
- case 0x00:
- break;
- default:
- status = STATUS_FORMAT_ERROR;
- }
- }
- }
- protected void readGraphicControlExt() {
- read();
- int packed = read();
- dispose = (packed & 0x1c) >> 2;
- if (dispose == 0) {
- dispose = 1;
- }
- transparency = (packed & 1) != 0;
- delay = readShort() * 10;
- transIndex = read();
- read();
- }
- protected void readHeader() {
- String id = "";
- for (int i = 0; i < 6; i++) {
- id += (char) read();
- }
- if (!id.startsWith("GIF")) {
- status = STATUS_FORMAT_ERROR;
- return;
- }
- readLSD();
- if (gctFlag && !err()) {
- gct = readColorTable(gctSize);
- bgColor = gct[bgIndex];
- }
- }
- protected void readImage() {
- ix = readShort();
- iy = readShort();
- iw = readShort();
- ih = readShort();
- int packed = read();
- lctFlag = (packed & 0x80) != 0;
- interlace = (packed & 0x40) != 0;
- lctSize = 2 << (packed & 7);
- if (lctFlag) {
- lct = readColorTable(lctSize);
- act = lct;
- } else {
- act = gct;
- if (bgIndex == transIndex)
- bgColor = 0;
- }
- int save = 0;
- if (transparency) {
- save = act[transIndex];
- act[transIndex] = 0;
- }
- if (act == null) {
- status = STATUS_FORMAT_ERROR;
- }
- if (err()) return;
- decodeImageData();
- skip();
- if (err()) return;
- frameCount++;
- image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE);
- setPixels();
- frames.add(new GifFrame(image, delay));
- if (transparency) {
- act[transIndex] = save;
- }
- resetFrame();
- }
- protected void readLSD() {
- width = readShort();
- height = readShort();
- int packed = read();
- gctFlag = (packed & 0x80) != 0;
- gctSize = 2 << (packed & 7);
- bgIndex = read();
- pixelAspect = read();
- }
- protected void readNetscapeExt() {
- do {
- readBlock();
- if (block[0] == 1) {
- int b1 = ((int) block[1]) & 0xff;
- int b2 = ((int) block[2]) & 0xff;
- loopCount = (b2 << 8) | b1;
- }
- } while ((blockSize > 0) && !err());
- }
- protected int readShort() {
- return read() | (read() << 8);
- }
- protected void resetFrame() {
- lastDispose = dispose;
- lastRect = new Rectangle(ix, iy, iw, ih);
- lastImage = image;
- lastBgColor = bgColor;
- int dispose = 0;
- boolean transparency = false;
- int delay = 0;
- lct = null;
- }
- protected void skip() {
- do {
- readBlock();
- } while ((blockSize > 0) && !err());
- }
- }
|