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