在java中从APNG中提取png文件 [英] extracting png files from APNG in java

查看:118
本文介绍了在java中从APNG中提取png文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在尝试从 APNG 文件中提取所有 png 文件.我一直在寻求帮助,但并没有太多.我所能找到的只是一个开源库 pngj,有了它,我就可以获得 APNG 文件的第一帧.

I have been trying to extract all the png files from an APNG file. i have looked for help and well there isnt much. All i could find is a open source library pngj and with it i am able to get the first frame of a APNG file.

这是我正在使用的代码

public static void mirror(File orig, File dest, boolean overwrite)
         {
    PngReader pngr = FileHelper.createPngReader(orig);
    PngWriter pngw = FileHelper.createPngWriter(dest, pngr.imgInfo,
            overwrite);
    pngw.setFilterType(FilterType.FILTER_CYCLIC); // just to test all
                                                    // filters
    int copyPolicy = ChunkCopyBehaviour.COPY_ALL;
    pngw.copyChunksFirst(pngr, copyPolicy);
    ImageLine lout = new ImageLine(pngw.imgInfo);
    int cols = pngr.imgInfo.cols;
    int channels = pngr.imgInfo.channels;
    int[] line = new int[cols * channels];
    int aux;
    for (int row = 0; row < pngr.imgInfo.rows; row++) {
        ImageLine l1 = pngr.readRow(row);
        line = l1.unpack(line, false);
        for (int c1 = 0, c2 = cols - 1; c1 < c2; c1++, c2--) {
            for (int i = 0; i < channels; i++) {
                aux = line[c1 * channels + i];
                line[c1 * channels + i] = line[c2 * channels + i];
                line[c2 * channels + i] = aux;
            }
        }
        lout.pack(line, false);
        pngw.writeRow(lout, row);
    }
    pngr.end();
    pngw.copyChunksLast(pngr, copyPolicy);
    pngw.end();
    // // print unknown chunks, just for information
    List<PngChunk> u = ChunkHelper.filterList(pngr.getChunksList()
            .getChunks(), new ChunkPredicate() {
        public boolean match(PngChunk c) {
            return ChunkHelper.isUnknown(c);
        }
    });
    if (!u.isEmpty())
        System.out.println("Unknown chunks:" + u);
}

所以基本上我只是镜像一个 apng 文件,它被转换成一个 png 文件,这是第一帧.那么有人可以告诉我如何获取剩余的帧并将它们保存为 png 文件吗?任何帮助或提示都会被应用

so basically i am just mirroring an apng file and it gets converted into a png file which is the first frame. So can some one tell me how to get the remaining frames and save them as png files? Any help or hints would be appricated

推荐答案

