import io
|
import numpy as np
|
from PIL import Image
|
|
|
def load_image_any(source):
|
"""统一加载为 Pillow Image 对象,并返回原类型标记"""
|
if isinstance(source, Image.Image):
|
return source.convert("RGBA"), "image"
|
|
if isinstance(source, np.ndarray):
|
return Image.fromarray(source).convert("RGBA"), "ndarray"
|
|
if isinstance(source, bytes):
|
return Image.open(io.BytesIO(source)).convert("RGBA"), "bytes"
|
|
raise ValueError("不支持的图片输入类型")
|
|
def resize_and_crop_center_any(source, target_w, target_h):
|
img, src_type = load_image_any(source)
|
if img is None:
|
return None
|
|
src_w, src_h = img.size
|
target_ratio = target_w / target_h
|
src_ratio = src_w / src_h
|
|
# 计算缩放比例(保证一边刚好,另一边多出来)
|
if src_ratio > target_ratio:
|
scale = target_h / src_h # 按高度匹配
|
else:
|
scale = target_w / src_w # 按宽度匹配
|
|
new_w = int(src_w * scale)
|
new_h = int(src_h * scale)
|
img_resized = img.resize((new_w, new_h), Image.LANCZOS)
|
|
# 居中裁剪
|
left = max((new_w - target_w) / 2, 0)
|
top = max((new_h - target_h) / 2, 0)
|
right = left + target_w
|
bottom = top + target_h
|
img_cropped = img_resized.crop((left, top, right, bottom))
|
|
# 返回与原输入一致的类型
|
if src_type == "image":
|
return img_cropped
|
elif src_type == "bytes":
|
buf = io.BytesIO()
|
img_cropped.save(buf, format="PNG")
|
return buf.getvalue()
|
elif src_type == "ndarray":
|
return np.array(img_cropped)
|
else:
|
return img_cropped # 兜底,返回 Pillow Image
|