预备接手表情包处理业务,前期处理并不复杂,流程包括 : GIF动图与视频的解帧 , 逐帧处理, 组合各帧得到新的GIF. 经过调研, 整合了ffmpeg的Java CV 可完美处理解帧 , animated-gif-lib 组件包含gif生成的成熟方案 , 进而问题解决.
animated-gif-lib.jar是用来拆分和合成GIF的工具包,主要用到其中的GifDecoder/AnimatedGifEncoder.
Java CV 常用于音频/图片等处理,其中整合了常用的c++类库,例如音频处理的ffmpeg,且可与Open CV配合使用.这里主要用到FFmpegFrameGrabber来取帧/Java2DFrameConverter来类型转换.
其实,GifDecoder也可以完成解帧的过程,但实际使用中发现各帧颜色处理上有偏差,解帧问题较大.故而,采用Java CV来解帧,只使用其中合成GIF的操作.
解帧,FFmpegFrameGrabber获取GIF总帧数时异常,故而采用GifDecoder获取
String gifPath = "/home/lab/test/11.gif"; String dirPath = "/home/lab/test/gif/"; // 用以解帧 FFmpegFrameGrabber grabberGif = new FFmpegFrameGrabber(gifPath); grabberGif.start(); Frame frame ; // 用以获取GIF总帧数 GifDecoder decoder = new GifDecoder(); int status = decoder.read(gifPath); if (status != GifDecoder.STATUS_OK) { throw new IOException("read image " + gifPath + " error!"); } // 类型转换,Frame -> BufferedImage Java2DFrameConverter converter = new Java2DFrameConverter(); int frameCount = decoder.getFrameCount(); for (int i = 0 ; i < frameCount ; i++) { String fileName = dirPath + "img_" + i + ".jpg"; File outPut = new File(fileName); frame = grabberGif.grabImage(); if (frame != null) { ImageIO.write(converter.getBufferedImage(frame),"jpg",outPut); } } grabberGif.stop();
合成GIF
int frameRate = 20;// 新GIF总帧数 String resGif = "/home/lab/test/22.gif"; FileOutputStream targetFile = new FileOutputStream(resGif); // 目标文件流 int margin = 2; // 间隔帧数 AnimatedGifEncoder en = new AnimatedGifEncoder(); en.setFrameRate(frameRate); en.start(targetFile); for (int i = 0; i < frameRate; i++) { en.addFrame(converter.convert(grabberGif.grabImage())); grabberGif.setFrameNumber(grabberGif.getFrameNumber() + margin); } en.finish(); grabberGif.stop(); targetFile.close();
原GIF倒序得到新GIF
String gifPath = "/home/lab/test/11.gif"; // 用以解帧 FFmpegFrameGrabber grabberGif = new FFmpegFrameGrabber(gifPath); grabberGif.start(); // 用以获取GIF总帧数 GifDecoder decoder = new GifDecoder(); int status = decoder.read(gifPath); if (status != GifDecoder.STATUS_OK) { throw new IOException("read image " + gifPath + " error!"); } // 类型转换,Frame -> BufferedImage Java2DFrameConverter converter = new Java2DFrameConverter(); int frameCount = decoder.getFrameCount(); String resGif = "/home/lab/test/22.gif"; FileOutputStream targetFile = new FileOutputStream(resGif); // 目标文件流 AnimatedGifEncoder en = new AnimatedGifEncoder(); en.setFrameRate(frameCount); en.start(targetFile); for (int i = frameCount - 1; i >= 0; i--) { grabberGif.setFrameNumber(i); en.addFrame(converter.convert(grabberGif.grabImage())); } en.finish(); grabberGif.stop(); targetFile.close();
因 javacv-platform依赖过重,实际引入的时候推荐指定系统版本的即可.开发机为64位Ubuntu,依赖如下
<dependency> <groupId>org.bytedeco</groupId> <artifactId>javacv</artifactId> <version>1.4.3</version> </dependency> <dependency> <groupId>org.bytedeco.javacpp-presets</groupId> <artifactId>opencv</artifactId> <version>3.4.3-1.4.3</version> <classifier>linux-x86_64</classifier> </dependency> <dependency> <groupId>org.bytedeco.javacpp-presets</groupId> <artifactId>ffmpeg</artifactId> <version>4.0.2-1.4.3</version> <classifier>linux-x86_64</classifier> </dependency> <dependency> <groupId>org.bytedeco</groupId> <artifactId>javacpp</artifactId> <version>1.4.3</version> </dependency> <dependency> <groupId>org.bytedeco.javacpp-presets</groupId> <artifactId>ffmpeg</artifactId> <version>4.0.2-1.4.3</version> <classifier>linux-x86_64</classifier> </dependency> <!-- gif --> <dependency> <groupId>com.madgag</groupId> <artifactId>animated-gif-lib</artifactId> <version>1.4</version> </dependency>
原文:https://www.cnblogs.com/nyatom/p/10837363.html