`

GIFDecoder.java源程序

阅读更多

import java.net.*;
import java.io.*;
import java.util.*;
import java.awt.*;
import java.awt.image.*;

public class GIFDecoder {

 /**
  * File read status: No errors.
  */
 public static final int STATUS_OK = 0;

 /**
  * File read status: Error decoding file (may be partially decoded)
  */
 public static final int STATUS_FORMAT_ERROR = 1;

 /**
  * File read status: Unable to open source.
  */
 public static final int STATUS_OPEN_ERROR = 2;

 protected BufferedInputStream in;
 protected int status;

 protected int width; // full image width
 protected int height; // full image height
 protected boolean gctFlag; // global color table used
 protected int gctSize; // size of global color table
 protected int loopCount = 1; // iterations; 0 = repeat forever

 protected int[] gct; // global color table
 protected int[] lct; // local color table
 protected int[] act; // active color table

 protected int bgIndex; // background color index
 protected int bgColor; // background color
 protected int lastBgColor; // previous bg color
 protected int pixelAspect; // pixel aspect ratio

 protected boolean lctFlag; // local color table flag
 protected boolean interlace; // interlace flag
 protected int lctSize; // local color table size

 protected int ix, iy, iw, ih; // current image rectangle
 protected Rectangle lastRect; // last image rect
 protected BufferedImage image; // current frame
 protected BufferedImage lastImage; // previous frame

 protected byte[] block = new byte[256]; // current data block
 protected int blockSize = 0; // block size

 // last graphic control extension info
 protected int dispose = 0;
 // 0=no action; 1=leave in place; 2=restore to bg; 3=restore to prev
 protected int lastDispose = 0;
 protected boolean transparency = false; // use transparent color
 protected int delay = 0; // delay in milliseconds
 protected int transIndex; // transparent color index

 protected static final int MaxStackSize = 4096;
 // max decoder pixel stack size

 // LZW decoder working arrays
 protected short[] prefix;
 protected byte[] suffix;
 protected byte[] pixelStack;
 protected byte[] pixels;

 protected ArrayList frames; // frames read from current file
 protected int frameCount;

 static class GifFrame {
  public GifFrame(BufferedImage im, int del) {
   image = im;
   delay = del;
  }
  public BufferedImage image;
  public int delay;
 }

 /**
  * Gets display duration for specified frame.
  *
  * @param n int index of frame
  * @return delay in milliseconds
  */
 public int getDelay(int n) {
  //
  delay = -1;
  if ((n >= 0) && (n < frameCount)) {
   delay = ((GifFrame) frames.get(n)).delay;
  }
  return delay;
 }

 /**
  * Gets the number of frames read from file.
  * @return frame count
  */
 public int getFrameCount() {
  return frameCount;
 }

 /**
  * Gets the first (or only) image read.
  *
  * @return BufferedImage containing first frame, or null if none.
  */
 public BufferedImage getImage() {
  return getFrame(0);
 }

 /**
  * Gets the "Netscape" iteration count, if any.
  * A count of 0 means repeat indefinitiely.
  *
  * @return iteration count if one was specified, else 1.
  */
 public int getLoopCount() {
  return loopCount;
 }

 /**
  * Creates new frame image from current data (and previous
  * frames as specified by their disposition codes).
  */
 protected void setPixels() {
  // expose destination image's pixels as int array
  int[] dest =
   ((DataBufferInt) image.getRaster().getDataBuffer()).getData();

  // fill in starting image contents based on last image's dispose code
  if (lastDispose > 0) {
   if (lastDispose == 3) {
    // use image before last
    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);
    // copy pixels

    if (lastDispose == 2) {
     // fill last image rect area with background color
     Graphics2D g = image.createGraphics();
     Color c = null;
     if (transparency) {
      c = new Color(0, 0, 0, 0);  // assume background is transparent
     } else {
      c = new Color(lastBgColor); // use given background color
     }
     g.setColor(c);
     g.setComposite(AlphaComposite.Src); // replace area
     g.fill(lastRect);
     g.dispose();
    }
   }
  }

  // copy each source line to the appropriate place in the destination
  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; // start of line in dest
    int dlim = dx + iw; // end of dest line
    if ((k + width) < dlim) {
     dlim = k + width; // past dest edge
    }
    int sx = i * iw; // start of line in source
    while (dx < dlim) {
     // map color and insert in destination
     int index = ((int) pixels[sx++]) & 0xff;
     int c = act[index];
     if (c != 0) {
      dest[dx] = c;
     }
     dx++;
    }
   }
  }
 }

 /**
  * Gets the image contents of frame n.
  *
  * @return BufferedImage representation of frame, or null if n is invalid.
  */
 public BufferedImage getFrame(int n) {
  BufferedImage im = null;
  if ((n >= 0) && (n < frameCount)) {
   im = ((GifFrame) frames.get(n)).image;
  }
  return im;
 }

 /**
  * Gets image size.
  *
  * @return GIF image dimensions
  */
 public Dimension getFrameSize() {
  return new Dimension(width, height);
 }

 /**
  * Reads GIF image from stream
  *
  * @param BufferedInputStream containing GIF file.
  * @return read status code (0 = no errors)
  */
 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 {
   is.close();
  } catch (IOException e) {
  }
  return status;
 }

 /**
  * Reads GIF image from stream
  *
  * @param InputStream containing GIF file.
  * @return read status code (0 = no errors)
  */
 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 {
   is.close();
  } catch (IOException e) {
  }
  return status;
 }

 /**
  * Reads GIF file from specified file/URL source 
  * (URL assumed if name contains ":/" or "file:")
  *
  * @param name String containing source
  * @return read status code (0 = no errors)
  */
 public int read(String name) {
  status = STATUS_OK;
  try {
   name = name.trim().toLowerCase();
   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;
 }

 /**
  * Decodes LZW image data into pixel array.
  * Adapted from John Cristy's ImageMagick.
  */
 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];

  //  Initialize GIF data stream decoder.

  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;
  }

  //  Decode GIF pixel stream.

  datum = bits = count = first = top = pi = bi = 0;

  for (i = 0; i < npix;) {
   if (top == 0) {
    if (bits < code_size) {
     //  Load bytes until there are enough bits for a code.
     if (count == 0) {
      // Read a new data block.
      count = readBlock();
      if (count <= 0)
       break;
      bi = 0;
     }
     datum += (((int) block[bi]) & 0xff) << bits;
     bits += 8;
     bi++;
     count--;
     continue;
    }

    //  Get the next code.

    code = datum & code_mask;
    datum >>= code_size;
    bits -= code_size;

    //  Interpret the code

    if ((code > available) || (code == end_of_information))
     break;
    if (code == clear) {
     //  Reset decoder.
     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;

    //  Add a new string to the string table,

    if (available >= MaxStackSize)
     break;
    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;
   }

   //  Pop a pixel off the pixel stack.

   top--;
   pixels[pi++] = pixelStack[top];
   i++;
  }

  for (i = pi; i < npix; i++) {
   pixels[i] = 0; // clear missing pixels
  }

 }

 /**
  * Returns true if an error was encountered during reading/decoding
  */
 protected boolean err() {
  return status != STATUS_OK;
 }

 /**
  * Initializes or re-initializes reader
  */
 protected void init() {
  status = STATUS_OK;
  frameCount = 0;
  frames = new ArrayList();
  gct = null;
  lct = null;
 }

 /**
  * Reads a single byte from the input stream.
  */
 protected int read() {
  int curByte = 0;
  try {
   curByte = in.read();
  } catch (IOException e) {
   status = STATUS_FORMAT_ERROR;
  }
  return curByte;
 }

 /**
  * Reads next variable length block from input.
  *
  * @return number of bytes stored in "buffer"
  */
 protected int readBlock() {
  blockSize = read();
  int n = 0;
  if (blockSize > 0) {
   try {
    int count = 0;
    while (n < blockSize) {
     count = in.read(block, n, blockSize - n);
     if (count == -1)
      break;
     n += count;
    }
   } catch (IOException e) {
   }

   if (n < blockSize) {
    status = STATUS_FORMAT_ERROR;
   }
  }
  return n;
 }

 /**
  * Reads color table as 256 RGB integer values
  *
  * @param ncolors int number of colors to read
  * @return int array containing 256 colors (packed ARGB with full alpha)
  */
 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) {
  }
  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;
 }

 /**
  * Main file parser.  Reads GIF content blocks.
  */
 protected void readContents() {
  // read GIF file content blocks
  boolean done = false;
  while (!(done || err())) {
   int code = read();
   switch (code) {

    case 0x2C : // image separator
     readImage();
     break;

    case 0x21 : // extension
     code = read();
     switch (code) {
      case 0xf9 : // graphics control extension
       readGraphicControlExt();
       break;

      case 0xff : // application extension
       readBlock();
       String app = "";
       for (int i = 0; i < 11; i++) {
        app += (char) block[i];
       }
       if (app.equals("NETSCAPE2.0")) {
        readNetscapeExt();
       }
       else
        skip(); // don't care
       break;

      default : // uninteresting extension
       skip();
     }
     break;

    case 0x3b : // terminator
     done = true;
     break;

    case 0x00 : // bad byte, but keep going and see what happens
     break;

    default :
     status = STATUS_FORMAT_ERROR;
   }
  }
 }

 /**
  * Reads Graphics Control Extension values
  */
 protected void readGraphicControlExt() {
  read(); // block size
  int packed = read(); // packed fields
  dispose = (packed & 0x1c) >> 2; // disposal method
  if (dispose == 0) {
   dispose = 1; // elect to keep old image if discretionary
  }
  transparency = (packed & 1) != 0;
  delay = readShort() * 10; // delay in milliseconds
  transIndex = read(); // transparent color index
  read(); // block terminator
 }

 /**
  * Reads GIF file header information.
  */
 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];
  }
 }

 /**
  * Reads next frame image
  */
 protected void readImage() {
  ix = readShort(); // (sub)image position & size
  iy = readShort();
  iw = readShort();
  ih = readShort();

  int packed = read();
  lctFlag = (packed & 0x80) != 0; // 1 - local color table flag
  interlace = (packed & 0x40) != 0; // 2 - interlace flag
  // 3 - sort flag
  // 4-5 - reserved
  lctSize = 2 << (packed & 7); // 6-8 - local color table size

  if (lctFlag) {
   lct = readColorTable(lctSize); // read table
   act = lct; // make local table active
  } else {
   act = gct; // make global table active
   if (bgIndex == transIndex)
    bgColor = 0;
  }
  int save = 0;
  if (transparency) {
   save = act[transIndex];
   act[transIndex] = 0; // set transparent color if specified
  }

  if (act == null) {
   status = STATUS_FORMAT_ERROR; // no color table defined
  }

  if (err()) return;

  decodeImageData(); // decode pixel data
  skip();

  if (err()) return;

  frameCount++;

  // create new image to receive frame data
  image =
   new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE);

  setPixels(); // transfer pixel data to image

  frames.add(new GifFrame(image, delay)); // add image to frame list

  if (transparency) {
   act[transIndex] = save;
  }
  resetFrame();

 }

 /**
  * Reads Logical Screen Descriptor
  */
 protected void readLSD() {

  // logical screen size
  width = readShort();
  height = readShort();

  // packed fields
  int packed = read();
  gctFlag = (packed & 0x80) != 0; // 1   : global color table flag
  // 2-4 : color resolution
  // 5   : gct sort flag
  gctSize = 2 << (packed & 7); // 6-8 : gct size

  bgIndex = read(); // background color index
  pixelAspect = read(); // pixel aspect ratio
 }

 /**
  * Reads Netscape extenstion to obtain iteration count
  */
 protected void readNetscapeExt() {
  do {
   readBlock();
   if (block[0] == 1) {
    // loop count sub-block
    int b1 = ((int) block[1]) & 0xff;
    int b2 = ((int) block[2]) & 0xff;
    loopCount = (b2 << 8) | b1;
   }
  } while ((blockSize > 0) && !err());
 }

 /**
  * Reads next 16-bit value, LSB first
  */
 protected int readShort() {
  // read 16-bit value, LSB first
  return read() | (read() << 8);
 }

 /**
  * Resets frame state for reading next image.
  */
 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());
 }
}

 

来自:http://luohonghong.blog.163.com/blog/static/783120582009534172860/

分享到:
评论

相关推荐

    Android代码-FloatingView

    GifDecoder.with(getActivity()).load(current_appAdStructItem.img_url, new GifDecoder.OnLoadGifListener() { @Override public void loadGifSuccess(File file) { GifDecoder.with(getActivity()).load(file)...

    GIFEncoder.js

    通过js生成GIF动画

    GIF解码和编码操作库源码

    该库包括四个类文件:AnimatedGifEncoder.java、GifDecoder.java、LZWEncoder.java 和 NeuQuant.java。 AnimatedGifEncoder.java 类文件用于编码 GIF 图像,提供了对 GIF 图像的编码和压缩功能。GifDecoder.java ...

    android gif支持源代码

    GifView的Jar包共有四个类: GifAction.java 观察者类,监视GIF是否加载成功 GifFrame.java ...GifDecoder.java 解码线程类 GifView.java 主类,包括常用方法,如GifView构造方法、设置图片源、延迟、绘制等。

    Java Source codes of GIF Encoder and Decoder

    `GifDecoder.java`文件通常包含一个类,用于读取和解析GIF文件,将其还原为像素数据。解码器的主要任务包括: 1. **文件头解析**:验证GIF文件的格式,并读取全局颜色表和其他元数据。 2. **帧解析**:提取每帧的...

    基于j2me的行动装置上显示gif动画

    在提供的文件列表中,有两个关键的类:GifDecoder.java 和 GifFrame.java。它们很可能构成了一个自定义的GIF解码框架,用于处理GIF文件的解析和播放。 1. **GifDecoder.java**: 这个类通常负责读取和解码GIF文件的...

    解决GIF动画缩放 (gif4j.jar GifDecoder)

    `gif4j.jar` 是一个Java库,专门设计用于处理GIF动画,包括缩放和压缩等功能。它内含了一个名为`GifDecoder`的类,该类能够解析GIF文件的结构,保持动画帧的信息完整。通过使用`gif4j.jar`,开发者可以避免将GIF动画...

    截图小工具工具源码,功能类似于qq截图,不过比qq截图功能少一点,添加gif生成

    - `AnimatedGifEncoder.java`、`LZWEncoder.java`、`NeuQuant.java`、`GifDecoder.java`:这些都是处理GIF编码和解码的关键组件,分别对应GIF动画编码器、LZW压缩、颜色量化算法和GIF解码器。 5. **开发环境与库**...

    如何给Android 2.3 图库添加Gif支持

    2. **`GifDecoder.java`**:这是一个全新的Java类,用于处理Gif解码的过程。该类包含了从Gif文件中读取数据并转换为可显示格式的逻辑。 3. **`Movie.java`**:这是一个Java类,负责处理所有类型的动画(包括Gif)。...

    GifDecoder

    在`GifDecoder`中,可能会有Java类作为用户接口,它通过JNI调用C++编写的解码库来处理GIF文件。这涉及到了Java和C++之间的类型映射、异常处理以及内存管理等细节。 4. **性能优化**:使用原生代码解码GIF可以避免...

    GifView2017最新版

    首先,`GifDecoder.java`文件是GIF解码器,它的主要任务是读取和解析GIF文件的内容。GIF是一种基于LZW压缩算法的位图格式,用于存储动画和透明图像。`GifDecoder`通常会读取GIF文件的数据流,提取出每一帧的信息,...

    AnimatedGifEncoder、LZWEncoder、GifDecoder、NeuQuant

    java处理gif的几个类(AnimatedGifEncoder、LZWEncoder、GifDecoder、NeuQuant),网上搜集的打成jar包方便使用

    Flex加载GIF动画处理类

    var frames:Array = gifDecoder.frames; for (var i:int = 0; i &lt; frames.length; i++) { var bitmap:Bitmap = new Bitmap(frames[i], "auto", true); var frameSprite:Sprite = new Sprite(); frameSprite....

    SSfuture Image Slide Show Generator-开源

    `GifDecoder.java` 和 `GIFEncoder.java` 是处理 GIF 文件的核心类。前者负责解码 GIF 文件,将图像数据转化为可操作的格式;后者则相反,将处理后的图像序列编码为 GIF 动画。这两个类是实现幻灯片动画的关键组件,...

    GIF-JS:JS编写的GIF图片文件decoderencoder

    任何人都可以出于任何目的(商业或非商业目的)以任何方式自由复制、修改、发布、使用、编译、销售或分发本软件,无论是源代码形式还是编译后的二进制文件。 在承认版权法的司法管辖区,本软件的作者或作者将本...

    基于Java的实例源码-Jav动画图标源码(显示GIF图像).zip

    在`codefans.net`这个文件中,可能包含了完整的Java源代码示例,演示了如何实现上述功能。如果你正在寻找如何在Java中显示GIF动画的方法,这个实例将是一个很好的学习资源。你可以通过阅读和理解代码来掌握如何将GIF...

    .net gif拆分和创建代码

    int frameCount = gifDecoder.GetFrameCount(); // 遍历每一帧并保存为 PNG 文件 string outputPath = "c:\\"; for (int i = 0; i ; i++) { Image frame = gifDecoder.GetFrame(i); // 获取第 i 帧 string ...

    Java中gif动图缩略图处理jar包

    在Java开发中,处理图像是一项常见的任务,特别是对于动态图像是一个挑战,因为它们涉及到多个帧和复杂的动画逻辑。GIF4J是一个专门用于处理GIF格式图像的库,尤其适用于创建GIF缩略图。这个jar包为开发者提供了一个...

    Java图片处理之获取gif图一帧图片的两种方法

    im4java库提供了Java接口,使得我们可以方便地在Java程序中调用ImageMagick的功能。以下是如何使用im4java提取GIF一帧的代码示例: ```java import org.im4java.core.*; import java.io.File; public class ...

Global site tag (gtag.js) - Google Analytics