动画GIF,显示在JPanel上,不是用paint方法在文件中截图,但JPG和PNG都可以

Animated GIF, displayed on JPanel, not screenshoting in file with paint method, but JPG and PNG are ok

不能使用 100% 真实代码,抱歉。其他 类 中的许多辅助功能,其中一些不是我的。

我正在制作视觉小说 - 只是评论一下我的项目,以便更好地理解。

我有一个带有 JPanel 卡片布局的 JFrame。 gameMainPanel 就是其中之一。我的目标 - 在拍摄时刻面板拍摄不可见的照片。在一个面板上是我的游戏绘图,在另一个面板上我正在制作游戏保存文件,其中包含游戏中的瞬间截图 - 所以游戏面板在那一刻不可见。它工作正常,但是当我在我的游戏面板上使用动画 GIF 时 - 它不是屏幕截图,而是所有其他 GUI 组件。

我正在使用如下代码加载动画 GIF 并调整其大小:

ImageIcon imageIcon = new ImageIcon(Engine.getPathString("/resource/character/" + name));
imageIcon.setImage(imageIcon.getImage().getScaledInstance(resizeX, resizeY, Image.SCALE_DEFAULT));
GameWindow.gameCharacterCenter.setIcon(imageIcon); //gameCharacterCenter is a simple JLabel on game panel

Engine.getPathString 是一个小包装器,只是 returns 一个带有文件完整路径的字符串。 Engine.getPathString("/example/dummy.txt") 将 return 类似 "C:/Java projects/Folder with that project/example/dummy.txt" 的东西,当然是关于完全正确的路径。

一会儿我需要拍一张我的游戏面板,我是这样拍的:

screenshot = new File(String.valueOf(Engine.getPathFile("/saves/" + name + ".jpeg")));
BufferedImage bufImage = new BufferedImage(GameWindow.gameMainPanel.getSize().width, GameWindow.gameMainPanel.getSize().height, BufferedImage.TYPE_INT_RGB);
GameWindow.gameMainPanel.paint(bufImage.createGraphics());
try {
    screenshot.createNewFile();
    ImageIO.write(bufImage, "jpeg", screenshot);
} catch (Exception ex) {
}

并且该代码正确地截取了我的 gameMainPanel 及其所有子项的屏幕截图 - 游戏菜单、角色、带有文本的标签...但如果它们是动画 GIF,则不是角色。当我加载完全相同的代码时,一个简单的 *.jpg 或 *.png - 封顶正常。

为什么当我将其绘制为父级时,其中带有动画 GIF 的 JLabel 不可见,但当其中包含 JPG 时 - 它正常绘制到 BufferedImage?

无法提供项目的完整代码,抱歉。 英语不是我的母语,所以 - 也 - 对此也感到抱歉。

使用 PrintScreen 按钮制作:

使用游戏内方法制作:

所以,我进行了一个快速测试,基本上,我使用了 PNG 图像和动画 gif 图像,我使用 ImageIO 加载两者并尝试保存生成的面板,然后我使用 ImageIcon加载图像并保存

我的意见...

PNG 图片

GIF 图片

"code"

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

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

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

                    BufferedImage png = ImageIO.read(...));
                    BufferedImage gif = ImageIO.read(...);
                    ImageIcon gifImg = new ImageIcon(...);

                    TestPane pngPane = new TestPane(png);
                    TestPane gifPane = new TestPane(gif);
                    TestPane imgPane = new TestPane(gifImg.getImage());

                    save(pngPane, "PNGTest.png");
                    save(gifPane, "gifTest.png");
                    save(imgPane, "imgGifTest.png");

                } catch (IOException ex) {
                    Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        });
    }

    public void save(JPanel pane, String to) throws IOException {
        pane.setSize(pane.getPreferredSize());
        BufferedImage img = new BufferedImage(pane.getWidth(), pane.getHeight(), BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = img.createGraphics();
        pane.printAll(g2d);
        g2d.dispose();

        ImageIO.write(img, "png", new File(to));
    }

    public class TestPane extends JPanel {

        private Image img;

        public TestPane(Image img) {
            this.img = img;
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(img.getWidth(this), img.getHeight(this));
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.drawImage(img, 0, 0, this);
            g2d.dispose();
        }

    }

}

结果...

PNG 图片来自 ImageIO

GIF 图片来自 ImageIO

GIF 图片来自 ImageIcon

我不想深入了解这一切的原理和原因,不用说,ImageIcon 确实使用后台线程加载图像并依赖于 ImageObserver 的支持当状态发生变化时重新绘制的组件,这就是它如何在屏幕上更新动画 GIF,因此,有人可能会猜测我们只是缺少更新通知。

我没有测试过,但是你可以使用 MediaTracker 来监控 ImageIcon 的状态并等待它加载,但考虑到使用 ImageIO 的简单性我会质疑是否值得。

洞穴

如果您希望动画 gif 在实时组件上播放,您将需要使用 ImageIcon!所以只能在生成预览的时候用这个"cheat"!