图片压缩&视频截取

Posted 菜菜

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图片压缩&视频截取相关的知识,希望对你有一定的参考价值。

背景

在我们开发网站的过程中,避免不了要对视频和图片进行一些处理。

场景一:用户上传的视频,我们需要将视频的某一帧截取出来作为视频的封面,便于在视频列表页显示为视频的预览,当然也可以截取某几帧生成一个gif动图。

场景二:用户上传的照片体积很大,我们在展示照片列表的时候,如果想要加载快,除了懒加载的方式(限制每次加载图片的数量,然后上滑继续加载),还可以在列表上只加载缩略图,然后进入详细页面后进行高清显示。

想要实现以上两个场景,如果你是用的是阿里云OSS存储,有提供的处理方式(收费),可以自行去查看:

这里介绍的处理方式是利用插件 ffmpeg 来处理。

实现前准备

FFmpeg 是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。可以轻易地实现多种视频格式之间的相互转换。这里我们只关注上面的两个场景。

打开https://ffmpeg.org/download.html 下载对应系统的工具包,这里我们介绍windows和linux下的使用。

使用

一、Windows环境

1.下载

根据自己已安装的压缩工具,选择对应的稳定版

下载完成后,解压到非C盘的目录下,比如我解压到D:\\tools\\ffmpeg文件夹下,这时我们可以看到D:\\tools\\ffmpeg\\bin下有3个exe执行文件,我们需要将该路径配置到path,就可以在任意命令窗口进行调用。

2.配置

打开系统设置-->点击环境变量-->点击用户变量中的Path-->添加D:\\tools\\ffmpeg\\bin路径,点击确定和应用

打开命令行,运行ffmpeg -version,看到如下提示,就表示成功了

3.图片压缩

有一张图片D:\\tools\\ffmpeg-sta\\avatar.jpg,将命令窗口切换至该目录,执行ffmpeg -i ./avatar.jpg -vf scale=-1:100 ./after.png

使用的就是命令 ffmpeg -i image_source -vf scale=width:height out_source

,该命令中 image_source表示输入文件,out_source是输出文件,width和height分别是压缩后图片的宽和高,当某一项为-1时,表示图片保持原来的比例进行压缩。

下图是压缩并改变格式后的:

4.视频截帧

执行命令ffmpeg -i SampleVideo.mp4 -ss 1 -vframes 1 output.png获取视频1s时的帧。

获取到以下图片为视频1s时的帧:

在windows上的简单使用,只是演示以下功能,我们实际开发更多是在linux环境下实现开头说的图片和视频的处理场景,下面一起来看看。

二、linux环境

1.环境搭建

如果你购买了云服务器,可以在自己的服务器进行部署,如果只是想验证功能是否满足预期,可以搭建一个简单的服务器,可以参考我的上一篇文章

Multipass一款更轻量级的虚拟机

2.编写脚本

