正如您所指出的,问题是gif动画化。
除非您非常想承担必须自己渲染每个帧的工作,否则唯一的选择是AffineTransform在paint方法中使用with。
一般来说,您应该不会在渲染方面看到明显的不同。
如果您真的很绝望,则可以在外部预先渲染gif并提供镜像版本
更新了“一种”工作示例
这是一个组合,这个和这个答案,使用此GIF作家。
基本上,此示例所做的是读取原始gif图像,逐帧镜像,然后写回镜像文件。
然后,它会将原始文件和镜像文件都以ImageIcons的形式加载回去,这主要是因为我真的不愿意重新发明用于显示动画gif的轮子。是的,您可以执行此 *** 作,并且将在其中提供所需的一切。
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; 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"); 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); } public void close() throws IOException { gifWriter.endWriteSequence(); } 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(); } } 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编写器当前仅适用于固定速率的gif。应该可以更改此设置,但是我没有时间。
基本上,据我了解,您需要将“帧”延迟传递给该writeToSquence方法。在这种方法中,您将需要构造IIOmetadata具有所有必需属性的适当属性,再加上帧延迟…
使用原始gif播放后更新
我正在玩的GIF已优化。也就是说,每个帧都“添加”到了动画中,而不是一个全新的帧。您的情况恰恰相反。每帧都是完整的图像。
现在,您可以通过多种方法进行检查,但是现在,我不会感到烦恼…
而是…在mirror(File, File)方法中,我对其进行了更改,以使每个帧都创建一个新的图像,而不是使用单个“主”图像BufferedImage
BufferedImage frame = new BufferedImage(imageAttr.get("imageWidth"), imageAttr.get("imageHeight"), BufferedImage.TYPE_INT_ARGB);Graphics2D g2d = frame.createGraphics();g2d.drawImage(image, imageAttr.get("imageLeftPosition"), imageAttr.get("imageTopPosition"), null);g2d.dispose();frame = mirror(frame);ImageIO.write(frame, "png", new File("img" + i + ".png"));images.add(frame);
我还更新了,GifSequenceWriter以将元数据设置为也更接近原始数据…
graphicsControlExtensionNode.setAttribute("disposalMethod", "restoreToBackgroundColor");graphicsControlExtensionNode.setAttribute("userInputFlag", "FALSE");graphicsControlExtensionNode.setAttribute( "transparentColorFlag", "TRUE");
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)