Java中加载GIF太快,修复Java gif动画的帧速

I'm making a Java app that displays certain GIF files from a folder. I'm currently using the code

final JLabel imageLabel = new JLabel();

imageLabel.setIcon(new ImageIcon(fileName));

contentPane.add(imageLabel, java.awt.BorderLayout.CENTER);

This works flawlessly, except that many (thousands) of my .GIF files have a misconfigured frame rate which makes them display at infinite speed (frameDelay=0), assuming that the browser will fix this automatically. Java does not do this by default. How can I override the frameDelay Java has to use for those animated gifs with frameDelay=0?

解决方案

I've found this, and it works well for one gif I tried.

I have no idea what he's exactly doing, but at a glance it looks like if the first frame has a delay of 0 it overwrites the delay for all frames with 10. Then he 'writes' a new GIF file in memory and loads that to image.

[edit] I polished it up a bit and ironed out the bugs.

No proprietary API

Doesn't just check the 1st frame to determine if it's bugged,

Replaces delay only for frames where it's zero.

public static Image readImgFromFile(String filename, Component parent) {

File file = new File(filename);

if (!file.exists()) {

return null;

}

// Fix for bug when delay is 0

try {

// Load anything but GIF the normal way

if (!filename.substring(filename.length() - 4).equalsIgnoreCase(".gif")) {

return ImageIO.read(file);

}

// Get GIF reader

ImageReader reader = ImageIO.getImageReadersByFormatName("gif").next();

// Give it the stream to decode from

reader.setInput(ImageIO.createImageInputStream(file));

int numImages = reader.getNumImages(true);

// Get 'metaFormatName'. Need first frame for that.

IIOMetadata imageMetaData = reader.getImageMetadata(0);

String metaFormatName = imageMetaData.getNativeMetadataFormatName();

// Find out if GIF is bugged

boolean foundBug = false;

for (int i = 0; i < numImages && !foundBug; i++) {

// Get metadata

IIOMetadataNode root = (IIOMetadataNode)reader.getImageMetadata(i).getAsTree(metaFormatName);

// Find GraphicControlExtension node

int nNodes = root.getLength();

for (int j = 0; j < nNodes; j++) {

Node node = root.item(j);

if (node.getNodeName().equalsIgnoreCase("GraphicControlExtension")) {

// Get delay value

String delay = ((IIOMetadataNode)node).getAttribute("delayTime");

// Check if delay is bugged

if (Integer.parseInt(delay) == 0) {

foundBug = true;

}

break;

}

}

}

// Load non-bugged GIF the normal way

Image image;

if (!foundBug) {

image = Toolkit.getDefaultToolkit().createImage(filename);

} else {

// Prepare streams for image encoding

ByteArrayOutputStream baoStream = new ByteArrayOutputStream();

try (ImageOutputStream ios = ImageIO.createImageOutputStream(baoStream)) {

// Get GIF writer that's compatible with reader

ImageWriter writer = ImageIO.getImageWriter(reader);

// Give it the stream to encode to

writer.setOutput(ios);

writer.prepareWriteSequence(null);

for (int i = 0; i < numImages; i++) {

// Get input image

BufferedImage frameIn = reader.read(i);

// Get input metadata

IIOMetadataNode root = (IIOMetadataNode)reader.getImageMetadata(i).getAsTree(metaFormatName);

// Find GraphicControlExtension node

int nNodes = root.getLength();

for (int j = 0; j < nNodes; j++) {

Node node = root.item(j);

if (node.getNodeName().equalsIgnoreCase("GraphicControlExtension")) {

// Get delay value

String delay = ((IIOMetadataNode)node).getAttribute("delayTime");

// Check if delay is bugged

if (Integer.parseInt(delay) == 0) {

// Overwrite with a valid delay value

((IIOMetadataNode)node).setAttribute("delayTime", "10");

}

break;

}

}

// Create output metadata

IIOMetadata metadata = writer.getDefaultImageMetadata(new ImageTypeSpecifier(frameIn), null);

// Copy metadata to output metadata

metadata.setFromTree(metadata.getNativeMetadataFormatName(), root);

// Create output image

IIOImage frameOut = new IIOImage(frameIn, null, metadata);

// Encode output image

writer.writeToSequence(frameOut, writer.getDefaultWriteParam());

}

writer.endWriteSequence();

}

// Create image using encoded data

image = Toolkit.getDefaultToolkit().createImage(baoStream.toByteArray());

}

// Trigger lazy loading of image

MediaTracker mt = new MediaTracker(parent);

mt.addImage(image, 0);

try {

mt.waitForAll();

}

catch (InterruptedException e) {

image = null;

}

return image;

}

catch (IOException e) {

e.printStackTrace();

return null;

}

}

Java在窗口上加载显示GIF动画图像,将多个独立的GIF图像串联在一起显示,形成GIF特有的动画形式。主要代码如下:   ImageIcon[] images; //用于动画的图标数组   Timer animationTimer;   int currentImage = 0; //当前图像编号   int delay = 500; //图像切换延迟   int width; //图像宽度   int height; //图像高度   public AnimatorIcon() //构造函数   {    setBackground(Color.white);    images = new ImageIcon[2]; //初始化数组    for (int i=0;i   images[i]=new ImageIcon(getClass().getResource("image" i ".gif")); //实例化图标    width = images[0].getIconWidth(); //初始化宽度值    height = images[0].getIconHeight(); //初始化高度值   }   public void paintComponent(Graphics g) { //重载组件绘制方法    super.paintComponent(g); //调用父类函数    images[currentImage].paintIcon(this,g,70,0); //绘制图标    currentImage=(currentImage 1)%2; //更改当前图像编号   }   public void actionPerformed(ActionEvent actionEvent) {    repaint();   }   public void startAnimation() { //开始动画    if (animationTimer==null) {    currentImage=0;    animationTimer=new Timer(delay, this); //实例化Timer对象    animationTimer.start(); //开始运行    } else if (!animationTimer.isRunning()) //如果没有运行    animationTimer.restart(); //重新运行   }   public void stopAnimation() {    animationTimer.stop(); //停止动画   }   public static void main(String args[]) {    AnimatorIcon animation = new AnimatorIcon(); //实例化动画图标    JFrame frame = new JFrame("动画图标"); //实例化窗口对象    frame.getContentPane().add(animation); //增加组件到窗口上    frame.setSize(200, 100); //设置窗口尺寸    frame.setVisible(true); //设置窗口可视    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //关闭窗口时退出程序    animation.startAnimation(); //开始动画
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值