当前位置: 首页 > news >正文

对上传的图片进行压缩,以保证它的大小不超过X MB

你可以在保存文件之前,对上传的图片进行压缩,以保证它的大小不超过 3 MB。可以使用 PIL(Pillow)库来调整图片的尺寸和质量。这里是修改后的代码:

修改点

  1. 调整分辨率:如果图片大小超过 3 MB,则缩小分辨率。
  2. 调整压缩质量:JPEG 图片可以降低 quality 参数(如 85)。
  3. PNG 图片转换:PNG 无法直接调整质量,可以减少色深或调整分辨率。

修改后的代码

from fastapi import APIRouter, UploadFile, File, Form, HTTPException
from PIL import Image
import os
import io

router = APIRouter()

MAX_FILE_SIZE_MB = 3
MAX_FILE_SIZE_BYTES = MAX_FILE_SIZE_MB * 1024 * 1024  # 3MB

def compress_image(image: Image.Image, format: str) -> bytes:
    """压缩图片至 3MB 以内"""
    quality = 95
    while True:
        img_byte_arr = io.BytesIO()
        if format == "JPEG":
            image.save(img_byte_arr, format="JPEG", quality=quality)
        elif format == "PNG":
            image.save(img_byte_arr, format="PNG", optimize=True)
        else:
            raise HTTPException(status_code=400, detail="Unsupported image format")
        
        img_size = img_byte_arr.tell()
        if img_size <= MAX_FILE_SIZE_BYTES or quality <= 20:
            break
        quality -= 5  # 逐步降低质量
        
    return img_byte_arr.getvalue()

async def process_uploaded_image(file: UploadFile):
    """处理上传的图片,调整大小,压缩"""
    if file.content_type not in ["image/jpeg", "image/png"]:
        raise HTTPException(status_code=400, detail="Only JPEG and PNG images are allowed")

    image = Image.open(io.BytesIO(await file.read()))
    
    # 调整图片大小,如果太大则缩小
    width, height = image.size
    if width > 2000 or height > 2000:
        image.thumbnail((2000, 2000))  # 先缩小到 2000x2000 以内

    format = "JPEG" if file.content_type == "image/jpeg" else "PNG"
    compressed_image_data = compress_image(image, format)
    
    return file.filename, compressed_image_data

@router.post("/upload/face-photo")
async def upload_face_photo(file: UploadFile = File(...), phone: str = Form(..., description="用户手机号")):
    """上传手机拍摄的人脸照片,并进行压缩"""
    filename, compressed_image_data = await process_uploaded_image(file)

    file_path = os.path.join(settings.TEMP_DIR, filename)
    with open(file_path, 'wb') as f:
        f.write(compressed_image_data)

    url = upload_to_oss(file_path, filename)
    redis_key = f"face_photos:{phone}"
    redis_client.hset(redis_key, filename, url)

    os.remove(file_path)

    return {"message": "Face photo uploaded successfully", "phone": phone, "filename": filename, "url": url}

@router.post("/upload/arm-photo")
async def upload_phone_photo(file: UploadFile = File(...), phone: str = Form(..., description="用户手机号")):
    """上传手机拍摄的手臂照片,并进行压缩"""
    filename, compressed_image_data = await process_uploaded_image(file)

    file_path = os.path.join(settings.TEMP_DIR, filename)
    with open(file_path, 'wb') as f:
        f.write(compressed_image_data)

    url = upload_to_oss(file_path, filename)
    redis_key = f"arm_photos:{phone}"
    redis_client.hset(redis_key, filename, url)

    os.remove(file_path)

    return {"message": "Arm photo uploaded successfully", "phone": phone, "filename": filename, "url": url}

优化点

  1. 自动调整图片尺寸:如果图片尺寸过大,缩小至 2000x2000 以内。
  2. JPEG 逐步降低质量:从 95 逐步降低到 20,保证文件大小在 3MB 以内。
  3. PNG 优化:对 PNG 进行优化,减少文件大小。
  4. 封装 process_uploaded_image 处理逻辑,复用代码,提高可读性。

这样,用户上传的超大图片会被自动调整大小和质量,不会超过 3MB,从而满足接口要求。

相关文章:

  • 亚马逊新品广告投放策略:从零到爆单的全链路解析
  • 黑客如何查找网络安全漏洞
  • 用 pytorch 从零开始创建大语言模型(四):从零开始实现一个用于生成文本的GPT模型
  • 关于Docker是否被淘汰虚拟机实现连接虚拟专用网络Ubuntu 22.04 LTS部署Harbor仓库全流程
  • C++ 各种map对比
  • 【JVM】内存区域划分,类加载机制和垃圾回收机制
  • openEuler24.03 LTS下安装Hadoop3完全分布式
  • 第十五届蓝桥杯C/C++组:宝石组合题目(从小学奥数到编程题详解)
  • 算法模型从入门到起飞系列——递归(探索自我重复的奇妙之旅)
  • C++内存分配方式
  • 数据结构-排序
  • 使用 request 的 axios 状态码分析
  • 市场热点复盘20240319
  • 数据结构Api
  • 泛微e9 流程表单使用 显示属性联动 实现某个字段的显示与隐藏
  • 【愚公系列】《高效使用DeepSeek》017-知识点思维导图生成
  • 危化品经营单位考试:心理调适与知识巩固双管齐下​
  • 头部颤抖的预防措施
  • win10 如何用我的笔记本 接网线 远程控制 台式机
  • OpenNJet动态API设置accessLog开关,颠覆传统运维工作模式
  • 孙磊已任中国常驻联合国副代表、特命全权大使
  • 青海西宁市城西区副区长于媛媛主动投案,接受审查调查
  • 习近平在上海考察
  • 马上评丨别让“免费领养”套路坑消费者又坑宠物
  • “麒麟王”亮相上海彩市,体彩即开票“瑞兽家族”迎来新成员
  • 第五届全国医院人文管理路演在昆山举办:患者体验才是温度计