75 lines
2.7 KiB
Python
75 lines
2.7 KiB
Python
from PIL import Image
|
|
import os
|
|
from config import Config
|
|
from logger import logger
|
|
|
|
class ImageProcessor:
|
|
# 格式映射:将常见的小写格式名转换为 Pillow 可识别的格式名
|
|
FORMAT_MAP = {
|
|
'jpg': 'JPEG',
|
|
'jpeg': 'JPEG',
|
|
'png': 'PNG',
|
|
'webp': 'WEBP',
|
|
'gif': 'GIF',
|
|
'bmp': 'BMP',
|
|
'tiff': 'TIFF',
|
|
}
|
|
|
|
@staticmethod
|
|
def resize_by_ratio(img, ratio_width, ratio_height):
|
|
"""等比例缩放至目标比例(最长边适配)"""
|
|
w, h = img.size
|
|
target_ratio = ratio_width / ratio_height
|
|
current_ratio = w / h
|
|
if current_ratio > target_ratio:
|
|
new_w = int(h * target_ratio)
|
|
new_h = h
|
|
else:
|
|
new_w = w
|
|
new_h = int(w / target_ratio)
|
|
return img.resize((new_w, new_h), Image.Resampling.LANCZOS)
|
|
|
|
@staticmethod
|
|
def resize_by_pixel(img, target_width, target_height):
|
|
"""等比例缩放至不超过目标像素(保持比例,以较长边为准)"""
|
|
w, h = img.size
|
|
ratio_w = target_width / w
|
|
ratio_h = target_height / h
|
|
ratio = min(ratio_w, ratio_h)
|
|
new_w = int(w * ratio)
|
|
new_h = int(h * ratio)
|
|
return img.resize((new_w, new_h), Image.Resampling.LANCZOS)
|
|
|
|
@staticmethod
|
|
def convert_image(input_path, output_path, target_format, quality=None):
|
|
"""
|
|
转换图片格式
|
|
target_format: 小写字符串,如 'jpg', 'png', 'webp'
|
|
"""
|
|
try:
|
|
with Image.open(input_path) as img:
|
|
# 获取 Pillow 标准格式名
|
|
pillow_format = ImageProcessor.FORMAT_MAP.get(target_format.lower())
|
|
if pillow_format is None:
|
|
logger.error(f"不支持的输出格式: {target_format}")
|
|
return False
|
|
|
|
# 对于 JPEG 格式,需要处理透明通道
|
|
if pillow_format == 'JPEG' and img.mode in ('RGBA', 'P'):
|
|
rgb_img = Image.new('RGB', img.size, (255, 255, 255))
|
|
rgb_img.paste(img, mask=img.split()[-1] if img.mode == 'RGBA' else None)
|
|
img = rgb_img
|
|
|
|
save_kwargs = {}
|
|
if pillow_format in ('JPEG', 'WEBP'):
|
|
save_kwargs['quality'] = quality if quality is not None else Config.DEFAULT_QUALITY
|
|
elif pillow_format == 'PNG':
|
|
save_kwargs['compress_level'] = 6
|
|
|
|
img.save(output_path, format=pillow_format, **save_kwargs)
|
|
logger.info(f"转换成功: {input_path} -> {output_path}")
|
|
return True
|
|
except Exception as e:
|
|
logger.error(f"转换失败 {input_path}: {e}")
|
|
return False
|