【问题标题】:Animated gif with varying frame rates loading incorrectly using Java使用 Java 错误加载不同帧速率的动画 gif
【发布时间】:2026-01-24 15:00:01
【问题描述】:

我想我刚刚查明了问题所在,但我仍然不确定该怎么做。

我使用 Photoshop 创建了各种动画 gif,我想在我的 Java 应用程序中显示它们。使用 ImageIcon,其中一些会按应有的方式显示。那些具有相同帧速率的帧(例如每帧长 1 秒)。但是,具有不同帧速率(例如,一帧是 1 秒,另一帧是 0.5 秒,下一帧是 0.2)的 gif 似乎无法正确显示。一旦 gif 到达以秒为单位的帧,图像就会混乱。一些示例包括背景短暂改变颜色和一半图像消失,或者大部分图像消失但 gif 仍在动画中。

我很难表达,但我是否需要使用 ImageIcon 以外的其他东西来正确加载具有不同帧速率的 gif?喜欢 BufferedImage 的东西?

编辑:在下面添加了完整的代码。同样,它适用于具有相同帧速率的图像,但不适用于具有不同帧速率的图像。

here is the image that works fine

here is the image that messes up

import java.awt.*;

import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JWindow;


public class Creature extends JWindow {
    public void initCreature() {

        JPanel contentPane = (JPanel) getContentPane();
        ImageIcon idleImage = new ImageIcon(getClass().getResource("img.gif"));

        // Set window properties
        getRootPane().putClientProperty("Window.shadow", false);
        setBackground(new Color(0,0,0,0));
        setAlwaysOnTop(true);
        contentPane.setOpaque(false);

        // Get size of user's screen
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        GraphicsDevice defaultScreen = ge.getDefaultScreenDevice();
        Rectangle screen = defaultScreen.getDefaultConfiguration().getBounds();
        int taskbarheight = (int) (Toolkit.getDefaultToolkit().getScreenSize().height 
        - GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds().getHeight());

        int x = (int) screen.getMaxX() - idleImage.getIconWidth();
        int y = (int) screen.getMaxY() - idleImage.getIconHeight() - taskbarheight;

        JLabel imageLabel = new JLabel(idleImage);
        setSize(idleImage.getIconWidth(), idleImage.getIconHeight());
        contentPane.add(imageLabel);
        setLocation(x, y);
        setVisible(true);
    }

    public static void main(String[] args) {

        EventQueue.invokeLater(new Runnable() {
            public void run() {
                Creature cr = new Creature();
                cr.initCreature();          
            }
        });

    }
}

【问题讨论】:

  • 发布您的代码的最小示例以了解可能出现的问题。
  • 添加到原始帖子。我开始认为我可能应该使用 ImageIcon 以外的其他东西
  • 1) 为了尽快获得更好的帮助,请发帖 minimal reproducible exampleShort, Self Contained, Correct Example。 2) 将行为不端的图像上传到图像共享网站并链接到它。
  • 感谢安德鲁,再次修复了我的帖子并添加了完整的程序+图片链接。鉴于我经常潜伏在这里,我会想知道如何最好地发帖。
  • 两个版本的帧速率似乎相同(一个在浏览器中看到,另一个在JLabel 中看到)。我猜我会说问题在于 PhotoShop 正在使用高级编码来确保只有 帧中发生变化的部分被更新。请注意,尽管 Java 支持特定的 文件类型,如 GIF、PNG 或 JPEG,但这并不意味着它正确理解每种文件类型的每种 编码 类型。一个更简单的图像,每次更改都会更改整个帧应该会更好,但字节数也会更大。

标签: java swing animated-gif frame-rate


【解决方案1】:

两个版本的帧速率似乎相同(一个在浏览器中看到,另一个在JLabel 中看到)。实际的问题是,Java 中的渲染在动画的不变区域中被“剪辑”了。

我猜我会说问题在于 PhotoShop 正在使用高级编码来确保只有 帧中发生变化的部分会被更新。请注意,尽管 Java 支持特定的文件类型,例如 GIF、PNG 或 JPEG,但这并不意味着它可以正确理解每种文件类型的每种 编码 类型。

一个更简单的图像,每次更改都会更改整个帧,应该会更好,但字节数也会更大。实际上,您可以在其他图像中看到它的工作原理。因为小龙是弯腰然后又站起来的,所以可见图像的所有部分都需要改变,所以它的动画不能像第一张图像那样优化。

【讨论】:

  • 我尝试了不同的 gif 生成器(Easy Gif Animator)并制作了另一个动画。如果每一帧都具有相同的延迟,它应该可以正常工作,就像 Photoshop 制作的 gif 一样(例如帧 1 是 0.5 秒,帧 2 是 0.5 秒等),但如果每个帧有不同的延迟,它也会显示混乱帧(我希望闪烁帧的长度为 0.2 秒,而其他帧的长度为 0.5 秒。这就是问题所在)。即使我用完全不同的图像更改了 0.2 秒的帧,它似乎仍然这样做。那好吧。谢谢您的帮助!我将开始修补动画本身。
  • 没关系,我不知道发生了什么。我在 Easy Gif Animator 中使用龙坐着的图片制作了第二个动画。闪烁的帧仍然比其他帧具有更短的延迟。它最终工作了。我什至不知道。这变得比我想要的更令人困惑。
【解决方案2】:

imageLabel 不知道在 GIF 的帧发生变化时重新绘制。您需要通过将 JLabel 传递给 setImageObserver 来告诉 ImageIcon 通知 JLabel 帧更改:

idleImage.setImageObserver(imageLabel);

来自该方法的文档:

如果 ImageIcon 包含动画 GIF,则设置此属性,以便通知观察者更新其显示。

【讨论】:

  • 我只应该添加那个吗?还是别的什么?如果我只是在初始化 JLabel 后添加那行代码,似乎什么都没有改变。无论如何,我都会阅读更多相关信息
  • 现在我可以访问 GIF,我通过运行一个简单的测试发现我的答案没有解决问题。 Andrew Thompson 的回答是最好的:如果可能,将图像更改为包含完整帧而不是增量帧。这可能应该报告为 Java 错误。
  • 我做了更多的实验,这似乎是艺术程序如何用不同的延迟时间对动画进行编码......也许java会自动假设每一帧都有相同的延迟时间并根据它重新绘制那?尽管我只是在 Easy Gif Animator 上制作了一个具有不同帧延迟的动画(与我第一次使用 Photoshop 时相比),即使我在 Easy Gif Animator 上的其他动画被搞砸了。我不知道是怎么回事。无论如何感谢您的帮助!