Java GIF 动画无法正确重画

2023-12-04

我正在尝试为 GIF 图像制作动画。动画可以,但画得不好。

It shows like this (non-animated screenshot): How I see it

In the image, the tail wags like this: This was the image I used

正如您所看到的,图像重绘效果不佳。我不想使用 JLabels 但它不能正常工作,所以我遵循当我的图像没有动画时这个问题.

我的代码是这样的:

public void draw(JPanel canvas, Graphics2D g2d, int x, int y) {
    getFrontImage().paintIcon(canvas, g2d, x, y);
}

图像的检索和保存位置如下:

ImageIcon gif = new ImageIcon(getClass().getResource(filename));

在 JPanel 画布中,我创建了一个绘制方法和一个每 10 毫秒重新绘制一次的计时器线程。这适用于除 GIF 之外的所有内容。谁能帮我解决这个问题?

--- Edit

很抱歉造成误解,我已将图像更新为我实际使用的图像。我希望得到正确的答案不会太麻烦......


好吧,经过一番思考后,我终于能够将框架的处置方法更改为restoreToBackgroundColor。基本上,这意味着动画不是增量变化,而是完整的帧替换......

PicaGif

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class AnimatedGifTest1 {

    public static void main(String[] args) {
        new AnimatedGifTest1();
    }

    public AnimatedGifTest1() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new PaintPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class PaintPane extends JPanel {

        private ImageIcon image;

        public PaintPane() {
            image = new ImageIcon(getClass().getResource("/ertcM02.gif"));
            Timer timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    repaint();
                }
            });
            timer.start();
        }

        @Override
        public Dimension getPreferredSize() {
            return image == null ? new Dimension(200, 200) : new Dimension(image.getIconWidth(), image.getIconHeight());
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g); // This is very important!
            int x = (getWidth() - image.getIconWidth()) / 2;
            int y = (getHeight() - image.getIconHeight()) / 2;
            image.paintIcon(this, g, x, y);
        }

    }



}

更新...

所以,我终于能够看看你正在使用的gif的处理方法,它被设置为restoreToPrevious,其中,根据图形交换格式版本 89a means:

恢复到以前的状态。解码器需要将被图形覆盖的区域恢复为渲染图形之前的区域。

我上面提供的图像在哪里使用restoreToBackgroundColor,根据图形交换格式版本 89a means:

恢复为背景颜色。图形使用的区域必须恢复为背景颜色

您可以使用以下代码自行检查...

public static class AnimatedGif {

    public enum DisposalMethod {

        RESTORE_TO_BACKGROUND,
        RESTORE_TO_PREVIOUS,
        DO_NOT_DISPOSE,
        UNSPECIFIED;

        public static DisposalMethod find(String text) {

            DisposalMethod dm = UNSPECIFIED;
            System.out.println(text);

            switch (text) {
                case "restoreToBackgroundColor":
                    dm = RESTORE_TO_BACKGROUND;
                    break;
                case "restoreToPrevious":
                    dm = RESTORE_TO_PREVIOUS;
                    break;
            }

            return dm;

        }
    }

    private List<ImageFrame> frames;
    private int frame;

    public AnimatedGif(JComponent player, URL url) throws IOException {
        frames = new ArrayList<>(25);
        try (InputStream is = url.openStream(); ImageInputStream stream = ImageIO.createImageInputStream(is)) {
            Iterator readers = ImageIO.getImageReaders(stream);
            if (!readers.hasNext()) {
                throw new RuntimeException("no image reader found");
            }
            ImageReader reader = (ImageReader) readers.next();
            reader.setInput(stream);            // don't omit this line!
            int n = reader.getNumImages(true);  // don't use false!
            System.out.println("numImages = " + n);
            for (int i = 0; i < n; i++) {
                BufferedImage image = reader.read(i);
                ImageFrame imageFrame = new ImageFrame(image);

                IIOMetadata imd = reader.getImageMetadata(i);
                Node tree = imd.getAsTree("javax_imageio_gif_image_1.0");
                NodeList children = tree.getChildNodes();

                for (int j = 0; j < children.getLength(); j++) {
                    Node nodeItem = children.item(j);
                    NamedNodeMap attr = nodeItem.getAttributes();
                    switch (nodeItem.getNodeName()) {
                        case "ImageDescriptor":
                            ImageDescriptor id = new ImageDescriptor(
                                            getIntValue(attr.getNamedItem("imageLeftPosition")),
                                            getIntValue(attr.getNamedItem("imageTopPosition")),
                                            getIntValue(attr.getNamedItem("imageWidth")),
                                            getIntValue(attr.getNamedItem("imageHeight")),
                                            getBooleanValue(attr.getNamedItem("interlaceFlag")));
                            imageFrame.setImageDescriptor(id);
                            break;
                        case "GraphicControlExtension":
                            GraphicControlExtension gc = new GraphicControlExtension(
                                            DisposalMethod.find(getNodeValue(attr.getNamedItem("disposalMethod"))),
                                            getBooleanValue(attr.getNamedItem("userInputFlag")),
                                            getBooleanValue(attr.getNamedItem("transparentColorFlag")),
                                            getIntValue(attr.getNamedItem("delayTime")) * 10,
                                            getIntValue(attr.getNamedItem("transparentColorIndex")));
                            imageFrame.setGraphicControlExtension(gc);
                            break;
                    }
                }
                frames.add(imageFrame);
            }
        } finally {
        }
    }

