?? gif89encoder.java
字號:
//******************************************************************************
// Gif89Encoder.java
//******************************************************************************
package net.jmge.gif;
import java.awt.*;
import java.io.*;
import java.util.Vector;
//==============================================================================
/** This is the central class of a JDK 1.1 compatible GIF encoder that, AFAIK,
* supports more features of the extended GIF spec than any other Java open
* source encoder. Some sections of the source are lifted or adapted from Jef
* Poskanzer's <cite>Acme GifEncoder</cite> (so please see the
* <a href="../readme.txt">readme</a> containing his notice), but much of it,
* including nearly all of the present class, is original code. My main
* motivation for writing a new encoder was to support animated GIFs, but the
* package also adds support for embedded textual comments.
* <p>
* There are still some limitations. For instance, animations are limited to
* a single global color table. But that is usually what you want anyway, so
* as to avoid irregularities on some displays. (So this is not really a
* limitation, but a "disciplinary feature" :) Another rather more serious
* restriction is that the total number of RGB colors in a given input-batch
* mustn't exceed 256. Obviously, there is an opening here for someone who
* would like to add a color-reducing preprocessor.
* <p>
* The encoder, though very usable in its present form, is at bottom only a
* partial implementation skewed toward my own particular needs. Hence a
* couple of caveats are in order. (1) During development it was in the back
* of my mind that an encoder object should be reusable - i.e., you should be
* able to make multiple calls to encode() on the same object, with or without
* intervening frame additions or changes to options. But I haven't reviewed
* the code with such usage in mind, much less tested it, so it's likely I
* overlooked something. (2) The encoder classes aren't thread safe, so use
* caution in a context where access is shared by multiple threads. (Better
* yet, finish the library and re-release it :)
* <p>
* There follow a couple of simple examples illustrating the most common way to
* use the encoder, i.e., to encode AWT Image objects created elsewhere in the
* program. Use of some of the most popular format options is also shown,
* though you will want to peruse the API for additional features.
*
* <p>
* <strong>Animated GIF Example</strong>
* <pre>
* import net.jmge.gif.Gif89Encoder;
* // ...
* void writeAnimatedGIF(Image[] still_images,
* String annotation,
* boolean looped,
* double frames_per_second,
* OutputStream out) throws IOException
* {
* Gif89Encoder gifenc = new Gif89Encoder();
* for (int i = 0; i < still_images.length; ++i)
* gifenc.addFrame(still_images[i]);
* gifenc.setComments(annotation);
* gifenc.setLoopCount(looped ? 0 : 1);
* gifenc.setUniformDelay((int) Math.round(100 / frames_per_second));
* gifenc.encode(out);
* }
* </pre>
*
* <strong>Static GIF Example</strong>
* <pre>
* import net.jmge.gif.Gif89Encoder;
* // ...
* void writeNormalGIF(Image img,
* String annotation,
* int transparent_index, // pass -1 for none
* boolean interlaced,
* OutputStream out) throws IOException
* {
* Gif89Encoder gifenc = new Gif89Encoder(img);
* gifenc.setComments(annotation);
* gifenc.setTransparentIndex(transparent_index);
* gifenc.getFrameAt(0).setInterlaced(interlaced);
* gifenc.encode(out);
* }
* </pre>
*
* @version 0.90 beta (15-Jul-2000)
* @author J. M. G. Elliott (tep@jmge.net)
* @see Gif89Frame
* @see DirectGif89Frame
* @see IndexGif89Frame
*/
public class Gif89Encoder {
private Dimension dispDim = new Dimension(0, 0);
private GifColorTable colorTable;
private int bgIndex = 0;
private int loopCount = 1;
private String theComments;
private Vector vFrames = new Vector();
//----------------------------------------------------------------------------
/** Use this default constructor if you'll be adding multiple frames
* constructed from RGB data (i.e., AWT Image objects or ARGB-pixel arrays).
*/
public Gif89Encoder()
{
// empty color table puts us into "palette autodetect" mode
colorTable = new GifColorTable();
}
//----------------------------------------------------------------------------
/** Like the default except that it also adds a single frame, for conveniently
* encoding a static GIF from an image.
*
* @param static_image
* Any Image object that supports pixel-grabbing.
* @exception IOException
* See the addFrame() methods.
*/
public Gif89Encoder(Image static_image) throws IOException
{
this();
addFrame(static_image);
}
//----------------------------------------------------------------------------
/** This constructor installs a user color table, overriding the detection of
* of a palette from ARBG pixels.
*
* Use of this constructor imposes a couple of restrictions:
* (1) Frame objects can't be of type DirectGif89Frame
* (2) Transparency, if desired, must be set explicitly.
*
* @param colors
* Array of color values; no more than 256 colors will be read, since that's
* the limit for a GIF.
*/
public Gif89Encoder(Color[] colors)
{
colorTable = new GifColorTable(colors);
}
//----------------------------------------------------------------------------
/** Convenience constructor for encoding a static GIF from index-model data.
* Adds a single frame as specified.
*
* @param colors
* Array of color values; no more than 256 colors will be read, since
* that's the limit for a GIF.
* @param width
* Width of the GIF bitmap.
* @param height
* Height of same.
* @param ci_pixels
* Array of color-index pixels no less than width * height in length.
* @exception IOException
* See the addFrame() methods.
*/
public Gif89Encoder(Color[] colors, int width, int height, byte ci_pixels[])
throws IOException
{
this(colors);
addFrame(width, height, ci_pixels);
}
//----------------------------------------------------------------------------
/** Get the number of frames that have been added so far.
*
* @return
* Number of frame items.
*/
public int getFrameCount() { return vFrames.size(); }
//----------------------------------------------------------------------------
/** Get a reference back to a Gif89Frame object by position.
*
* @param index
* Zero-based index of the frame in the sequence.
* @return
* Gif89Frame object at the specified position (or null if no such frame).
*/
public Gif89Frame getFrameAt(int index)
{
return isOk(index) ? (Gif89Frame) vFrames.elementAt(index) : null;
}
//----------------------------------------------------------------------------
/** Add a Gif89Frame frame to the end of the internal sequence. Note that
* there are restrictions on the Gif89Frame type: if the encoder object was
* constructed with an explicit color table, an attempt to add a
* DirectGif89Frame will throw an exception.
*
* @param gf
* An externally constructed Gif89Frame.
* @exception IOException
* If Gif89Frame can't be accommodated. This could happen if either (1) the
* aggregate cross-frame RGB color count exceeds 256, or (2) the Gif89Frame
* subclass is incompatible with the present encoder object.
*/
public void addFrame(Gif89Frame gf) throws IOException
{
accommodateFrame(gf);
vFrames.addElement(gf);
}
//----------------------------------------------------------------------------
/** Convenience version of addFrame() that takes a Java Image, internally
* constructing the requisite DirectGif89Frame.
*
* @param image
* Any Image object that supports pixel-grabbing.
* @exception IOException
* If either (1) pixel-grabbing fails, (2) the aggregate cross-frame RGB
* color count exceeds 256, or (3) this encoder object was constructed with
* an explicit color table.
*/
public void addFrame(Image image) throws IOException
{
addFrame(new DirectGif89Frame(image));
}
//----------------------------------------------------------------------------
/** The index-model convenience version of addFrame().
*
* @param width
* Width of the GIF bitmap.
* @param height
* Height of same.
* @param ci_pixels
* Array of color-index pixels no less than width * height in length.
* @exception IOException
* Actually, in the present implementation, there aren't any unchecked
* exceptions that can be thrown when adding an IndexGif89Frame
* <i>per se</i>. But I might add some pedantic check later, to justify the
* generality :)
*/
public void addFrame(int width, int height, byte ci_pixels[])
throws IOException
{
addFrame(new IndexGif89Frame(width, height, ci_pixels));
}
//----------------------------------------------------------------------------
/** Like addFrame() except that the frame is inserted at a specific point in
* the sequence rather than appended.
*
* @param index
* Zero-based index at which to insert frame.
* @param gf
* An externally constructed Gif89Frame.
* @exception IOException
* If Gif89Frame can't be accommodated. This could happen if either (1)
* the aggregate cross-frame RGB color count exceeds 256, or (2) the
* Gif89Frame subclass is incompatible with the present encoder object.
*/
public void insertFrame(int index, Gif89Frame gf) throws IOException
{
accommodateFrame(gf);
vFrames.insertElementAt(gf, index);
}
//----------------------------------------------------------------------------
/** Set the color table index for the transparent color, if any.
*
* @param index
* Index of the color that should be rendered as transparent, if any.
* A value of -1 turns off transparency. (Default: -1)
*/
public void setTransparentIndex(int index)
{
colorTable.setTransparent(index);
}
//----------------------------------------------------------------------------
/** Sets attributes of the multi-image display area, if applicable.
*
* @param dim
* Width/height of display. (Default: largest detected frame size)
* @param background
* Color table index of background color. (Default: 0)
* @see Gif89Frame#setPosition
*/
public void setLogicalDisplay(Dimension dim, int background)
{
dispDim = new Dimension(dim);
bgIndex = background;
}
//----------------------------------------------------------------------------
/** Set animation looping parameter, if applicable.
*
* @param count
* Number of times to play sequence. Special value of 0 specifies
* indefinite looping. (Default: 1)
*/
public void setLoopCount(int count)
{
loopCount = count;
}
//----------------------------------------------------------------------------
/** Specify some textual comments to be embedded in GIF.
*
* @param comments
* String containing ASCII comments.
*/
public void setComments(String comments)
{
theComments = comments;
}
//----------------------------------------------------------------------------
/** A convenience method for setting the "animation speed". It simply sets
* the delay parameter for each frame in the sequence to the supplied value.
* Since this is actually frame-level rather than animation-level data, take
* care to add your frames before calling this method.
*
* @param interval
* Interframe interval in centiseconds.
*/
public void setUniformDelay(int interval)
{
for (int i = 0; i < vFrames.size(); ++i)
((Gif89Frame) vFrames.elementAt(i)).setDelay(interval);
}
//----------------------------------------------------------------------------
/** After adding your frame(s) and setting your options, simply call this
* method to write the GIF to the passed stream. Multiple calls are
* permissible if for some reason that is useful to your application. (The
* method simply encodes the current state of the object with no thought
* to previous calls.)
*
* @param out
* The stream you want the GIF written to.
* @exception IOException
* If a write error is encountered.
*/
public void encode(OutputStream out) throws IOException
{
int nframes = getFrameCount();
boolean is_sequence = nframes > 1;
// N.B. must be called before writing screen descriptor
colorTable.closePixelProcessing();
// write GIF HEADER
Put.ascii("GIF89a", out);
// write global blocks
writeLogicalScreenDescriptor(out);
colorTable.encode(out);
if (is_sequence && loopCount != 1)
writeNetscapeExtension(out);
if (theComments != null && theComments.length() > 0)
writeCommentExtension(out);
// write out the control and rendering data for each frame
for (int i = 0; i < nframes; ++i)
((Gif89Frame) vFrames.elementAt(i)).encode(
out, is_sequence, colorTable.getDepth(), colorTable.getTransparent()
);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -