Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
515 views
in Technique[技术] by (71.8m points)

swing - Mirroring animated gif on load in Java - ImageIcon

So I have an animated gif that I load into an ImageIcon like this:

Image image = new ImageIcon("image.gif").getImage();

and I can draw it using this:

g.drawImage(image, x, y, null);

I know that I can mirror it on the fly using AffineTransform, but I need to be able to mirror it horizontally after loading, so that I can draw the mirrored one instead if needed without the overhead of transforming it every time it gets redrawn. Is there a way to do this using swing/awt?

A library that could do this would also be a huge help.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The problem is, as you have pointed out, is the fact the gif's are animated.

Unless you desperately want to take over the job of having to render each frame yourself, the only choice you have is to use an AffineTransform with in the paint method.

Generally speaking, you shouldn't see a significant difference (in rendering).

If you are really desperate, you could simply pre-render the gif externally and provide a mirrored version

Updated with a "kind of" working example

This is a combination of this and this answers, using this GIF writer.

Basically what this example does is it reads an original gif image, mirrors it frame by frame, and writes back out to a mirrored file.

It then loads both the original and mirrored files back in as ImageIcons, mostly because I'm not really up to re-inventing the wheel for display animated gifs. Yes, you could do it and everything you would need is provided within..

enter image description here

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("java_animated.gif"), new File("Mirror.gif"));
            orig = new ImageIcon("java_animated.gif");
            mirror = new ImageIcon("Mirror.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));
                        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");

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...