【JAVA】 后端 图片裁剪、压缩 及 视频压缩

本人使用java封装的后端媒体处理工具包

基于ImageMagick和FFmpeg客户端,使用java调用命令行实现
https://gitee.com/gnliscream/multimedia-utils

介绍

java后端的图片、视频处理工具jar包

1.获取视频信息

2.生成视频封面图

3.异步压缩视频(生成输出文件名后,调用异步压缩视频方法,且同一时间只会处理一个视频,多个请求的视频会进行排队处理)

4.异步压缩视频完成时回调通知

5.图片裁切

6.图片压缩

客户端安装

运行环境需安装FFmpeg和ImageMagick,官网地址如下:

FFmpeg:https://ffmpeg.org/

ImageMagick:http://www.imagemagick.com.cn/

FFmpeg解压后需设置/bin目录的环境变量,ImageMagick安装版安装后会自动设置环境变量。

引入依赖

<dependency>
      <groupId>com.whty.zdxt</groupId>
      <artifactId>multimedia-utils</artifactId>
      <version>0.0.1-SNAPSHOT</version>
</dependency>

配置

yml 配置上传文件的临时路径

spring:
  servlet:
    multipart:
      # 是否支持 multipart 上传文件
      enabled: true
      # 最大支持文件大小
      max-file-size: 10MB
      # 最大支持请求大小
      max-request-size: 10MB
      # 上传文件的临时目录
      location: E:/tomcat-temp

注入 视频处理类FFmpegUtils 以及 图片处理类 ImageMagickUtils

import com.whty.zdxt.multimedia.util.FFmpegUtils;
import com.whty.zdxt.multimedia.util.ImageMagickUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@Component
public class MultimediaUtilsConfig {
    
    /**
     * 视频处理工具,因为所有压缩任务需要排队进行,所以FFmpegUtils需要是单例的,FFmpegUtils实例交由spring管理就为单例的
     */
    @Bean
    public FFmpegUtils fFmpegUtilsImpl() {
        return new FFmpegUtils();
    }

    /**
     * 图片处理工具
     */
    @Bean
    public ImageMagickUtils imageMagickUtils() {
        return new ImageMagickUtils();
    }

}

使用

FileController

import com.example.demo.util.FileUtil;
import com.whty.zdxt.multimedia.attribute.CompressionAttributes;
import com.whty.zdxt.multimedia.attribute.CropAttributes;
import com.whty.zdxt.multimedia.attribute.ResizeAttributes;
import com.whty.zdxt.multimedia.attribute.VideoAttributes;
import com.whty.zdxt.multimedia.enumeration.Suffix;
import com.whty.zdxt.multimedia.enumeration.VideoSize;
import com.whty.zdxt.multimedia.pojo.FFmpegInfo;
import com.whty.zdxt.multimedia.util.FFmpegUtils;
import com.whty.zdxt.multimedia.util.ImageMagickUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.servlet.MultipartProperties;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;

@RestController
@RequestMapping("/file")
public class FileController {

    @Autowired
    private FFmpegUtils fFmpegUtils;

    @Autowired
    private MultipartProperties multipartProperties;

    @Autowired
    private ImageMagickUtils imageMagickUtils;

    /**
     * 获取视频信息
     */
    @PostMapping("/getVideoInfo")
    public Object getFileInfo(@RequestParam MultipartFile file) {
        String location = multipartProperties.getLocation();

        // 生成上传视频的临时文件
        File inputFile = FileUtil.multipartFile2File(file, location);

        // 调用视频处理工具类
        String inputFileName = inputFile.getName();
        FFmpegInfo info = fFmpegUtils.getInfo(location, inputFileName);

        // 删除上传视频的临时文件
        inputFile.delete();
        return info;
    }

    /**
     * 生成视频封面图
     */
    @PostMapping("/createVideoCover")
    public Object createVideoCover(@RequestParam MultipartFile file) {
        String location = multipartProperties.getLocation();
        // 生成上传视频的临时文件
        File inputFile = FileUtil.multipartFile2File(file, location);

        // 调用视频处理工具类
        String outputFileName = fFmpegUtils.createCover(location, inputFile.getName());

        // 删除上传视频的临时文件
        inputFile.delete();
        return outputFileName;
    }

    /**
     * 压缩视频
     */
    @PostMapping("/compressionVideo")
    public Object compressionVideo(@RequestParam MultipartFile file) {

        String location = multipartProperties.getLocation();

        // 生成上传视频的临时文件
        File inputFile = FileUtil.multipartFile2File(file, location);

        // 调用视频处理工具类


        CompressionAttributes compressionAttributes = new CompressionAttributes();
        // 设置视频压缩完成时的回调URL
        compressionAttributes.setProgressUrl("http://localhost:8999/file/callback?fileId=111111&a=456");

        // 设置视频压缩参数
        VideoAttributes videoAttributes = new VideoAttributes();
        videoAttributes.setMaxDuration(15);
        videoAttributes.setMaxFps(20);
        videoAttributes.setVideoSize(VideoSize.HD480);

        compressionAttributes.setVideoAttributes(videoAttributes);

        String outputFileName = fFmpegUtils.putCompressionTask(location, inputFile.getName(), compressionAttributes);

        return outputFileName;
    }

