Advertisement
Guest User

GifDecoder

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