wangzhibo
2025-08-04 f5106b912f1261fe633aa6bcdf10a4b7e74345aa
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
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