一、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)

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