Java对GIF的简单删帧操作

来源:互联网 发布:淘宝虚拟专营入口 编辑:程序博客网 时间:2024/06/03 13:18

问题简介

最近在一些网站爬了一些搞笑动态图片,没想到保存好之后预览竟然是是这样:

这里写图片描述

用图片浏览器逐帧看了一下,原来每一张图片第一帧都是类似空白的画面,所以预览的缩略图也是第一张画面。

那么如果能用代码读取到GIF的每一帧,删除后在合并为一个新GIF那问题就解决了。

于是找了下Java 操作GIF图片的类库,最后在GitHub上找到了这个:

animated-gif-lib-for-java

方法简介

整个工程主要就两个java文件,一个用于解码的GifDecoder类,一个用于编码的AnimatedGifEncoder,另外有两个辅助类复制进来即可。

GifDecoder类

主要方法有:

  • public int read(String name)

    指定需要解码的GIF图片路径,还有两个重载方法,支持读取InputStreamBufferedInputStream

  • public int getDelay(int n)

    获取指定帧的延迟时间。

  • public int getFrameCount()

    获取GIF图片的帧数

  • public int getLoopCount()

    获取GIF图片的播放次数,0表示无限循环播放

  • public BufferedImage getFrame(int n)

    获取指定帧的图像数据

AnimatedGifEncoder类

另一个是用于编码的AnimatedGifEncoder类,方法和解码基本相反:

  • public void setDelay(int ms)

    设置每帧之间的延迟时间,GifDecoder能获取到任意两帧之间的延迟,而AnimatedGifEncoder貌似没有提供两帧之间的延迟设定,按照同一延迟时间处理。

  • public void setRepeat(int iter)

    设置播放次数,0表示无限循环播放

  • public boolean addFrame(BufferedImage im)

    添加帧

  • public void setFrameRate(float fps)

    设置帧率,与delay作用类似,相对设置delay为Math.round(100f / fps)

  • public boolean finish()

    添加帧并配置好之后调用这个方法关闭文件输出流等

  • public boolean start(String file)

    设置输出的文件路径,另一个重载方法以流的形式输出

另外AnimatedGifEncoder还提供一些其他方法,包括设置透明度、背景颜色、图片质量、尺寸等。

代码

知道用法之后就简单了,先解码将原始GIF的所有帧数据、帧延迟、播放次数读取出来,然后再编码回去,同时删除第一帧即可。
这里除了点小问题,我的环境中Eclipse突然无法读取绝对路径,所以使用File.separator代替斜杠。

    private String baseOutPath = "D:" + File.separator + "p" + File.separator+ "2" + File.separator;    //存放解码出来的所有帧    private BufferedImage[] bi;    //延迟时间    private int delay;    public static void main(String[] args) throws IOException {        GIFHandler handler = new GIFHandler();        dt.start();    }    private void start() {        //"D:/p/1",要转换的GIF图片目录        File gifPath = new File("D:" + File.separator + "p" + File.separator+ "1");        File[] gifs = null;        //读取出所有GIF图片        if (gifPath.isDirectory()) {            gifs = gifPath.listFiles();        }        if (gifs != null && gifs.length != 0) {            for (File f : gifs) {                trans(f);                System.out.println(f.getName());            }        }        System.out.println("转换完成");    }    /**     *  转换     */    private void trans(File transFile) {        decode(transFile);        encode(baseOutPath + transFile.getName());    }    private void encode(String outPath) {        AnimatedGifEncoder encoder = new AnimatedGifEncoder();        // 设置循环模式,0为无限循环 这里没有使用源文件的播放次数        encoder.setRepeat(0);        // 设置输出路径        encoder.start(outPath);        //这里从1开始,去掉第一帧        for (int i = 1; i < bi.length; i++) {            encoder.setDelay(delay);            encoder.addFrame(bi[i]);        }        encoder.finish();    }    private void decode(File f) {        GifDecoder decoder = new GifDecoder();        try {            decoder.read(new FileInputStream(f));        } catch (FileNotFoundException e) {            e.printStackTrace();        }        // 获取到帧数        int frameCount = decoder.getFrameCount();        bi = new BufferedImage[frameCount];        // 获取到每一帧的数据保存到bi        for (int i = 0; i < frameCount; i++) {            bi[i] = decoder.getFrame(i);        }        // 获取到每帧之间的延迟时间,这里只取第一帧的        delay = decoder.getDelay(0);        // ImageIO.write(frame, "jpeg", out); 该方法用于输出分解得到的单个图片文件    }

使用这两个类可以进行一些简单的帧操作,比如添加水印、设置延迟等。另外源码也不复杂,可以自行定义。

原创粉丝点击