    protected String getNodeValue(Node node) {
        return node == null ? null : node.getNodeValue();
    }

    protected int getIntValue(Node node) {
        return node == null ? 0 : getIntValue(node.getNodeValue());
    }

    protected boolean getBooleanValue(Node node) {
        return node == null ? false : getBooleanValue(node.getNodeValue());
    }

    protected int getIntValue(String value) {
        return value == null ? 0 : Integer.parseInt(value);
    }

    protected boolean getBooleanValue(String value) {
        return value == null ? false : Boolean.parseBoolean(value);
    }

    public class ImageFrame {

        private BufferedImage image;
        private ImageDescriptor imageDescriptor;
        private GraphicControlExtension graphicControlExtension;

        public ImageFrame(BufferedImage image) {
            this.image = image;
        }

        protected void setImageDescriptor(ImageDescriptor imageDescriptor) {
            this.imageDescriptor = imageDescriptor;
        }

        protected void setGraphicControlExtension(GraphicControlExtension graphicControlExtension) {
            this.graphicControlExtension = graphicControlExtension;
            System.out.println(graphicControlExtension.getDisposalMethod());
        }

        public GraphicControlExtension getGraphicControlExtension() {
            return graphicControlExtension;
        }

        public BufferedImage getImage() {
            return image;
        }

        public ImageDescriptor getImageDescriptor() {
            return imageDescriptor;
        }

    }

    public class GraphicControlExtension {

        private DisposalMethod disposalMethod;
        private boolean userInputFlag;
        private boolean transparentColorFlag;
        private int delayTime;
        private int transparentColorIndex;

        public GraphicControlExtension(DisposalMethod disposalMethod, boolean userInputFlag, boolean transparentColorFlag, int delayTime, int transparentColorIndex) {
            this.disposalMethod = disposalMethod;
            this.userInputFlag = userInputFlag;
            this.transparentColorFlag = transparentColorFlag;
            this.delayTime = delayTime;
            this.transparentColorIndex = transparentColorIndex;
        }

        public int getDelayTime() {
            return delayTime;
        }

        public DisposalMethod getDisposalMethod() {
            return disposalMethod;
        }

        public int getTransparentColorIndex() {
            return transparentColorIndex;
        }

        public boolean isTransparentColorFlag() {
            return transparentColorFlag;
        }

        public boolean isUserInputFlag() {
            return userInputFlag;
        }

    }

    public class ImageDescriptor {

        private int imageLeftPosition;
        private int imageTopPosition;
        private int imageHeight;
        private int imageWeight;
        private boolean interlaced;

        public ImageDescriptor(int imageLeftPosition, int imageTopPosition, int imageHeight, int imageWeight, boolean interlaced) {
            this.imageLeftPosition = imageLeftPosition;
            this.imageTopPosition = imageTopPosition;
            this.imageHeight = imageHeight;
            this.imageWeight = imageWeight;
            this.interlaced = interlaced;
        }

        public int getImageHeight() {
            return imageHeight;
        }

        public int getImageLeftPosition() {
            return imageLeftPosition;
        }

        public int getImageTopPosition() {
            return imageTopPosition;
        }

        public int getImageWeight() {
            return imageWeight;
        }

        public boolean isInterlaced() {
            return interlaced;
        }

    }

}

这段代码来自将 .gif 图像添加到 JTabbedpane 后不会移动

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java GIF 动画无法正确重画 的相关文章

