2016-04-17 4 views
1

Я пытаюсь отобразить анимированный gif внутри приложения java. Пока он отображает и оживляет, но там, где он должен быть полностью черным или полностью белым, он становится прозрачным, и я вижу цвет прямоугольника, нарисованного под ним. Например, вот один из гифы, которые я использую:Java (swing) gif частично прозрачный, когда он не должен быть

Original gif

На черном фоне это не заметно, однако, когда я изменить его бирюзового:

Gif on top of a cyan background

Что действительно странно заключается в том, что кажется, что он правильно отображается для самого первого кадра, а затем только беспорядки. Это метод я использую, чтобы получить и сделать изображение:

//Draw title 
img = new ImageIcon(Display.class.getResource(titlePath)).getImage(); 
g.drawImage(img, 404, 430, this); 

Я перекрывая paintcomponent в классе, который расширяет JPanel, и я только перекрашивать вызов на этом классе один раз.

Что может быть причиной этого, это известная проблема, или я ошибаюсь в том, как я собираюсь нарисовать изображение? Я не смог найти какую-либо документацию по этой проблеме.

Заранее благодарен!

Вот два из original gif files.

EDIT: Вот пример кода, который я написал. Я удалил ненужный код, чтобы он был коротким, но все это касалось проблемы. Также может быть полезно отметить, что когда я рисую файл png (который является одним из фреймов, используемых для создания gif) с тем же методом, проблем нет. Gif был сделан на http://gifmaker.me/ в случае, если это релевантно.

public class Display extends JPanel implements Constants{ 
    private GameData GD; 
    private String currentImagePath; 

    public Display(GameData gd){ 
     GD = gd; 
     this.setPreferredSize(screenDimension); 

     this.repaint(); 
    } 

    public void draw(Location loc){ 
     currentImagePath = loc.getCurrentImagePath(); 

     this.repaint(); 
    } 

