当前位置: 首页> 财经> 股票 > 重庆建设施工安全信息网官网_工程项目建设程序_网络营销案例具体分析_百度推广app下载官方

重庆建设施工安全信息网官网_工程项目建设程序_网络营销案例具体分析_百度推广app下载官方

时间:2025/7/11 7:47:27来源:https://blog.csdn.net/qq_44136028/article/details/146977036 浏览次数:1次
重庆建设施工安全信息网官网_工程项目建设程序_网络营销案例具体分析_百度推广app下载官方

前端压缩视频(@ffmpeg/ffmpeg)和图片(browser-image-compression)

1.压缩图片

安装插件
npm install browser-image-compression --save
引入插件
import { createWorker } from 'browser-image-compression';
定义方法
   // 压缩图片async compressImage(file, maxSizeMB) {const options = {maxSizeMB,maxWidthOrHeight: 1920,useWebWorker: true};try {const compressedFile = await imageCompression(file, options);const fileExtension = file.name.split('.').pop();const compressedFileName = `${Date.now()}.${fileExtension}`;return new File([compressedFile], compressedFileName, { type: file.type });} catch (error) {console.error('图片压缩失败:', error);return file; // 压缩失败则使用原文件}},

2.压缩视频

安装插件
npm install @ffmpeg/ffmpeg@0.12.6 --save
npm install @ffmpeg/util@0.12.1 --save
npm install @ffmpeg/core@0.12.4 --save
引入插件
import { FFmpeg } from '@ffmpeg/ffmpeg'
import { fetchFile ,toBlobURL} from '@ffmpeg/util'  // 注意来源包变化
定义方法
   // 初始化 FFmpegasync initFFmpeg() {this.initStatus = 'loading'try {this.ffmpeg = new FFmpeg()// 加载关键资源await this.ffmpeg.load({coreURL: '/public/ffmpeg-core.js',wasmURL: '/public/ffmpeg-core.wasm',workerURL: '/public/ffmpeg-core.worker.js'})// 验证初始化完成if (!this.ffmpeg.loaded) {throw new Error('FFmpeg 核心加载失败')}console.log('FFmpeg 初始化完成');this.initStatus = 'ready'this.retryCount = 0} catch (err) {this.initStatus = 'error'console.error('初始化失败:', err)}}// 压缩视频async compressVideo() {if (!this.ffmpeg?.loaded) {alert('FFmpeg 未初始化完成,请稍后重试')return}try {await this.ffmpeg.writeFile('input.mp4', await fetchFile(this.currentFile))await this.executeCompression(10) return await this.outputResult()} catch (err) {console.log(222);// this.handleError(err)}},// 开始压缩async executeCompression(maxSizeMB) {const bitrate = maxSizeMB * 8 * 1024 * 1024 / 10; // 计算目标比特率const crf = 23; // 常用的 CRF 值,数值越小质量越高console.log('executeCompression');try {await this.ffmpeg.exec(['-i', 'input.mp4','-b:v', `${6000}k`,'-vf', 'scale=640:-1', // 调整分辨率,'-preset', 'fast', // 编码速度'output.mp4']);console.log('Compression completed successfully');} catch (err) {console.error('Compression failed:', err);// 处理错误,例如显示错误消息this.status = '压缩失败: ' + err.message;}},// 输出压缩结果async outputResult() {console.log('outputResult');const data = await this.ffmpeg.readFile('output.mp4')const fileExtension = this.currentFile.name.split('.').pop();const compressedFileName = `${Date.now()}.${fileExtension}`;return new File([data], compressedFileName, { type: 'video/mp4' });// const url = URL.createObjectURL(new Blob([data], { type: 'video/mp4' }))// 处理下载或预览...},
