⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gif89encoder.java

📁 Gif89Encoder! JAVA环境下应用!
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
//******************************************************************************
// 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 + -