    /**
     * 压缩视频完成时的回调
     */
    @PostMapping("/callback")
    public Object callback(@RequestBody String info, @RequestParam("fileId") String fileId, @RequestParam("a") String a) {
        // 回调信息
        String[] split = info.split("/");

        // 回调参数 fileId,根据fileId查询数据库的上传临时文件名和下载临时文件名,进行文件上传和文件删除
        System.out.println(String.format("fileId为%s的文件已压缩完成", fileId));

        return null;
    }

    /**
     * 图片裁切
     */
    @PostMapping("/crop")
    public Object crop(@RequestParam MultipartFile file) {

        String location = multipartProperties.getLocation();

        // 生成上传图片的临时文件
        File inputFile = FileUtil.multipartFile2File(file, location);

        // 调用图片处理工具类
        // 裁切成3000x1200的图后,修改分辨率为宽800的图(高度按比例缩小)
        CropAttributes cropAttributes = new CropAttributes(3000, 1200, 1000, 500);
        ResizeAttributes resizeAttributes = new ResizeAttributes(800, null);
        String outputFileName = imageMagickUtils.cropAndResize(location, inputFile.getName(), cropAttributes, resizeAttributes);

        // 删除上传图片的临时文件
        inputFile.delete();
        return outputFileName;
    }

    /**
     * 图片分辨率修改
     */
    @PostMapping("/resize")
    public Object resize(@RequestParam MultipartFile file) {

        String location = multipartProperties.getLocation();

        // 生成上传图片的临时文件
        File inputFile = FileUtil.multipartFile2File(file, location);

        // 调用图片处理工具类
        ResizeAttributes resizeAttributes = new ResizeAttributes(800, null);
        String outputFileName = imageMagickUtils.resize(location, inputFile.getName(), resizeAttributes, Suffix.JPG);

        // 删除上传图片的临时文件
        inputFile.delete();
        return outputFileName;
    }

}

FileUtil

import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.UUID;

public class FileUtil {

    /**
     * 将上传的MultipartFile转化为File
     */
    public static File multipartFile2File(MultipartFile multipartFile, String directory) {
        String suffix = getSuffix(multipartFile.getOriginalFilename());
        File tempFile = null;
        try {
            tempFile = new File(directory + "/" + UUID.randomUUID().toString() + suffix);
            multipartFile.transferTo(tempFile);
        } catch (IOException e) {
            throw new RuntimeException("multipartFile转File失败", e);
        }
        return tempFile;
    }

    /**
     * 获取文件拓展名
     */
    public static String getSuffix(String fileName) {
        if (fileName == null) {
            throw new RuntimeException("获取文件拓展名失败");
        }
        int index = fileName.lastIndexOf(".");
        if (-1 == index) {
            throw new RuntimeException("获取文件拓展名失败");
        }
        return fileName.substring(index);
    }

}

文档

图片工具ImageMagickUtils

方法

1.图片裁切后修改分辨率并指定输出文件格式

cropAndResize(tempDirectory,inputFileName,cropAttributes,resizeAttributes,outputFileSuffix)

2.图片裁切后修改分辨率

cropAndResize(tempDirectory,inputFileName,cropAttributes,resizeAttributes)

3.图片裁切并指定输出文件格式

crop(tempDirectory,inputFileName,cropAttributes,outputFileSuffix)

4.图片裁切

crop(tempDirectory,inputFileName,cropAttributes)

5.图片修改分辨率并指定输出文件格式

resize(tempDirectory,inputFileName,resizeAttributes,outputFileSuffix)

6.图片修改分辨率

resize(tempDirectory,inputFileName,resizeAttributes)

参数介绍

输入参数
参数 类型 必需 注释
tempDirectory String 临时文件目录
inputFileName String 输入文件名
cropAttributes CropAttributes 裁切参数
resizeAttributes ResizeAttributes 修改分辨率参数
outputFileSuffix Suffix 输出文件格式,未设置则同输入文件格式

其中:

CropAttributes

参数 类型 必需 注释
width Integer 裁切图片的宽
height Integer 裁切图片的高
leftOffset Integer 距左边偏移量
topOffset Integer 距顶部偏移量

ResizeAttributes