完整的代码
<template><div class="container"><!-- <input type="file" @change="handleFileUpload" accept="video/*" /> --><input type="file" @change="handleFileUpload"  /><button :disabled="isProcessing" @click="compress">{{ isProcessing ? '处理中...' : '开始压缩' }}</button><!-- 进度条 --><div v-for="(progress, index) in uploadProgresses" :key="index" class="progress-container"><div class="file-name">{{ progress.fileName }}</div><div class="progress-bar"><div class="progress" :style="{ width: progress.percentage + '%' }"></div></div><div class="progress-text">{{ progress.percentage }}%</div></div><!-- 状态提示 --><div class="status">{{ status }}</div><!-- 压缩结果预览 --><video v-if="compressedUrl" :src="compressedUrl" controls class="preview"></video><a v-if="compressedUrl" :href="compressedUrl" download="compressed.mp4">下载压缩文件</a></div>
</template><script>
import imageCompression from 'browser-image-compression';
import { FFmpeg } from '@ffmpeg/ffmpeg'
import axios from 'axios';
import { fetchFile ,toBlobURL} from '@ffmpeg/util'  // 注意来源包变化
// const baseURL = 'https://cdn.jsdelivr.net/npm/@ffmpeg/core-mt@0.12.9/dist/esm'
export default {data() {return {isProcessing: false,progress: 0,status: '',compressedUrl: null,ffmpeg: null,currentFile: null,retryCount: 0,initStatus: 'loading', // 初始化状态:loading, ready, erroruploadProgresses:[]}},methods: {// 更新上传进度updateUploadProgress(index, percentage) {this.uploadProgresses[index].percentage = percentage;},// 上传文件async uploadFiles(files) {const uploadPromises = files.map((file, index) => {const formData = new FormData();formData.append('files', file);return axios.post('http://localhost:9080/upload', formData, {headers: {'Content-Type': 'multipart/form-data',},onUploadProgress: (progressEvent) => {console.log(progressEvent);const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);this.updateUploadProgress(index, percentCompleted);}});});try {await Promise.all(uploadPromises);alert('文件上传成功');} catch (error) {console.error('上传失败:', error);alert('文件上传失败');}},//获取上传文件async handleFileUpload(e) {this.currentFile = e.target.files[0]this.uploadProgresses.push({fileName: this.currentFile.name,percentage: 0});},// 压缩图片async compressImage(file, maxSizeMB) {const options = {maxSizeMB,maxWidthOrHeight: 1920,useWebWorker: true};try {const compressedFile = await imageCompression(file, options);const fileExtension = file.name.split('.').pop();const compressedFileName = `${Date.now()}.${fileExtension}`;return new File([compressedFile], compressedFileName, { type: file.type });} catch (error) {console.error('图片压缩失败:', error);return file; // 压缩失败则使用原文件}},// 压缩视频async compressVideo() {if (!this.ffmpeg?.loaded) {alert('FFmpeg 未初始化完成,请稍后重试')return}try {await this.ffmpeg.writeFile('input.mp4', await fetchFile(this.currentFile))await this.executeCompression(10) return await this.outputResult()} catch (err) {console.log(222);// this.handleError(err)}},// 开始压缩async compress() {if (!this.currentFile) {alert('请选择一个视频文件')return}this.isProcessing = trueconst compressedFiles = [];let compressedFile;if(this.currentFile.type.includes('image')){compressedFile = await this.compressImage(this.currentFile, 1); // 设置最大文件大小为1MB}else if(this.currentFile.type.includes('video')){compressedFile =  await this.compressVideo()}compressedFiles.push(compressedFile);this.isProcessing = falsethis.uploadFiles(compressedFiles);},// 开始压缩async executeCompression(maxSizeMB) {const bitrate = maxSizeMB * 8 * 1024 * 1024 / 10; // 计算目标比特率const crf = 23; // 常用的 CRF 值,数值越小质量越高console.log('executeCompression');try {await this.ffmpeg.exec(['-i', 'input.mp4','-b:v', `${6000}k`,'-vf', 'scale=640:-1', // 调整分辨率,'-preset', 'fast', // 编码速度'output.mp4']);console.log('Compression completed successfully');} catch (err) {console.error('Compression failed:', err);// 处理错误,例如显示错误消息this.status = '压缩失败: ' + err.message;}},// 输出压缩结果async outputResult() {console.log('outputResult');const data = await this.ffmpeg.readFile('output.mp4')const fileExtension = this.currentFile.name.split('.').pop();const compressedFileName = `${Date.now()}.${fileExtension}`;return new File([data], compressedFileName, { type: 'video/mp4' });// const url = URL.createObjectURL(new Blob([data], { type: 'video/mp4' }))// 处理下载或预览...},async initFFmpeg() {this.initStatus = 'loading'try {this.ffmpeg = new FFmpeg()// 加载关键资源await this.ffmpeg.load({coreURL: '/public/ffmpeg-core.js',wasmURL: '/public/ffmpeg-core.wasm',workerURL: '/public/ffmpeg-core.worker.js'// coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'),// wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, 'application/wasm'),// workerURL: await toBlobURL(`${baseURL}/ffmpeg-core.worker.js`, 'text/javascript')})// 验证初始化完成if (!this.ffmpeg.loaded) {throw new Error('FFmpeg 核心加载失败')}console.log('FFmpeg 初始化完成');this.initStatus = 'ready'this.retryCount = 0} catch (err) {this.initStatus = 'error'console.error('初始化失败:', err)}}},async mounted() {try {this.initFFmpeg()} catch (err) {console.error('FFmpeg 初始化失败:', err)}}
}
</script><style>
.container {max-width: 600px;margin: 2rem auto;padding: 20px;
}input[type="file"] {margin-bottom: 1rem;
}button {background: #42b983;color: white;border: none;padding: 10px 20px;border-radius: 4px;cursor: pointer;
}button:disabled {background: #ccc;cursor: not-allowed;
}.progress-container {margin: 1rem 0;height: 20px;border-radius: 10px;position: relative;
}.progress-bar {height: 100%;background: #42b983;border-radius: 10px;transition: width 0.3s ease;
}.progress-container span {position: absolute;right: 10px;top: 1px;color: #333;
}.status {margin: 1rem 0;color: #666;
}.preview {width: 100%;margin-top: 1rem;border: 1px solid #ddd;
}a {display: inline-block;margin-top: 1rem;color: #42b983;text-decoration: none;
}.file-upload-container {max-width: 800px;margin: 0 auto;padding: 20px;}.progress-container {margin: 10px 0;}.file-name {margin-bottom: 5px;font-size: 14px;}.progress-bar {height: 20px;border: 1px solid #ccc;border-radius: 5px;overflow: hidden;background-color: #f5f5f5;}.progress {height: 100%;background-color: #4CAF50;width: 0;}.progress-text {margin-top: 5px;text-align: center;}
</style>
本地起node+express服务
const express = require('express');
const multer = require('multer');
const cors = require('cors');
const path = require('path');
const fs = require('fs');const app = express();
const port = 9080;// 配置 CORS
app.use(cors());
app.use((req, res, next) => {res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp');res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');next();
});
// 配置 multer 存储
const storage = multer.diskStorage({destination: function (req, file, cb) {cb(null, 'uploads/'); // 上传文件的存储目录},filename: function (req, file, cb) {cb(null, Date.now() + path.extname(file.originalname)); // 重命名文件,避免文件名冲突}
});// 配置文件过滤
const fileFilter = (req, file, cb) => {if (file.mimetype.startsWith('image/') || file.mimetype.startsWith('video/') || file.mimetype === 'application/gzip') {cb(null, true); // 接受文件} else {cb(null, false); // 拒绝文件cb(new Error('文件类型不被允许'));}
};// 配置 multer
const upload = multer({storage: storage,limits: {fileSize: 1024 * 1024 * 100 // 限制文件大小为 100MB},fileFilter: fileFilter
});// 创建上传目录
if (!fs.existsSync('uploads')) {fs.mkdirSync('uploads');
}// 多文件上传接口
app.post('/upload', upload.array('files'), (req, res) => {if (req.files && req.files.length > 0) {const files = req.files.map(file => ({filename: file.filename,originalname: file.originalname,mimetype: file.mimetype,size: file.size}));res.status(200).json({message: '文件上传成功',data: files});} else {res.status(400).json({ message: '文件上传失败' });}
});// 启动服务器
app.listen(port, () => {console.log(`服务器运行在 http://localhost:${port}`);
});
关键字:重庆建设施工安全信息网官网_工程项目建设程序_网络营销案例具体分析_百度推广app下载官方

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: