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

import java.io.*;

import java.awt.*;

import java.awt.image.*;

/**

* Class AnimatedGifEncoder - Encodes a GIF file consisting of one or

* more frames.

 
 

* Example:

*    AnimatedGifEncoder e = new AnimatedGifEncoder();

*    e.start(outputFileName);

*    e.setDelay(1000);   // 1 frame per sec

*    e.addFrame(image1);

*    e.addFrame(image2);

*    e.finish();

* 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 finish() flushes all

* frames.  If setSize 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

setDelay(1000/fps).

*

* @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 

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 

if (height 

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 

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 

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 

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 = 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 

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 >> 8) & 0xff);

}

/**

* Writes string to output stream

*/

protected void writeString(String s) throws IOException {

for (int i = 0; i 

out.write((byte) s.charAt(i));

}

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值