    @Override 
    public void paintComponent(Graphics g){ 
     super.paintComponent(g); 
     g.setColor(CYAN); 
     g.fillRect(0, 0, screenW, screenH); 

     Image img; 

     if(OtherWorlds.isOnTitle == true){ //Title screen 
      //Draw image 
      img = new ImageIcon(Display.class.getResource(currentImagePath)).getImage(); 
      g.drawImage(img, 10, 10, this); 

      //Draw other stuff 

     { 
     else{ //Regular location 

      //Draw image 
      img = new ImageIcon(Display.class.getResource(currentImagePath)).getImage(); 
      g.drawImage(img, 10, 10, this); 

      //Other images and stuff in different areas 
      //Drawn using the exact same method as above 

      } 

      //Random other lines and stuff 
     } 
    } 
} 
+0

Интересно, но я не может воспроизвести его. Было бы полезно изменить ваш вопрос и включить [минимальный, полный пример] (http://stackoverflow.com/help/mcve), чтобы мы могли видеть остальную часть того, что вы делаете, и компилировать/запускать его, если необходимо , – Radiodef

+0

@ Radiodef Спасибо за предложение, я отредактировал вопрос, надеюсь, что этого достаточно, чтобы дать некоторое представление. – sirrandalot

+0

У вас есть ссылка на исходное изображение? – MadProgrammer

ответ

1

Если когда-нибудь у вас есть эти типы проблем, вы хотите, чтобы начать играть вокруг с disposalMethod кадров.

Я побежал ваш GIF через какую-то проверка коду и нашел disposalMethod быть установлены в RESTORE_TO_BACKGROUND

Так, в основном, я взял свой GIF и побежал через следующий код, который создал новый GIF с disposalMethod из none

Logo01Logo02

Так исходное изображение находится на вершине и «фиксированный» изображение на дне. Фон окрашен в красный цвет, чтобы подчеркнуть разницу

import java.awt.BorderLayout; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.GraphicsConfiguration; 
import java.awt.GraphicsEnvironment; 
import java.awt.geom.AffineTransform; 
import java.awt.image.BufferedImage; 
import java.awt.image.RenderedImage; 
import java.io.File; 
import java.io.IOException; 
import java.util.ArrayList; 
import java.util.HashMap; 
import java.util.Iterator; 
import java.util.List; 
import java.util.Map; 
import javax.imageio.IIOException; 
import javax.imageio.IIOImage; 
import javax.imageio.ImageIO; 
import javax.imageio.ImageReader; 
import javax.imageio.ImageTypeSpecifier; 
import javax.imageio.ImageWriteParam; 
import javax.imageio.ImageWriter; 
import javax.imageio.metadata.IIOMetadata; 
import javax.imageio.metadata.IIOMetadataNode; 
import javax.imageio.stream.FileImageOutputStream; 
import javax.imageio.stream.ImageInputStream; 
import javax.imageio.stream.ImageOutputStream; 
import javax.swing.ImageIcon; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 
import org.w3c.dom.NamedNodeMap; 
import org.w3c.dom.Node; 
import org.w3c.dom.NodeList; 

public class MirrorImage { 

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

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

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

    public class TestPane extends JPanel { 

     private ImageIcon orig; 
     private ImageIcon mirror; 

     public TestPane() { 
      mirror(new File("Qzlxj.gif"), new File("Test.gif")); 
      orig = new ImageIcon("Qzlxj.gif"); 
      mirror = new ImageIcon("Test.gif"); 
     } 

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

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      if (orig != null) { 
       Graphics2D g2d = (Graphics2D) g.create(); 
       int x = (getWidth() - orig.getIconWidth())/2; 
       int y = (getHeight() - (orig.getIconHeight() * 2))/2; 
       g2d.drawImage(orig.getImage(), x, y, this); 

//    AffineTransform at = new AffineTransform(); 
//    at.setToScale(1, -1); 
//    at.translate(0, -mirror.getIconHeight()); 
//    g2d.setTransform(at); 
       g2d.drawImage(mirror.getImage(), x, y + mirror.getIconHeight(), this); 
       g2d.dispose(); 
      } 
     } 
    } 

    public static void mirror(File source, File dest) { 

     List<BufferedImage> images = new ArrayList<>(25); 
     List<Integer> delays = new ArrayList<>(25); 
     int delay = 0; 

     ImageOutputStream output = null; 
     GifSequenceWriter writer = null; 

     try { 

      String[] imageatt = new String[]{ 
       "imageLeftPosition", 
       "imageTopPosition", 
       "imageWidth", 
       "imageHeight" 
      }; 

      ImageReader reader = (ImageReader) ImageIO.getImageReadersByFormatName("gif").next(); 
      ImageInputStream ciis = ImageIO.createImageInputStream(source); 
      reader.setInput(ciis, false); 
      int noi = reader.getNumImages(true); 
      BufferedImage master = null; 

      for (int i = 0; i < noi; i++) { 

       BufferedImage image = reader.read(i); 
       IIOMetadata metadata = reader.getImageMetadata(i); 

       Node tree = metadata.getAsTree("javax_imageio_gif_image_1.0"); 
       NodeList children = tree.getChildNodes(); 
       for (int j = 0; j < children.getLength(); j++) { 
        Node nodeItem = children.item(j); 
        System.out.println(nodeItem.getNodeName()); 
        if (nodeItem.getNodeName().equals("ImageDescriptor")) { 
         Map<String, Integer> imageAttr = new HashMap<String, Integer>(); 
         NamedNodeMap attr = nodeItem.getAttributes(); 
//      for (int index = 0; index < attr.getLength(); index++) { 
//       Node node = attr.item(index); 
//       System.out.println("----> " + node.getNodeName() + "=" + node.getNodeValue()); 
//      } 
         for (int k = 0; k < imageatt.length; k++) { 
          Node attnode = attr.getNamedItem(imageatt[k]); 
          imageAttr.put(imageatt[k], Integer.valueOf(attnode.getNodeValue())); 
         } 

         if (master == null) { 
          master = new BufferedImage(imageAttr.get("imageWidth"), imageAttr.get("imageHeight"), BufferedImage.TYPE_INT_ARGB); 
         } 

         Graphics2D g2d = master.createGraphics(); 
         g2d.drawImage(image, imageAttr.get("imageLeftPosition"), imageAttr.get("imageTopPosition"), null); 
         g2d.dispose(); 

//      BufferedImage frame = mirror(copyImage(master)); 
         BufferedImage frame = copyImage(master); 
         ImageIO.write(frame, "png", new File("img" + i + ".png")); 
         images.add(frame); 

        } else if (nodeItem.getNodeName().equals("GraphicControlExtension")) { 
         NamedNodeMap attr = nodeItem.getAttributes(); 
         Node delayNode = attr.getNamedItem("delayTime"); 
         if (delayNode != null) { 
          delay = Math.max(delay, Integer.valueOf(delayNode.getNodeValue())); 
          delays.add(delay); 
         } 
        } 
       } 

      } 

      output = new FileImageOutputStream(dest); 
      writer = new GifSequenceWriter(output, images.get(0).getType(), delay * 10, true); 

      for (int i = 0; i < images.size(); i++) { 
       BufferedImage nextImage = images.get(i); 
       writer.writeToSequence(nextImage); 
      } 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } finally { 
      try { 
       writer.close(); 
      } catch (Exception e) { 
      } 
      try { 
       output.close(); 
      } catch (Exception e) { 
      } 
     } 
    } 

    public static BufferedImage mirror(BufferedImage img) { 

     BufferedImage mirror = createCompatibleImage(img); 
     Graphics2D g2d = mirror.createGraphics(); 
     AffineTransform at = new AffineTransform(); 
     at.setToScale(1, -1); 
     at.translate(0, -img.getHeight()); 
     g2d.setTransform(at); 
     g2d.drawImage(img, 0, 0, null); 
     g2d.dispose(); 

     return mirror; 

    } 

    public static BufferedImage copyImage(BufferedImage img) { 
     int width = img.getWidth(); 
     int height = img.getHeight(); 

     BufferedImage newImage = createCompatibleImage(img); 
     Graphics graphics = newImage.createGraphics(); 

     int x = (width - img.getWidth())/2; 
     int y = (height - img.getHeight())/2; 

     graphics.drawImage(img, x, y, img.getWidth(), img.getHeight(), null); 
     graphics.dispose(); 

     return newImage; 
    } 

    public static BufferedImage createCompatibleImage(BufferedImage image) { 
     return getGraphicsConfiguration().createCompatibleImage(image.getWidth(), image.getHeight(), image.getTransparency()); 
    } 

    public static GraphicsConfiguration getGraphicsConfiguration() { 
     return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration(); 
    } 

    public static class GifSequenceWriter { 

     protected ImageWriter gifWriter; 
     protected ImageWriteParam imageWriteParam; 
     protected IIOMetadata imageMetaData; 

     /** 
     * Creates a new GifSequenceWriter 
     * 
     * @param outputStream the ImageOutputStream to be written to 
     * @param imageType one of the imageTypes specified in BufferedImage 
     * @param timeBetweenFramesMS the time between frames in miliseconds 
     * @param loopContinuously wether the gif should loop repeatedly 
     * @throws IIOException if no gif ImageWriters are found 
     * 
     * @author Elliot Kroo (elliot[at]kroo[dot]net) 
     */ 
     public GifSequenceWriter(
       ImageOutputStream outputStream, 
       int imageType, 
       int timeBetweenFramesMS, 
       boolean loopContinuously) throws IIOException, IOException { 
      // my method to create a writer 
      gifWriter = getWriter(); 
      imageWriteParam = gifWriter.getDefaultWriteParam(); 
      ImageTypeSpecifier imageTypeSpecifier 
        = ImageTypeSpecifier.createFromBufferedImageType(imageType); 

      imageMetaData 
        = gifWriter.getDefaultImageMetadata(imageTypeSpecifier, 
          imageWriteParam); 

      String metaFormatName = imageMetaData.getNativeMetadataFormatName(); 

      IIOMetadataNode root = (IIOMetadataNode) imageMetaData.getAsTree(metaFormatName); 

      IIOMetadataNode graphicsControlExtensionNode = getNode(
        root, 
        "GraphicControlExtension"); 

      //restoreToBackgroundColor 
      //restoreToPrevious 
      graphicsControlExtensionNode.setAttribute("disposalMethod", "none"); 
      graphicsControlExtensionNode.setAttribute("userInputFlag", "FALSE"); 
      graphicsControlExtensionNode.setAttribute(
        "transparentColorFlag", 
        "FALSE"); 
      graphicsControlExtensionNode.setAttribute(
        "delayTime", 
        Integer.toString(timeBetweenFramesMS/10)); 
      graphicsControlExtensionNode.setAttribute(
        "transparentColorIndex", 
        "0"); 

      IIOMetadataNode commentsNode = getNode(root, "CommentExtensions"); 
      commentsNode.setAttribute("CommentExtension", "Created by MAH"); 

      IIOMetadataNode appEntensionsNode = getNode(
        root, 
        "ApplicationExtensions"); 

      IIOMetadataNode child = new IIOMetadataNode("ApplicationExtension"); 

      child.setAttribute("applicationID", "NETSCAPE"); 
      child.setAttribute("authenticationCode", "2.0"); 

      int loop = loopContinuously ? 0 : 1; 

      child.setUserObject(new byte[]{0x1, (byte) (loop & 0xFF), (byte) ((loop >> 8) & 0xFF)}); 
      appEntensionsNode.appendChild(child); 

      imageMetaData.setFromTree(metaFormatName, root); 

      gifWriter.setOutput(outputStream); 

      gifWriter.prepareWriteSequence(null); 
     } 

     public void writeToSequence(RenderedImage img) throws IOException { 
      gifWriter.writeToSequence(
        new IIOImage(
          img, 
          null, 
          imageMetaData), 
        imageWriteParam); 
     } 

     /** 
     * Close this GifSequenceWriter object. This does not close the 
     * underlying stream, just finishes off the GIF. 
     */ 
     public void close() throws IOException { 
      gifWriter.endWriteSequence(); 
     } 

     /** 
     * Returns the first available GIF ImageWriter using 
     * ImageIO.getImageWritersBySuffix("gif"). 
     * 
     * @return a GIF ImageWriter object 
     * @throws IIOException if no GIF image writers are returned 
     */ 
     private static ImageWriter getWriter() throws IIOException { 
      Iterator<ImageWriter> iter = ImageIO.getImageWritersBySuffix("gif"); 
      if (!iter.hasNext()) { 
       throw new IIOException("No GIF Image Writers Exist"); 
      } else { 
       return iter.next(); 
      } 
     } 

     /** 
     * Returns an existing child node, or creates and returns a new child 
     * node (if the requested node does not exist). 
     * 
     * @param rootNode the <tt>IIOMetadataNode</tt> to search for the child 
     * node. 
     * @param nodeName the name of the child node. 
     * 
     * @return the child node, if found or a new node created with the given 
     * name. 
     */ 
     private static IIOMetadataNode getNode(
       IIOMetadataNode rootNode, 
       String nodeName) { 
      int nNodes = rootNode.getLength(); 
      for (int i = 0; i < nNodes; i++) { 
       if (rootNode.item(i).getNodeName().compareToIgnoreCase(nodeName) 
         == 0) { 
        return ((IIOMetadataNode) rootNode.item(i)); 
       } 
      } 
      IIOMetadataNode node = new IIOMetadataNode(nodeName); 
      rootNode.appendChild(node); 
      return (node); 
     } 
    } 
} 

И, наконец, «фиксированный» GIF

Fixed01Fixed02

выше на основе исследований с Mirroring animated gif on load in Java - ImageIcon

+0

Спасибо тонну! Я попытаюсь интегрировать что-то подобное в свой код, как только смогу, и дам вам знать, есть ли какие-либо проблемы! – sirrandalot

+0

Хорошо, поэтому я прочитал код, и я немного смущен, насколько это необходимо. Я предполагаю, что нет простого способа изменить «метод удаления»? – sirrandalot

+0

Код, который я опубликовал, был использован для «исправления» метода «disposMethod» и отображения результатов. Поэтому, если вам не нужно модифицировать 'disposMethod', вам это не понадобится, но я предоставил его, чтобы вы могли поиграть с ним. В глубине кода кода вы найдете 'graphicsControlExtensionNode.setAttribute (" disposMethod "," none ");', который использовался для изменения 'disposMethod', если вам это нужно. Вы должны просто загрузить два последних gif, так как они являются результатом кода – MadProgrammer

Смежные вопросы