让swing正确显示gif图片

  今天美工做了一幅gif的图片,我放到JLabel里面去,gif图片闪动得特别厉害。以为美工提供的图片有问题,又双击用IE打开,却显示正常。心想应该是java组建对gif图片显示的问题。网上查了下swing对gif的显示。果不其然,是swing对gif的显示问题。下面整理下处理swing正确显示gif图片的问题。

首先需要对Gif这种图片格式有一些基本认识。
第一:Gif由一系列Image组成,也就是桢,Gif动画就是连续地显示这些桢,但是这还不够。
第二:无论某一时刻轮循到哪一桢,第1桢,总是要当作背景画出来,而且第1桢也是所有桢当中最长最高的,它的尺寸也是整个Gif图象的尺寸,位置从(0, 0)开始,其余各桢可能只是描述与相临各桢变化的部分,所以长和高要小且不完整,起始位置是该桢相对整体背景的位置。(这点SWT也是这样做的)
第三:Gif动画连续显示不一定是各个桢轮循单独显示,而是不仅仅显示当前该显示的桢,还要向前追溯到"第一桢",从"第一桢"开始到当前应该显示的桢组成的连续一系列"桢簇",所以某一时刻单单显示背景和当前桢是不够的,而是显示背景和当前"桢簇"。""桢簇""是我自己取的名字,而且我看SWT轮循的例子中并没有用到"桢簇",而是传统的单桢轮循。但是同样的方法对Swing不奏效,现在我对此还不得其解。关于"第一桢",是和com.sun.imageio.plugins.gif.GIFImageMetadata类的disposalMethod属性有关,在SWT中这个属性是org.eclipse.swt.graphics.ImageData.disposalMethod。disposalMethod据我的研究是描述处理桢的方法,常见的disposalMethod取值有none(取值0,不处理)、Background(取值2,背景)两种,所谓的当前桢的"第一桢"就是向前追溯到最近的disposalMethod取值为2的那一桢的下一桢,也就是说或者"第一桢"的前一桢的disposalMethod取值为2,或者"第一桢"就是Gif索引为2的桢,因为Gif的第1桢总要当背景显示。
第四:桢的元数据在SWT中用org.eclipse.swt.graphics.ImageData类封装,在Swing中对应的是com.sun.imageio.plugins.gif.GIFImageMetadata(可是截止到JDK6.0 u11,这个类的版本号还是0.5,有些另人失望:(),可以通过次类获取到delayTime这个属性,也就是下一桢的间隔时间,但是有很多Gif,这个值总是0,所以Swing显示频率相当的快。

下面为处理代码:

public class GifComponent extends JComponent {
    private static final long serialVersionUID = 1L;
    private GifBean[] gifBeans;
    private Map<Integer, Integer[]> gifBeanMap = new HashMap<Integer, Integer[]>();
    private int index = 0;
    private int delayFactor;
    private Timer timer;

    /**
     * 
     * @param gifFile
     * @param delayFactor
     *            显示gif每帧图片的时间因子
     */
    public GifComponent(File gifFile, int delayFactor) {
	setDelayFactor(delayFactor);
	setGifFile(gifFile);
    }

    /**
     * 设置Gif文件
     * 
     * @param gifFile
     */
    public void setGifFile(File gifFile) {
	ImageReader reader = null;
	try {
	    ImageInputStream imageIn = ImageIO.createImageInputStream(gifFile);
	    Iterator<ImageReader> iter = ImageIO
		    .getImageReadersByFormatName("gif");
	    if (iter.hasNext()) {
		reader = iter.next();
	    }
	    reader.setInput(imageIn, false);
	    gifBeanMap.clear();
	    gifBeans = new GifBean[reader.getNumImages(true)];
	    GIFImageMetadata meta = null;
	    for (int i = 0; i < gifBeans.length; i++) {
		meta = (GIFImageMetadata) reader.getImageMetadata(i);
		gifBeans[i] = new GifBean();
		gifBeans[i].image = reader.read(i);
		gifBeans[i].x = meta.imageLeftPosition;
		gifBeans[i].y = meta.imageTopPosition;
		gifBeans[i].width = meta.imageWidth;
		gifBeans[i].height = meta.imageHeight;
		gifBeans[i].disposalMethod = meta.disposalMethod;
		gifBeans[i].delayTime = meta.delayTime == 0 ? 1
			: meta.delayTime;
	    }
	    for (int i = 1; i < gifBeans.length; i++) {
		if (gifBeans[i].disposalMethod == 2) {
		    gifBeanMap.put(new Integer(i), new Integer[] { i });
		    continue;
		}
		int firstIndex = getFirstIndex(i);
		List<Integer> list = new ArrayList<Integer>();
		for (int j = firstIndex; j <= i; j++) {
		    list.add(j);
		}
		gifBeanMap.put(new Integer(i), list.toArray(new Integer[] {}));
	    }
	} catch (IOException e) {
	    e.printStackTrace();
	}
	setTimer();
    }

    private synchronized void setTimer() {
	if (timer != null) {
	    timer.cancel();
	}
	timer = new Timer("show gif");
	timer.schedule(new TimerTask() {
	    @Override
	    public void run() {
		repaint();
		try {
		    Thread.sleep(gifBeans[index].delayTime * delayFactor);
		} catch (InterruptedException e) {
		}
		index++;
		if (index >= gifBeans.length) {
		    index = 0;
		}
	    }

	}, 0, 1);

    }

    /**
     * 设置时间因子
     * 
     * @param delayFactor
     */
    public void setDelayFactor(int delayFactor) {
	this.delayFactor = delayFactor;
    }

    @Override
    protected void paintComponent(Graphics g) {
	g.drawImage(gifBeans[0].image, gifBeans[0].x, gifBeans[0].y, this);
	if (index > 0) {
	    Integer[] array = gifBeanMap.get(index);
	    for (Integer i : array) {
		g.drawImage(gifBeans[i].image, gifBeans[i].x, gifBeans[i].y,
			this);
	    }
	}
    }

    private int getFirstIndex(int index) {
	int tempIndex = index;
	while (tempIndex > 1) {
	    if (tempIndex - 1 > 0
		    && gifBeans[tempIndex - 1].disposalMethod == 2) {
		return index;
	    }
	    tempIndex--;
	}
	return tempIndex;
    }

    /**
     * 用于保持gif每帧图片的信息
     */
    public class GifBean {
	public BufferedImage image;
	public int x;
	public int y;
	public int width;
	public int height;
	public int disposalMethod;
	public int delayTime;
    }

}


 

原文参考:http://space.itpub.net/13685345/viewspace-514315 

 

你可能感兴趣的:(让swing正确显示gif图片)