这里实现一个上传页面,上传图片后保存原图片和压缩后的图片,上传视频后保存视频和1s时截取的视频帧生成的图片,因为同涉及前后端实现,所以选择nuxt框架(https://nuxt.com.cn/)进行简单实现。

初始化一个项目,并安装依赖

npx nuxi init ffmpeg-test
cd ffmpeg-test 
yarn install

前端

将app.vue文件中的<h1>Welcome to the homepage</h1>替换为<NuxtPage />,根目录下新建pages文件夹,并在该目录下新建index.vue文件,在这个文件中实现前端页面。

<!-- pages/index.vue -->
<template>
 <div>
    <input type="file" name="pickerPic" id="picId" @change="getFile($event)" accept="image/*, video/*">
  </div>   
</template>
  
<script setup lang=\'ts\'>
  function getFile(e:any) 
    const file = e.target.files[0];
    let formData = new FormData();
    formData.append(\'file\',file);
    $fetch(\'/api/upload\', method: \'POST\', body: formData).then(res => 
      console.log(\'res=>\',res)
    )
  
</script>

服务端

在package.json中增加如下配置,运行yarn install安装插件

"dependencies": 
    "axios": "^0.27.2",
    "express": "^4.18.2",
    "formidable": "^2.1.1"
  ,

根目录下新建server文件夹,该文件夹下新建api文件夹,然后在api文件夹下新建upload.js文件,在该文件中实现服务端的逻辑

// server/api/upload.js
import path from \'path\'
import formdata from \'formidable\'
import cp from \'child_process\'
import fs from \'fs\'
const __dirname = path.resolve();

export default defineEventHandler(async (event) => 
  const request = event.node.req


  const filePath = path.join(__dirname, \'./\', \'uploads\');
  var form = new formdata.IncomingForm();
  form.maxFileSize = 50 * 1024 * 1024;
  form.multiples = true
  form.uploadDir = filePath; //指定保存文件的路径,formidable会自动保存文件
  request.files = ;
  request.data = ;

  await form.parse(request);
  await form.on(\'file\', function (name, file) 
    console.log(\'file\');
    request.files[name] = file;//这里提取上传的文件
  );
  await form.on(\'end\', async function () 
    // 默认保存的文件名是随机串
    for (var k in request.files) 
      var f = request.files[k];
      var n = \'origin_\' + f.originalFilename;
      // 自己重新指定文件名和后缀
      if (f.mimetype.indexOf(\'image/\') == 0) 
        await fs.renameSync(f.filepath, filePath + "/" + n);
        // 图片压缩
        await cp.execSync(`ffmpeg -i $filePath/origin_$f.originalFilename -vf scale=-1:100 $filePath/after_$f.originalFilename`)
       else if (f.mimetype.indexOf(\'video/\') == 0) 
        await fs.rename(f.filepath, filePath + "/" + n, async function (err) 
          if (err) throw err;
          // 视频抽帧
          await cp.execSync(`ffmpeg -i $filePath/origin_$f.originalFilename -ss 1 -vframes 1 $filePath/after_pic.png`)
        );
      
    
  );
  return 
    api: \'works\'
  
)

pm2的方式启动,新增了ecosystem.config.js文件

module.exports = 
  apps: [
    
      name: \'NuxtAppName\',
      port: \'3300\',
      exec_mode: \'cluster\',
      instances: \'2\',
      script: \'./.output/server/index.mjs\'
    
  ]

package.json文件中scripts的build命令改为nuxt build & pm2 restart all

3.部署

命令行工具连接服务器,执行命令sudo apt-get install ffmpeg安装ffmpeg,安装完成后执行 ffmpeg -version ,看到如下提示表示安装成功。

遇到问题先执行下面的命令

sudo add-apt-repository main
sudo add-apt-repository universe
sudo add-apt-repository restricted
sudo add-apt-repository multiverse 

将自己的代码下载到该服务器,或者使用我已经上传的示例 https://github.com/guduqiucai/ffmpeg-test.git ,下载后切换到项目根目录,创建一个uploads目录,作为我们存储上传的文件的地方。

服务器安装插件

sudo apt install yarn
sudo apt install nodejs npm
sudo npm install pm2 -g

nuxt3运行需要node16.x及以上版本(可以使用nvm管理node版本)

git clone https://gitee.com/mirrors/nvm
bash install.sh # 注意:进入nvm目录内执行
nvm -version # 查看版本
nvm install v16.16.0

切换到项目根目录,执行yarn install安装依赖,如果报错,先执行下面的命令

sudo apt remove cmdtest
sudo apt remove yarn
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt update
sudo apt install yarn

安装完成后执行yarn build 编译并启动项目,如下图所示服务就正常启动了

这里我的multipass 地址是 172.17.166.77, 而且我们设置的pm2监听端口是3000,所以打开浏览器,访问http://172.17.166.77:3000/可以正常看到如下图所示页面:

上传一个图片,查看服务器存储结果,如下图所示出现了原图片origin_avatar.jpg和压缩后的图片after_avatar.jpg:

上传一个视频,查看服务器存储结果,如下图所示出现了原视频文件origin_SampleVideo.mp4和抽帧的图片after_pic.png:

到这里就简单实现了我们开始说的场景,Over~。

想把手机中的一段视频里的图片截取出来,应该如何操作?

参考技术A

1、在手机安装图一的剪辑软件打开,点击+,在+弹出的菜单选择空项目。

2、点击右侧的媒体然后点选一个需要截取中间一段的视频。

3、如果看到图一的编码警告直接点击确定即可,接着点击右上角的√。然后移动视频,让时间轴处在需要截取视频开头的位置。

4、点击时间轴上面的视频,看到已经多个黄色的框说明被选中了。然后点击菜单上的剪刀。选则中播放指针中拆分。

5、看到视频被分成两节了,然后点击不需要的一节,然后点击删除符号删除视频。

6、在移动到需要的一节结尾的部分,然后点击从播放指针中拆分。然后点击不需要的一节,再次点击删除符号进行删除。

7、然后留下中间的一段视频,让其不被选中状态,即时间轴上面的视频文件无黄色 的框,按手机返回键或者是点击时间轴视频区域外即可不选中视频文件。然后点击导出的符号,在图二点击没有题目。

8、在没有题目下点击图一的位置,之后点击保存到相册即可导出视频。

参考技术B

步骤如下:

①在手机端,下载好爱奇艺,用手点击打开爱奇艺软件。


②再打开的界面中,选择需要截图的视频,点击进入。



③进入下一个界面后,点击视频右下角的全屏图标,即可全屏观看。



④打开全屏后,点击视频右侧的照相机图标即可以截取图片。


参考技术C 用360N4的魔球浮在屏幕上轻点击一键截屏轻松完成保留图像,同时长按音量键十和电源键能截取频,其余的型号不得而知,新买的360N6pro则做不到。

以上是关于图片压缩&视频截取的主要内容,如果未能解决你的问题,请参考以下文章

如何截取视频的第一帧图片

如何利用ffmpeg将一小段视频截取成图片

您好!请问用java怎么将截取png的图片中间一部分,以及如何压缩一个png图片?

pdf文件中截取eps图片并压缩

Canvas截取视频流上传图片

php怎样截取视频图