From f29a7b646c2809e376e4b6dbb3295c69b2388cb7 Mon Sep 17 00:00:00 2001 From: tcmofashi Date: Wed, 5 Mar 2025 19:19:34 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=8E=8B=E7=BC=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/chat/utils_image.py | 71 ++++++++++++++++++++++++++++++- src/plugins/models/utils_model.py | 2 +- 2 files changed, 71 insertions(+), 2 deletions(-) diff --git a/src/plugins/chat/utils_image.py b/src/plugins/chat/utils_image.py index efe2f1c9..cd6b9819 100644 --- a/src/plugins/chat/utils_image.py +++ b/src/plugins/chat/utils_image.py @@ -255,4 +255,73 @@ def compress_base64_image_by_scale(base64_data: str, scale: float = 0.5) -> str: print(f"\033[1;31m[错误]\033[0m 压缩图片失败: {str(e)}") import traceback print(traceback.format_exc()) - return base64_data \ No newline at end of file + return base64_data + +async def compress_image( image_path: str, target_size: int = 0.8 * 1024 * 1024): + """压缩图片并返回base64编码 + Args: + image_path: 图片文件路径 + target_size: 目标文件大小(字节),默认0.8MB + Returns: + Optional[str]: 成功返回base64编码的图片数据,失败返回None + """ + try: + file_size = os.path.getsize(image_path) + if file_size <= target_size: + # 如果文件已经小于目标大小,直接读取并返回base64 + with open(image_path, 'rb') as f: + return base64.b64encode(f.read()).decode('utf-8') + + # 打开图片 + with Image.open(image_path) as img: + # 获取原始尺寸 + original_width, original_height = img.size + + # 计算缩放比例 + scale = min(1.0, (target_size / file_size) ** 0.5) + + # 计算新的尺寸 + new_width = int(original_width * scale) + new_height = int(original_height * scale) + + # 创建内存缓冲区 + output_buffer = io.BytesIO() + + # 如果是GIF,处理所有帧 + if getattr(img, "is_animated", False): + frames = [] + for frame_idx in range(img.n_frames): + img.seek(frame_idx) + new_frame = img.copy() + new_frame = new_frame.resize((new_width, new_height), Image.Resampling.LANCZOS) + frames.append(new_frame) + + # 保存到缓冲区 + frames[0].save( + output_buffer, + format='GIF', + save_all=True, + append_images=frames[1:], + optimize=True, + duration=img.info.get('duration', 100), + loop=img.info.get('loop', 0) + ) + else: + # 处理静态图片 + resized_img = img.resize((new_width, new_height), Image.Resampling.LANCZOS) + + # 保存到缓冲区,保持原始格式 + if img.format == 'PNG' and img.mode in ('RGBA', 'LA'): + resized_img.save(output_buffer, format='PNG', optimize=True) + else: + resized_img.save(output_buffer, format='JPEG', quality=95, optimize=True) + + # 获取压缩后的数据并转换为base64 + compressed_data = output_buffer.getvalue() + print(f"\033[1;32m[成功]\033[0m 压缩图片: {os.path.basename(image_path)} ({original_width}x{original_height} -> {new_width}x{new_height})") + + return base64.b64encode(compressed_data).decode('utf-8') + + except Exception as e: + print(f"\033[1;31m[错误]\033[0m 压缩图片失败: {os.path.basename(image_path)}, 错误: {str(e)}") + return None \ No newline at end of file diff --git a/src/plugins/models/utils_model.py b/src/plugins/models/utils_model.py index 3ba873d7..261fe88d 100644 --- a/src/plugins/models/utils_model.py +++ b/src/plugins/models/utils_model.py @@ -7,7 +7,7 @@ from typing import Tuple, Union from nonebot import get_driver from loguru import logger from ..chat.config import global_config -from ..chat.utils_image import compress_base64_image_by_scale +from ..chat.utils_image import compress_base64_image_by_scale,compress_image driver = get_driver() config = driver.config