Загрузка анимированного изображения в массив BufferedImage - PullRequest
0 голосов
/ 13 января 2012

Я пытаюсь без проблем внедрить анимированные текстуры в игру OpenGL.Я создал общий класс ImageDecoder для преобразования любого BufferedImage в ByteBuffer.Пока он отлично работает, хотя не загружает анимированные изображения.

Я не пытаюсь загрузить анимированное изображение в качестве ImageIcon.Мне нужен BufferedImage, чтобы получить OpenGL-совместимый ByteBuffer.

Как я могу загрузить все кадры в виде массива BufferedImage в анимированном изображении?На аналогичной ноте, как я могу получить частоту / период анимации?

Обрабатывает ли Java APNG?

Ответы [ 2 ]

0 голосов
/ 16 июля 2014

Следующий код является адаптацией из моей собственной реализации для размещения части "в массив".

Проблема с GIF-файлами: есть разные методы удаления, которые необходимо учитывать, если вы хотите, чтобы этоработать со всеми из них.Код ниже пытается компенсировать это.Например, есть специальная реализация для режима «doNotDispose», которая берет все кадры от начала до N и рисует их друг над другом в BufferedImage.

Преимущество этого метода перед тем, который опубликовал chubbsondubsявляется то, что он не должен ждать задержки анимации GIF, но может быть сделано в основном мгновенно.

BufferedImage[] array = null;
ImageInputStream imageInputStream = ImageIO.createImageInputStream(new ByteArrayInputStream(data)); // or any other source stream
Iterator<ImageReader> imageReaders = ImageIO.getImageReaders(imageInputStream);
while (imageReaders.hasNext())
{
    ImageReader reader = (ImageReader) imageReaders.next();
    try
    {
        reader.setInput(imageInputStream);
        frames = reader.getNumImages(true);
        array = new BufferedImage[frames];
        for (int frameId : frames)
        {
            int w = reader.getWidth(0);
            int h = reader.getHeight(0);
            int fw = reader.getWidth(frameId);
            int fh = reader.getHeight(frameId);
            if (h != fh || w != fw)
            {
                GifMeta gm = getGifMeta(reader.getImageMetadata(frameId));
                // disposalMethodNames: "none", "doNotDispose","restoreToBackgroundColor","restoreToPrevious",
                if ("doNotDispose".equals(gm.disposalMethod))
                {
                    image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
                    Graphics2D g = (Graphics2D) image.getGraphics();
                    for (int f = 0; f <= frameId; f++)
                    {
                        gm = getGifMeta(reader.getImageMetadata(f));

                        if ("doNotDispose".equals(gm.disposalMethod))
                        {
                            g.drawImage(reader.read(f), null, gm.imageLeftPosition, gm.imageTopPosition);
                        }
                        else
                        {
                            // XXX "Unimplemented disposalMethod (" + getName() + "): " + gm.disposalMethod);
                        }
                    }
                    g.dispose();
                }
                else
                {
                    image = reader.read(frameId);
                    // XXX "Unimplemented disposalMethod (" + getName() + "): " + gm.disposalMethod;
                }
            }
            else
            {
                image = reader.read(frameId);
            }
            if (image == null)
            {
                throw new NullPointerException();
            }
            array[frame] = image;
        }
    }
    finally
    {
        reader.dispose();
    }
}
return array;

private final static class GifMeta
{

    String disposalMethod = "none";
    int imageLeftPosition = 0;
    int imageTopPosition = 0;
    int delayTime = 0;
}

private GifMeta getGifMeta(IIOMetadata meta)
{
    GifMeta gm = new GifMeta();
    final IIOMetadataNode gifMeta = (IIOMetadataNode) meta.getAsTree("javax_imageio_gif_image_1.0");
    NodeList childNodes = gifMeta.getChildNodes();
    for (int i = 0; i < childNodes.getLength(); ++i)
    {
        IIOMetadataNode subnode = (IIOMetadataNode) childNodes.item(i);
        if (subnode.getNodeName().equals("GraphicControlExtension"))
        {
            gm.disposalMethod = subnode.getAttribute("disposalMethod");
            gm.delayTime = Integer.parseInt(subnode.getAttribute("delayTime"));
        }
        else if (subnode.getNodeName().equals("ImageDescriptor"))
        {
            gm.imageLeftPosition = Integer.parseInt(subnode.getAttribute("imageLeftPosition"));
            gm.imageTopPosition = Integer.parseInt(subnode.getAttribute("imageTopPosition"));
        }
    }
    return gm;
}
0 голосов
/ 13 января 2012

Я не думаю, что Java поддерживает APNG по умолчанию, но вы можете использовать стороннюю библиотеку для его анализа:

http://code.google.com/p/javapng/source/browse/trunk/javapng2/src/apng/com/sixlegs/png/AnimatedPngImage.java?r=300

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

new ImageIcon( url ).setImageObserver( new ImageObserver() {
    public void imageUpdate( Image img, int infoFlags, int x, int y, int width, int height ) {
        if( infoFlags & ImageObserver.FRAMEBITS == ImageObserver.FRAMEBITS ) {
            // another frame was loaded do something with it.
        }
    }
});

Это загружается асинхронно в другом потоке, поэтому imageUpdate () не будет вызываться немедленноНо он будет вызываться для каждого кадра, когда он его анализирует.

http://docs.oracle.com/javase/1.4.2/docs/api/java/awt/image/ImageObserver.html

...