Java GIF动画无法正确重新绘制

我正在尝试为GIF图像制作动画。 动画有效,但画面效果不佳。

它显示如下(非动画截图): 我怎么看

在图像中,尾巴像这样摇晃: 这是我用过的图像

如您所见,图像不能很好地重现。 我不想使用JLabel,但是没有正常工作,所以当我的图像没有动画时我就按照这个问题 。

我的代码是这样的:

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

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

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

在JPanelcanvas中,我制作了一个paint方法和一个每10ms重绘一次的计时器线程。 这适用于除GIF之外的所有事情。 谁可以帮我这个?

—编辑

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

好吧,经过多次讨论之后,我终于可以将帧的处理方法更改为restoreToBackgroundColor 。 基本上,这意味着动画不是增量变化,而是完整的帧替换……

异食癖GIF

 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 ,根据GRAPHICS INTERCHANGE FORMAT Version 89a的含义:

恢复到上一个​​。 解码器需要恢复图形覆盖的区域,以及渲染图形之前的区域。

我上面提供的图像使用restoreToBackgroundColor ,根据GRAPHICS INTERCHANGE FORMAT版本89a表示:

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

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

 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 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图像在将其添加到JTabbed窗格时不会移动