修复 Java 中动画 gif 的帧率 [英] fix frame rate of animated gif in Java
问题描述
我正在制作一个 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);
这完美无缺,除了我的许多(数千个).GIF 文件的帧速率配置错误,这使得它们以无限速度显示 (frameDelay=0),假设浏览器会自动修复此问题.Java 默认不这样做.如何使用 frameDelay=0 覆盖 Java 必须用于那些 gif 动画的 frameDelay?
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?
推荐答案
我找到了这个,它适用于我试过的一个 gif.
I've found this, and it works well for one gif I tried.
我不知道他到底在做什么,但乍一看就像如果第一帧的延迟为 0,它会用 10 覆盖所有帧的延迟.然后他写"在内存中创建一个新的 GIF 文件并将其加载到图像中.
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] 我稍微打磨了一下并解决了错误.
[edit] I polished it up a bit and ironed out the bugs.
- 没有专有 API
- 不只是检查第一帧以确定它是否被窃听,
- 仅替换延迟为零的帧.
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 的帧率的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!