`
walksing
  • 浏览: 217165 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

AnimatedGifEncoder

阅读更多
import java.io.*;
import java.awt.*;
import java.awt.image.*;

/**
* Class AnimatedGifEncoder - Encodes a GIF file consisting of one or
* more frames.
* <pre>
* Example:
*    AnimatedGifEncoder e = new AnimatedGifEncoder();
*    e.start(outputFileName);
*    e.setDelay(1000);   // 1 frame per sec
*    e.addFrame(image1);
*    e.addFrame(image2);
*    e.finish();
* </pre>
* No copyright asserted on the source code of this class.  May be used
* for any purpose, however, refer to the Unisys LZW patent for restrictions
* on use of the associated LZWEncoder class.  Please forward any corrections
* to kweiner@fmsware.com.
*
* @author Kevin Weiner, FM Software
* @version 1.03 November 2003
*
*/

public class AnimatedGifEncoder {

protected int width; // image size
protected int height;
protected Color transparent = null; // transparent color if given
protected int transIndex; // transparent index in color table
protected int repeat = -1; // no repeat
protected int delay = 0; // frame delay (hundredths)
protected boolean started = false; // ready to output frames
protected OutputStream out;
protected BufferedImage image; // current frame
protected byte[] pixels; // BGR byte array from frame
protected byte[] indexedPixels; // converted frame indexed to palette
protected int colorDepth; // number of bit planes
protected byte[] colorTab; // RGB palette
protected boolean[] usedEntry = new boolean[256]; // active palette entries
protected int palSize = 7; // color table size (bits-1)
protected int dispose = -1; // disposal code (-1 = use default)
protected boolean closeStream = false; // close stream when finished
protected boolean firstFrame = true;
protected boolean sizeSet = false; // if false, get size from first frame
protected int sample = 10; // default sample interval for quantizer

/**
  * Sets the delay time between each frame, or changes it
  * for subsequent frames (applies to last frame added).
  *
  * @param ms int delay time in milliseconds
  */
public void setDelay(int ms) {
  delay = Math.round(ms / 10.0f);
}

/**
  * Sets the GIF frame disposal code for the last added frame
  * and any subsequent frames.  Default is 0 if no transparent
  * color has been set, otherwise 2.
  * @param code int disposal code.
  */
public void setDispose(int code) {
  if (code >= 0) {
   dispose = code;
  }
}

/**
  * Sets the number of times the set of GIF frames
  * should be played.  Default is 1; 0 means play
  * indefinitely.  Must be invoked before the first
  * image is added.
  *
  * @param iter int number of iterations.
  * @return
  */
public void setRepeat(int iter) {
  if (iter >= 0) {
   repeat = iter;
  }
}

/**
  * Sets the transparent color for the last added frame
  * and any subsequent frames.
  * Since all colors are subject to modification
  * in the quantization process, the color in the final
  * palette for each frame closest to the given color
  * becomes the transparent color for that frame.
  * May be set to null to indicate no transparent color.
  *
  * @param c Color to be treated as transparent on display.
  */
public void setTransparent(Color c) {
  transparent = c;
}

/**
  * Adds next GIF frame.  The frame is not written immediately, but is
  * actually deferred until the next frame is received so that timing
  * data can be inserted.  Invoking <code>finish()</code> flushes all
  * frames.  If <code>setSize</code> was not invoked, the size of the
  * first image is used for all subsequent frames.
  *
  * @param im BufferedImage containing frame to write.
  * @return true if successful.
  */
public boolean addFrame(BufferedImage im) {
  if ((im == null) || !started) {
   return false;
  }
  boolean ok = true;
  try {
   if (!sizeSet) {
    // use first frame's size
    setSize(im.getWidth(), im.getHeight());
   }
   image = im;
   getImagePixels(); // convert to correct format if necessary
   analyzePixels(); // build color table & map pixels
   if (firstFrame) {
    writeLSD(); // logical screen descriptior
    writePalette(); // global color table
    if (repeat >= 0) {
     // use NS app extension to indicate reps
     writeNetscapeExt();
    }
   }
   writeGraphicCtrlExt(); // write graphic control extension
   writeImageDesc(); // image descriptor
   if (!firstFrame) {
    writePalette(); // local color table
   }
   writePixels(); // encode and write pixel data
   firstFrame = false;
  } catch (IOException e) {
   ok = false;
  }

  return ok;
}

/**
  * Flushes any pending data and closes output file.
  * If writing to an OutputStream, the stream is not
  * closed.
  */
public boolean finish() {
  if (!started) return false;
  boolean ok = true;
  started = false;
  try {
   out.write(0x3b); // gif trailer
   out.flush();
   if (closeStream) {
    out.close();
   }
  } catch (IOException e) {
   ok = false;
  }

  // reset for subsequent use
  transIndex = 0;
  out = null;
  image = null;
  pixels = null;
  indexedPixels = null;
  colorTab = null;
  closeStream = false;
  firstFrame = true;

  return ok;
}

/**
  * Sets frame rate in frames per second.  Equivalent to
  * <code>setDelay(1000/fps)</code>.
  *
  * @param fps float frame rate (frames per second)
  */
public void setFrameRate(float fps) {
  if (fps != 0f) {
   delay = Math.round(100f / fps);
  }
}

/**
  * Sets quality of color quantization (conversion of images
  * to the maximum 256 colors allowed by the GIF specification).
  * Lower values (minimum = 1) produce better colors, but slow
  * processing significantly.  10 is the default, and produces
  * good color mapping at reasonable speeds.  Values greater
  * than 20 do not yield significant improvements in speed.
  *
  * @param quality int greater than 0.
  * @return
  */
public void setQuality(int quality) {
  if (quality < 1) quality = 1;
  sample = quality;
}

/**
  * Sets the GIF frame size.  The default size is the
  * size of the first frame added if this method is
  * not invoked.
  *
  * @param w int frame width.
  * @param h int frame width.
  */
public void setSize(int w, int h) {
  if (started && !firstFrame) return;
  width = w;
  height = h;
  if (width < 1) width = 320;
  if (height < 1) height = 240;
  sizeSet = true;
}

/**
  * Initiates GIF file creation on the given stream.  The stream
  * is not closed automatically.
  *
  * @param os OutputStream on which GIF images are written.
  * @return false if initial write failed.
  */
public boolean start(OutputStream os) {
  if (os == null) return false;
  boolean ok = true;
  closeStream = false;
  out = os;
  try {
   writeString("GIF89a"); // header
  } catch (IOException e) {
   ok = false;
  }
  return started = ok;
}

/**
  * Initiates writing of a GIF file with the specified name.
  *
  * @param file String containing output file name.
  * @return false if open or initial write failed.
  */
public boolean start(String file) {
  boolean ok = true;
  try {
   out = new BufferedOutputStream(new FileOutputStream(file));
   ok = start(out);
   closeStream = true;
  } catch (IOException e) {
   ok = false;
  }
  return started = ok;
}

/**
  * Analyzes image colors and creates color map.
  */
protected void analyzePixels() {
  int len = pixels.length;
  int nPix = len / 3;
  indexedPixels = new byte[nPix];
  NeuQuant nq = new NeuQuant(pixels, len, sample);
  // initialize quantizer
  colorTab = nq.process(); // create reduced palette
  // convert map from BGR to RGB
  for (int i = 0; i < colorTab.length; i += 3) {
   byte temp = colorTab[i];
   colorTab[i] = colorTab[i + 2];
   colorTab[i + 2] = temp;
   usedEntry[i / 3] = false;
  }
  // map image pixels to new palette
  int k = 0;
  for (int i = 0; i < nPix; i++) {
   int index =
    nq.map(pixels[k++] & 0xff,
        pixels[k++] & 0xff,
        pixels[k++] & 0xff);
   usedEntry[index] = true;
   indexedPixels[i] = (byte) index;
  }
  pixels = null;
  colorDepth = 8;
  palSize = 7;
  // get closest match to transparent color if specified
  if (transparent != null) {
   transIndex = findClosest(transparent);
  }
}

/**
  * Returns index of palette color closest to c
  *
  */
protected int findClosest(Color c) {
  if (colorTab == null) return -1;
  int r = c.getRed();
  int g = c.getGreen();
  int b = c.getBlue();
  int minpos = 0;
  int dmin = 256 * 256 * 256;
  int len = colorTab.length;
  for (int i = 0; i < len;) {
   int dr = r - (colorTab[i++] & 0xff);
   int dg = g - (colorTab[i++] & 0xff);
   int db = b - (colorTab[i] & 0xff);
   int d = dr * dr + dg * dg + db * db;
   int index = i / 3;
   if (usedEntry[index] && (d < dmin)) {
    dmin = d;
    minpos = index;
   }
   i++;
  }
  return minpos;
}

/**
  * Extracts image pixels into byte array "pixels"
  */
protected void getImagePixels() {
  int w = image.getWidth();
  int h = image.getHeight();
  int type = image.getType();
  if ((w != width)
   || (h != height)
   || (type != BufferedImage.TYPE_3BYTE_BGR)) {
   // create new image with right size/format
   BufferedImage temp =
    new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
   Graphics2D g = temp.createGraphics();
   g.drawImage(image, 0, 0, null);
   image = temp;
  }
  pixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
}

/**
  * Writes Graphic Control Extension
  */
protected void writeGraphicCtrlExt() throws IOException {
  out.write(0x21); // extension introducer
  out.write(0xf9); // GCE label
  out.write(4); // data block size
  int transp, disp;
  if (transparent == null) {
   transp = 0;
   disp = 0; // dispose = no action
  } else {
   transp = 1;
   disp = 2; // force clear if using transparent color
  }
  if (dispose >= 0) {
   disp = dispose & 7; // user override
  }
  disp <<= 2;

  // packed fields
  out.write(0 | // 1:3 reserved
      disp | // 4:6 disposal
         0 | // 7   user input - 0 = none
       transp); // 8   transparency flag

  writeShort(delay); // delay x 1/100 sec
  out.write(transIndex); // transparent color index
  out.write(0); // block terminator
}

/**
  * Writes Image Descriptor
  */
protected void writeImageDesc() throws IOException {
  out.write(0x2c); // image separator
  writeShort(0); // image position x,y = 0,0
  writeShort(0);
  writeShort(width); // image size
  writeShort(height);
  // packed fields
  if (firstFrame) {
   // no LCT  - GCT is used for first (or only) frame
   out.write(0);
  } else {
   // specify normal LCT
   out.write(0x80 | // 1 local color table  1=yes
       0 | // 2 interlace - 0=no
       0 | // 3 sorted - 0=no
       0 | // 4-5 reserved
       palSize); // 6-8 size of color table
  }
}

/**
  * Writes Logical Screen Descriptor
  */
protected void writeLSD() throws IOException {
  // logical screen size
  writeShort(width);
  writeShort(height);
  // packed fields
  out.write((0x80 | // 1   : global color table flag = 1 (gct used)
       0x70 | // 2-4 : color resolution = 7
       0x00 | // 5   : gct sort flag = 0
      palSize)); // 6-8 : gct size

  out.write(0); // background color index
  out.write(0); // pixel aspect ratio - assume 1:1
}

/**
  * Writes Netscape application extension to define
  * repeat count.
  */
protected void writeNetscapeExt() throws IOException {
  out.write(0x21); // extension introducer
  out.write(0xff); // app extension label
  out.write(11); // block size
  writeString("NETSCAPE" + "2.0"); // app id + auth code
  out.write(3); // sub-block size
  out.write(1); // loop sub-block id
  writeShort(repeat); // loop count (extra iterations, 0=repeat forever)
  out.write(0); // block terminator
}

/**
  * Writes color table
  */
protected void writePalette() throws IOException {
  out.write(colorTab, 0, colorTab.length);
  int n = (3 * 256) - colorTab.length;
  for (int i = 0; i < n; i++) {
   out.write(0);
  }
}

/**
  * Encodes and writes pixel data
  */
protected void writePixels() throws IOException {
  LZWEncoder encoder =
   new LZWEncoder(width, height, indexedPixels, colorDepth);
  encoder.encode(out);
}

/**
  *    Write 16-bit value to output stream, LSB first
  */
protected void writeShort(int value) throws IOException {
  out.write(value & 0xff);
  out.write((value >> & 0xff);
}

/**
  * Writes string to output stream
  */
protected void writeString(String s) throws IOException {
  for (int i = 0; i < s.length(); i++) {
   out.write((byte) s.charAt(i));
  }
}
}
分享到:
评论

相关推荐

    AnimatedGifEncoder 类 c# 制作 gif 用到

    c# 使用图片制作 gif 的时候,需要用到一个类,那就是 AnimatedGifEncoder,使用的时候,把这个类复制进工程中,就可以使用相关类了。

    AnimatedGifEncoder NeuQuant LZWEncoder源码(图片处理)

    在给定的压缩包文件中,我们关注的是三个关键组件:`AnimatedGifEncoder`、`NeuQuant`和`LZWEncoder`,这些都是与处理GIF动图密切相关的类。以下是这些组件的详细解释和它们在图片处理中的应用。 1. ** ...

    AnimatedGifEncoder、LZWEncoder、GifDecoder、NeuQuant

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

    AnimatedGifEncoder.java源码(处理GIF图片)

    AnimatedGifEncoder.java源码(处理GIF图片)AnimatedGifEncoder.java源码(处理GIF图片)AnimatedGifEncoder.java源码(处理GIF图片)

    NGif.包含AnimatedGifEncoder、GifDecoder、GifEncoder、LZWEncoder、NeuQuant

    "NGif"是一个专为处理GIF文件而设计的类库,它包含了多种核心组件,如 AnimatedGifEncoder、GifDecoder、GifEncoder、LZWEncoder 和 NeuQuant,这些组件对于理解和操作GIF文件至关重要。 **AnimatedGifEncoder** 是...

    小工具-c#屏幕截图,录制GIF(AnimatedGifEncoder)-附件资源

    小工具-c#屏幕截图,录制GIF(AnimatedGifEncoder)-附件资源

    Gif.Components.dll

    gif处理,图像处理,Gif.Components.dll,AnimatedGifEncoder

    GIF解码和编码操作库源码

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

    GIF图片生成器(C#)

    在IT领域,C#是一种广泛使用的编程语言,尤其在开发桌面应用、游戏和网页服务方面。本项目" GIF图片生成器(C#)"是利用C#技术实现的一个实用工具,其目的是帮助用户创建、编辑和管理GIF动态图片。...

    多张jpg图合成gif动画.doc

    2、AnimatedGifEncoder类:在jpgToGif方法中,我们使用了AnimatedGifEncoder类来合成gif动画。这类是Java中使用最广泛的gif动画生成工具之一。AnimatedGifEncoder类提供了多种方法来控制gif动画的生成,例如设置播放...

    .net gif拆分和创建代码

    1. **初始化 `AnimatedGifEncoder` 实例**:首先创建一个 `AnimatedGifEncoder` 的实例,并指定输出文件路径。 2. **设置动画延迟时间**:通过调用 `SetDelay` 方法设置每帧之间的延迟时间,单位为毫秒。 3. **设置...

    关于Gif解析的java代码

    这里提到的四个源代码文件——`AnimatedGifEncoder.java`、`GifHelper.java`、`LZWencoder.java`和`NeuQuant.java`,它们分别扮演了不同的角色,共同构建了一个完整的GIF编码解决方案。 1. ** AnimatedGifEncoder....

    C# Gif屏幕录制工具

    /* * 名称:GIF屏幕录制demo * 作者:Crystal_lz * 时间:2016-03-18 * 博客:var.la,clzf.co(最近关闭) ... * 所以 代码并不是全部都是我写的 是网上下载的一个&lt;AnimatedGifEncoder&gt;来该的 */

    java 合成 gif

    在实际编程中,开发者首先会加载所有要合成的静态图像,然后创建`AnimatedGifEncoder`实例,为每一帧设置属性(如延迟时间、循环次数等),最后调用编码方法将图像序列写入到GIF文件中。 总的来说,Java合成GIF...

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

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

    gif的四个java类

    在Java编程环境中,处理图像文件,特别是动画GIF文件时,常常会涉及到四个核心类:`AnimatedGifEncoder`、`GifDecoder`、`LZWEncoder`和`NeuQuant`。这些类分别用于创建、解码和优化GIF图像。下面将详细解释每个类的...

    java 图片处理,水印,缩放,放大,叠加等功能

    `AnimatedGifEncoder`用于创建动态GIF,而`LZWEncoder`则是对Lempel-Ziv-Welch (LZW) 压缩算法的实现,这种压缩方式常用于GIF格式。 6. **代码示例** - `NeuQuant.java`可能是一个颜色量化算法,如NeuQuant,它...

Global site tag (gtag.js) - Google Analytics