GIF анимация играет очень быстро в JFrame


import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;

import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;

import common.ResourcesToAccess;

public class RecordingStartingThread extends Thread{
    @Override
    public void run(){
        JFrame f = new JFrame();
        ImageIcon reel = new ImageIcon("src/images/reel.GIF");
        JLabel label = new JLabel(reel);
        reel.setImageObserver(label);
        f.getContentPane().add(label);
        f.setUndecorated(true);
        f.setSize(300, 300);
        f.setVisible(true);
    }
    public static void main(String[] args) {
        new RecordingStartingThread().start();
    } 
}

Проблема: GIF играет очень быстро.

Вопрос: Как убедиться,что GIF воспроизводится с нормальной скоростью?

2 2

2 ответа:

Что касается скорости воспроизведения GIF - я тоже сталкивался с этой проблемой. Если я правильно помню, это было вызвано "дефолтом" (или не предусмотрено?) значение частоты кадров в файле GIF. Некоторые веб-браузеры "переопределили" эту частоту кадров, чтобы GIF играл правильно.

В результате я создал класс, который преобразует GIF (read GIF - > write GIF) и выдает частоту кадров, предоставленную пользователем. com.madgag.gif.fmsware.AnimatedGifEncoder class-это внешняя библиотека, которую я связываю с проектом через Maven: animated-gif-lib-1.0.jar
public final class GIFUtils {

private GIFUtils() {
}

public static List<BufferedImage> extractFrames(String filePath) throws IOException {
    return extractFrames(new File(filePath));
}

public static List<BufferedImage> extractFrames(File file) throws IOException {
    List<BufferedImage> imgs = new LinkedList<BufferedImage>();
    ImageReader reader = ImageIO.getImageReadersBySuffix("GIF").next();
    ImageInputStream in = null;
    try {
        in = ImageIO.createImageInputStream(new FileInputStream(file));
        reader.setInput(in);
        BufferedImage img = null;
        int count = reader.getNumImages(true);
        for(int i = 0; i < count; i++) {
            Node tree = reader.getImageMetadata(i).getAsTree("javax_imageio_gif_image_1.0");
            int x = Integer.valueOf(tree.getChildNodes().item(0).getAttributes()
                    .getNamedItem("imageLeftPosition").getNodeValue());
            int y = Integer.valueOf(tree.getChildNodes().item(0).getAttributes()
                    .getNamedItem("imageTopPosition").getNodeValue());
            BufferedImage image = reader.read(i);
            if(img == null) {
                img = new BufferedImage(image.getWidth() + x, image.getHeight() + y,
                        BufferedImage.TYPE_4BYTE_ABGR);
            }

            Graphics2D g = img.createGraphics();
            ImageUtils.setBestRenderHints(g);
            g.drawImage(image, x, y, null);
            imgs.add(ImageUtils.copy(img));
        }
    }
    finally {
        if(in != null) {
            in.close();
        }
    }
    return imgs;
}

public static void writeGif(List<BufferedImage> images, File gifFile, int millisForFrame)
        throws FileNotFoundException, IOException {
    BufferedImage firstImage = images.get(0);
    int type = firstImage.getType();

    ImageOutputStream output = new FileImageOutputStream(gifFile);

    // create a gif sequence with the type of the first image, 1 second
    // between frames, which loops continuously
    GifSequenceWriter writer = new GifSequenceWriter(output, type, 100, false);

    // write out the first image to our sequence...
    writer.writeToSequence(firstImage);
    for(int i = 1; i < images.size(); i++) {
        BufferedImage nextImage = images.get(i);
        writer.writeToSequence(nextImage);
    }

    writer.close();
    output.close();
}

public static Image createGif(List<BufferedImage> images, int millisForFrame) {
    AnimatedGifEncoder g = new AnimatedGifEncoder();
    ByteArrayOutputStream out = new ByteArrayOutputStream(5 * 1024 * 1024);
    g.start(out);
    g.setDelay(millisForFrame);
    g.setRepeat(1);
    for(BufferedImage i : images) {
        g.addFrame(i);
    }
    g.finish();
    byte[] bytes = out.toByteArray();
    return Toolkit.getDefaultToolkit().createImage(bytes);
}

И GifSequenceWriter выглядит так: это:

public class GifSequenceWriter {
    protected ImageWriter gifWriter;
    protected ImageWriteParam imageWriteParam;
    protected IIOMetadata imageMetaData;

    public GifSequenceWriter(ImageOutputStream outputStream, int imageType, int timeBetweenFramesMS,
            boolean loopContinuously) throws IIOException, IOException {
        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");
        }
        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;
    }
}

Самое простое решение этой проблемы-просто создать a .gif-файл, который является "хорошо сформированным", то есть содержит соответствующую частоту кадров. Этого можно добиться с помощью различных онлайн конвертеров, например, google "gif speed changer".