随机推荐

  • Qt 在 MainWindow 的对象成员中连接 SIGNAL 和 SLOT

    我有一个 MyClass 类 private pushButton button void connectSignalAndSlot private slot void buttonAction 我想使用 connectSignalAndS
  • C# 中 const 和 readonly 有什么区别?

    有什么区别const and readonly in C 你什么时候会使用其中一种而不是另一种 除了明显的差异之外 必须在定义时声明值const VS readonly值可以动态计算 但需要在构造函数退出之前分配 之后它被冻结 const是
  • stWSO2ESB 输出序列处理

    我正在 WSO2ESB 中通过 XSLT 将 XML 请求转换为 SOAP 只是想知道是否可以使请求参数可用于响应 E g
  • 读取 oleObject 文件的代码[关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 目前不接受答案 我从 Word DOCX 文档 oleObject1 bin 等 中提取了许多 OleObject 文件 是否有开源代码 主要是 Java 来读取此
  • ggplot2 中的交错轴标签

    我想错开我的 x 轴标签ggplot2 令人惊讶的是 我尝试的方法有效 感谢 Hadley 和一致的语法 c lt ggplot mtcars aes factor cyl c lt c geom bar c theme axis text
  • 如何在 Blazor Server + ASP.NET Core API + SignalR 项目中管理客户端连接

    我正在使用 ASP NET Core API 通过 SignalR 连接开发 Blazor 服务器应用程序 以将实时更新从服务器发送到客户端 但是 我在管理用户连接时遇到问题 的独特性问题是用户在浏览器中打开的每个选项卡都代表 Signal
  • BigQuery 中的新 PIVOT 功能

    今天 BigQuery 发布了一个新的很酷的函数 名为PIVOT 下面是它的工作原理 with Produce AS SELECT Kale as product 51 as sales Q1 as quarter UNION ALL SE
  • 如何在特定文件夹(ZIP 中)中添加文件

    以下代码说明了如何使用 java 将文件添加到 zip 中 String source C Users XXXXX Desktop Helicopter zip try ZipFile zipFile new ZipFile source
  • MVC/JQuery 验证不接受逗号作为小数点分隔符

    更新 07 01 2018 尽管有人建议这是一个 jQuery 问题而不是 MS ASP MVC 问题 但我认为这是一个 MVC 问题 我已经在 asp net core 2 0 MVC 中创建了整个应用程序 但错误仍然存 在 对我来说 将
  • RichTextBox从文本中删除转义字符

    在将文本添加到 RichTextBox 中的 RTF 属性之前 我对文本进行了一些处理 添加转义字符 然后将数据划分为多行 文字是 第 1 行 n u001aline2 n u001aline3 n u001aline4 当我将 VS 20
  • initContainers 和 Kubernetes 中容器的区别

    我注意到在部署文件中有两个容器字段 例如initContainers and containers对我来说看起来很困惑 我通过互联网搜索但无法理解 谁能告诉我两者之间的区别initContainers and containers以及我们如
  • OAuth2 登录后 Facebook 获取个人资料链接

    我通过 Facebook 社交网络为网站上的用户使用 OAuth2 登录 登录后是否仍然可以获取特定用户的 Facebook 个人资料 URL 例如通过accessToken 或者 Facebook 现在隐藏这些信息 在发生数据泄露事件之后
  • 为什么 imshow 的范围参数会翻转我的图像?

    import matplotlib pyplot as plt import numpy as np n 16 im np eye n fig plt figure ax fig add subplot 121 ax imshow im a
  • 为什么会调用 OnlyOnCanceled 延续?

    打电话时await RunAsync 在下面的代码中 我希望继续TaskContinuationOptions OnlyRanToCompletion继续运行 但是OnlyOnCanceled继续被调用 产生调试输出 任务已取消 Why p
  • 我可以使用 Homebrew 安装最新的 AWS EB CLI 吗?

    自制似乎正在安装 an 旧版本 不支持 of the AWS 电子银行工具 有没有办法让 Homebrew 安装当前的版本 我是自制软件的新手 Homebrew 依靠志愿者来更新配方 如果您发现过时的公式 请提交错误或拉取请求
  • jquery post codeigniter 验证

    我们使用 jquery 将表单 load 到 div 中 然后我们使用 jquery post 将该形式发送到 codeigniter 控制器 即 app post 然后我们希望 Codeigniter 执行验证 但不确定如何返回页面以显示
  • 为什么积压已满时 ServerSocket 连接不会被拒绝?

    无私的好奇心 在 Java 中 我监听一个套接字 积压为 1 ServerSocket ss new ServerSocket 4000 1 我在壳里跑 netcat localhost 4000 很多次 到目前为止 5 次 连接永远不会被
  • 如何检索必须在另一个线程上计算的值

    在许多情况下 线程 A 需要一个必须在线程 B 上计算的值 最常见的是 B EDT 考虑以下示例 String host SwingUtilities invokeAndWait new Runnable public void run h
  • 如何在 pyomo 中将积分定义为目标函数?

    我希望能够定义一个积分pyomo作为目标函数的一部分 我无法弄清楚积分需要什么样的表达式 这是我最好的猜测 model ConcreteModel model t ContinuousSet bounds 0 1 model y Var m
  • Java GIF 动画无法正确重画

    我正在尝试为 GIF 图像制作动画 动画可以 但画得不好 It shows like this non animated screenshot In the image the tail wags like this 正如您所看到的 图像重