Java对GIF的简单删帧操作

本文介绍了如何使用Java处理GIF动态图,通过GifDecoder和AnimatedGifEncoder类实现读取、删除第一帧并重新编码,解决GIF预览显示问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题简介

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

这里写图片描述

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

那么如果能用代码读取到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); 该方法用于输出分解得到的单个图片文件
    }

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值