La animación GIF de Java no se repinta correctamente

Intento animar una imagen GIF. La animación funciona, pero no está pintando bien.

Se muestra así (captura de pantalla no animada): Cómo lo veo

En la imagen, la cola se mueve así: Esta fue la imagen que utilicé

Como puede ver, la imagen no se repinta bien. No quiero usar JLabels pero eso no funcionó correctamente, así que seguí esta pregunta cuando mi imagen no se animaba .

Mi código es así:

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

Donde se recupera la imagen y se guarda de esta manera:

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

En el canvas de JPanel, he creado un método de pintura y un hilo de temporizador que se repinta cada 10 ms. Eso funciona para todo excepto para el GIF. ¿Alguien que pueda ayudarme con esto?

— Editar

Lamento el malentendido. He actualizado la imagen a la que estoy usando. Espero que no sea una molestia obtener la respuesta correcta …

De acuerdo, así que después de mucho rebuscar, finalmente pude cambiar el método de eliminación del fotogtwig para restreToBackgroundColor . Básicamente, lo que esto significa es que la animación no es un cambio gradual, sino un reemplazo de cuadro completo …

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); } } } 

Actualizado…

Por lo tanto, finalmente pude echar un vistazo al método de eliminación para el gif que está utilizando, que está configurado para restreToPrevious , que, de acuerdo con GRAPHICS INTERCHANGE FORMAT Versión 89a, significa:

Restaurar a anterior. El decodificador debe restaurar el área sobreescrita por el gráfico con lo que estaba allí antes de representar el gráfico.

Donde como la imagen que he proporcionado arriba usa restreToBackgroundColor , que de acuerdo con GRAPHICS INTERCHANGE FORMAT Version 89a significa:

Restaurar al color de fondo. El área utilizada por el gráfico debe restaurarse al color de fondo

Puede verificarlo usted mismo usando el siguiente código …

 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 "restreToBackgroundColor": dm = RESTORE_TO_BACKGROUND; break; case "restreToPrevious": 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; } } } 

Este código proviene de la imagen .gif no se mueve al agregarlo al panel JTabbed