参数 类型 必需 注释
width Integer 输出图片的宽,只填写宽则高自适应
height Integer 输出图片的高,只填写高则宽自适应
quality Integer 输出图片的质量,范围0~100,默认100
输出参数
参数 类型 必需 注释
outputFileName String 输出文件名

视频工具FFmpegUtils

方法

1.获取视频信息

getInfo(tempDirectory,inputFileName)

输入参数
参数 类型 必需 注释
tempDirectory String 临时文件目录
inputFileName String 输入文件名
输出参数
参数 类型 必需 注释
format FFFormat 文件信息
videoInfo VideoInfo 视频信息
audioInfo AudioInfo 音频信息

其中:

FFFormat

参数 类型 必需 注释
filename String 文件名全路径名
duration String 文件时长
size String 文件大小
bitRate String 文件比特率

VideoInfo

参数 类型 必需 注释
codecName String 视频 编码名称
codecType String 类型 video
width Integer 视频 宽度
height Integer 视频 高度
frameRate Integer 视频 帧率
duration Integer 视频 时长
bitRate Integer 视频 比特率
nbFrames Integer 视频 总帧数

AudioInfo

参数 类型 必需 注释
codecName String 音频 编码名称
codecType String 类型 audio
duration Integer 音频 时长
bitRate Integer 音频 比特率
sampleRate Integer 音频 采样率
channels Integer 音频 声道数 1:单声道 2:双声道
2.截取视频封面

createCover(tempDirectory, inputFileName, outputFileSuffix)

createCover(tempDirectory, inputFileName)

输入参数
参数 类型 必需 注释
tempDirectory String 临时文件目录
inputFileName String 输入文件名
outputFileSuffix Suffix 输出文件格式,默认jpg
输出参数
参数 类型 必需 注释
outputFileName String 输出文件名
3.视频压缩

putCompressionTask(tempDirectory, inputFileName, compressionAttributes)

putCompressionTask(tempDirectory, inputFileName, compressionAttributes, outputFileName)

输入参数
参数 类型 必需 注释
tempDirectory String 临时文件目录
inputFileName String 输入文件名
compressionAttributes CompressionAttributes 压缩参数
outputFileName String 输出文件名,默认UUID生成

其中:

CompressionAttributes

参数 类型 必需 注释
videoAttributes VideoAttributes 视频压缩参数
audioAttributes AudioAttributes 音频压缩参数
progressUrl String 压缩完成后的回调地址

VideoAttributes

参数 类型 必需 注释
codec VideoCodec 视频编码(默认libx264,libx265)
maxFps Integer 最大帧率
videoSize VideoSize 视频分辨率(hd480,hd720,hd1080,800x800)
maxDuration Integer 最大时长
maxBitRate Integer 视频最大比特率

AudioAttributes

参数 类型 必需 注释
maxBitRate Integer 音频最大比特率
maxSamplingRate Integer 音频最大采样率
输出参数
参数 类型 必需 注释
outputFileName String 输出文件名

ImageMagick官网

http://www.imagemagick.com.cn/

命令行

图片裁切

magick 1.jpg -crop 3000x1200+1000+500 2.jpg

1.jpg 为6000x4500的图片

3000x1200 裁切后图片的宽x高

+1000 裁切横坐标偏移量

+500 裁切纵坐标偏移量

2.jpg 为裁切后的3000x1200的图片

image

图片压缩

指定分辨率压缩
magick 1.jpg -resize 3000x2250 2.jpg
给定宽度,高度自动选择以保留宽高比。
magick 1.jpg -resize 3000 2.jpg
给定高度,自动选择宽度以保留宽高比。
magick 1.jpg -resize x2250 2.jpg

FFmpeg官网

https://ffmpeg.org/ffmpeg.html#Advanced-options

命令行

查询视频信息

ffprobe -v quiet -print_format json -show_format -show_streams 1.mp4

设置帧率 -r

ffmpeg –i input.mp4 –r fps output.mp4

设置码率 音频:-b:a 视频: - b:v

ffmpeg -i input.avi -b:v 1500k output.mp4

设置分辨率

ffmpeg -i input.mp4 -s 320x240 output.mp4

设置声道和采样率

-ac 1 设置声道数为1
-ar 48000 设置采样率为48000Hz

截取视频生成图片

从第-ss秒开始,每秒截取-r张图片,持续-t秒,使用-s进行缩放,保存为foo-001.jpeg, foo-002.jpeg...
ffmpeg -i 1.mp4 -ss 5 -r 1 -t 1 -s hd480 -f image2 foo-%03d.jpeg

网上的开源框架

https://github.com/a-schild/jave2

网上的相关资料

https://www.jianshu.com/p/e14bc2551cfd
https://www.jianshu.com/p/3c8c4a892f3c
https://blog.csdn.net/u010629285/article/details/102998555

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270