上传文件并对图片/视频/音频/大文件通过python压缩文件,上传minio存储

一、python压缩文件环境和库

python版本:3.12

1、使用 Pillow(PIL)库对图片进行压缩,支持调整质量、尺寸和格式转换。

pip install pillow

2、使用 FFmpeg对视频压缩

# Ubuntu/Debian
sudo apt install ffmpeg

3、使用pydub(基于 FFmpeg 的封装)对音频压缩

pip install pydub

4、使用 gzip对大文件压缩

二、压缩对象并上传到minio

具体压缩到什么大小,需要结合具体对象的格式等信息

from PIL import Image
import subprocess
import gzip
from io import BytesIO
from pydub import AudioSegment


    async def compress(cls, file_in: UploadFile, file_type: int, ext: str, object_name_no_ext):
        # 关于参数 file_in: uniapp前端上传提交的数据,python服务端通过fastapi的UploadFile类型接收
        # file_type: 上传对象的类型,10图片 20视频 30文件 40音频
        # ext: 上传对象的扩展名
        # object_name_no_ext:创建的对象名称(不带扩展名)/img/20260515/123EM 、 test,方便压缩后组成存储文件名,如/img/20260515/123EM.jpeg,test.ppt.gz
        # 压缩文件
        # 执行压缩
        if file_type == 10:
            # quality: 压缩质量(1 - 100)
            quality = 85
            img = Image.open(BytesIO(file_in.file.read()))
            # 调整尺寸(可选)
            # max_size = (1024, 768)
            # max_size: 最大尺寸(宽, 高),如(800, 600)
            # if max_size:
            #     img.thumbnail(max_size, Image.Resampling.LANCZOS)

            # format: 输出格式(JPEG, PNG, WEBP)
            img_format = "JPEG"
            content_type = "image/jpeg"
            new_ext = 'jpeg'
            # if ext == 'png':
            #     img_format = 'PNG'
            #     content_type = "image/png"
            #     new_ext = 'png'
            #     max_size = (1920, 1080)
            #     img.thumbnail(max_size, Image.Resampling.LANCZOS)
            # 转换为 RGB(避免 RGBA 保存 JPEG 报错)
            if img.mode in ("RGBA", "P"):
                img = img.convert("RGB")
            compressed_data = BytesIO()
            img.save(compressed_data, format=img_format, quality=quality, optimize=True)
            compressed_data.seek(0)
            length = len(compressed_data.getvalue())
            object_name = object_name_no_ext + '.' + new_ext
            return compressed_data, content_type, length, object_name, new_ext
        elif file_type == 20:
            # 视频压缩
            # 启动 FFmpeg 进程(从 stdin 读取,输出到 stdout)
            # preset: 编码速度(ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow)
            # crf: 压缩质量(0 - 51,越小质量越高,建议18 - 28)
            ffmpeg_cmd = [
                "ffmpeg",
                "-i", "pipe:0",
                "-vcodec", "libx264",
                "-crf", "24",
                "-preset", "fast",
                "-acodec", "aac",
                "-f", "mp4",
                "-movflags", "frag_keyframe+empty_moov",  # 允许流式 MP4
                "pipe:1"
            ]
            proc = subprocess.Popen(ffmpeg_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

            # 写入输入数据并获取压缩后的数据
            compressed_data, _ = proc.communicate(input=file_in.file.read())
            compressed_data = BytesIO(compressed_data)
            content_type = "video/mp4"
            length = len(compressed_data.getvalue())
            object_name = object_name_no_ext + '.' + 'mp4'
            return compressed_data, content_type, length, object_name, 'mp4'
        elif file_type == 40:
            # 音频压缩
            # format: 输入文件的格式(如"wav", "mp3", "flac")
            # bitrate: 目标比特率(如"128k")设置音频比特率(常见值:64k(低质量)、128k(标准)、192k(高质量)
            bitrate = "128k"
            audio = AudioSegment.from_file(BytesIO(file_in.file.read()), format=ext)
            # 导出为 MP3
            compressed_data = BytesIO()
            audio.export(compressed_data, format="mp3", bitrate=bitrate)
            compressed_data.seek(0)
            compressed_data = BytesIO(compressed_data.read())
            content_type = "audio/mpeg"
            length = len(compressed_data.getvalue())
            object_name = object_name_no_ext + '.' + 'mp3'
            return compressed_data, content_type, length, object_name, 'mp3'
        else:
            # 使用GZIP压缩大文件
            compressed_data = BytesIO()
            with gzip.GzipFile(fileobj=compressed_data, mode="wb") as gz:
                gz.write(file_in.file.read())
            compressed_data.seek(0)
            content_type = "application/gzip"
            length = len(compressed_data.getvalue())
            object_name = object_name_no_ext + '.' + ext + '.gz'
            return compressed_data, content_type, length, object_name, '.gz'
    # 获取压缩后的数据,对象类型、压缩后的文件大小,对象存储名称,文件扩展名
    compressed_data, content_type, file_size, object_name, origin_ext = await compress(file_in, file_type, ext, object_name_no_ext)
    # minio上传压缩后的文件
    put_config = {
			'bucket_name': bucket_name,
			'object_name': object_name,
			'data': compressed_data,
			'length': file_size,
			'part_size': 10*1024*1024
		}
	if content_type:
		put_config['content_type'] = content_type
	minioClient.put_object(**put_config)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值