在Java中修复动画gif的帧速率

我正在制作一个Java应用程序,显示文件夹中的某些GIF文件。 我目前正在使用该代码

final JLabel imageLabel = new JLabel(); imageLabel.setIcon(new ImageIcon(fileName)); contentPane.add(imageLabel, java.awt.BorderLayout.CENTER); 

这完美无缺,除了我的.GIF文件中有很多(数千)具有错误配置的帧速率,这使得它们以无限速度显示(frameDelay = 0),假设浏览器将自动修复此问题。 默认情况下,Java不会这样做。 如何覆盖frameDelay Java必须用于frameDelay = 0的GIF动画?

我发现了这个 ,它适用于我试过的一个gif。

我不知道他到底在做什么,但是看起来如果第一帧的延迟为0它会覆盖所有帧的延迟为10.然后他在内存中“写入”一个新的GIF文件并将其加载到图片。

[编辑]我把它打磨了一下,然后解决了这些问题。

  • 没有专有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; } }