实际上是 PNGJ库(我是作者)不支持 APNG 标准(题外话:我决定反对它,因为我不喜欢 APGN 方法,因为它不符合我的库的想法:加载巨大"数据 -IDAT-逐行渐进;并直接将块(元数据)加载到内存中;APGN 滥用 PGN 标准,将帧存储在块中).

Actually the PNGJ library (I'm the author) does not support APNG standard (digression: I decided against it because I didn't like APGN approach and because it didn't fit with the idea of my library :loading "huge" data -IDAT- progressively, line by line; and loading the chunks (metadata) in memory directly; APGN abuses the PGN standard by storing frames in chunks).

您可以尝试使用它来做您想做的事情,但不能以优雅和健壮的方式使用.这是一个例子.除了丑陋之外,这不适用于部分帧(小于完整图像的帧,APNG 支持),也不适用于叠加层,也不适用于调色板图像(后面的问题最容易解决)(已修复,希望如此).

You could try to use it anyay to do what you want to, but not in an elegant and robust way. Here's an example. Beside being ugly, this would not work for partial frames (frames smaller than the full image, which APNG supports), nor for overlays, nor for paletted images (the later issue would be the easiest to fix) (fixed, hopefully).

这是用 http://philip.html5.org/tests/apng/测试的028.png

import java.io.File;
import java.io.FileOutputStream;

import ar.com.hjg.pngj.FileHelper;
import ar.com.hjg.pngj.ImageLine;
import ar.com.hjg.pngj.PngHelperInternal;
import ar.com.hjg.pngj.PngReader;
import ar.com.hjg.pngj.PngWriter;
import ar.com.hjg.pngj.chunks.*;

public class ApngSplit {

    private static final String PREFIX = "apngf";

    /** reads a APNG file and tries to split it into its frames */
    public static void process(File orig) throws Exception {
        PngReader pngr = FileHelper.createPngReader(orig);
        File dest = new File(orig.getParent(), PREFIX + "0_" + orig.getName());
        PngWriter pngw = FileHelper.createPngWriter(dest, pngr.imgInfo, true);
        System.out.println("writing default frame " + pngw.getFilename());
        pngr.setChunkLoadBehaviour(ChunkLoadBehaviour.LOAD_CHUNK_ALWAYS);
        pngr.setMaxBytesMetadata(Integer.MAX_VALUE);
        pngr.setMaxTotalBytesRead(Long.MAX_VALUE);
        pngr.setSkipChunkIds(new String[] {});
        int copyPolicy = ChunkCopyBehaviour.COPY_PALETTE | ChunkCopyBehaviour.COPY_ALL_SAFE;
        pngw.copyChunksFirst(pngr, copyPolicy);
        int cols = pngr.imgInfo.cols;
        int channels = pngr.imgInfo.channels;
        for (int row = 0; row < pngr.imgInfo.rows; row++) {
            ImageLine l1 = pngr.readRow(row);
            pngw.writeRow(l1, row);
        }
        pngr.end();
        pngw.copyChunksLast(pngr, copyPolicy);
        pngw.end();
        processExtra2(orig, pngr.getChunksList());
    }

    private static void processExtra2(File orig, ChunksList chunks) throws Exception {
        int numframe = 0;
        FileOutputStream os = null;
        boolean afterIdat = false;
        for (PngChunk chunkApng : chunks.getChunks()) {
            if (chunkApng.id.equals("IDAT"))
                afterIdat = true;
            if (chunkApng.id.equals("fcTL") && afterIdat) {
                numframe++;
                if (os != null)
                    endPng(chunks, os);
                File dest = new File(orig.getParent(), PREFIX + numframe + "_" + orig.getName());
                System.out.println("writing seq " + numframe + " : " + dest);
                os = new FileOutputStream(dest);
                beginPng(chunks, os);
            }
            if (chunkApng.id.equals("fdAT")) {
                ChunkRaw crawf = chunkApng.createRawChunk();
                int seq = PngHelperInternal.readInt4fromBytes(crawf.data, 0);
                ChunkRaw crawi = new ChunkRaw(crawf.len - 4, ChunkHelper.b_IDAT, true);
                System.arraycopy(crawf.data, 4, crawi.data, 0, crawi.data.length);
                crawi.writeChunk(os);
            }
        }
        if (os != null)
            endPng(chunks, os);
    }

    private static void endPng(ChunksList chunks, FileOutputStream fos) throws Exception {
        chunks.getById1(PngChunkIEND.ID).createRawChunk().writeChunk(fos);
        fos.close();
    }

    private static void beginPng(ChunksList chunks, FileOutputStream fos) throws Exception {
        fos.write(new byte[] { -119, 80, 78, 71, 13, 10, 26, 10 }); // signature
        chunks.getById1(PngChunkIHDR.ID).createRawChunk().writeChunk(fos);
        PngChunk plte = chunks.getById1(PngChunkPLTE.ID);
        if (plte != null)
            plte.createRawChunk().writeChunk(fos);
    }

    public static void main(String[] args) throws Exception {
        process(new File("C:/temp/029.png"));
    }

}

这篇关于在java中从APNG中提取png文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