2025-07-21 18:47:59 +08:00

92 lines
4.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import os
from PIL import Image, ImageDraw, ImageFile, ImageFont
class PicItem:
def __init__(self, pic: ImageFile, label: str):
self.pic = pic
self.label = label
class PictureMatrixGenerater():
def __init__(self, background: str, picSize: tuple, itemSize: tuple, margin: int, itemNum: int, fontMargin: int, font: str, fontSize: int):
self.backImage = Image.open(background)
self.picSize = picSize
self.itemSize = itemSize
self.margin = margin
self.itemNum = itemNum
self.fontSize = fontSize
self.fontMargin = fontMargin
self.actualSize = (itemSize[0], itemSize[1] + fontMargin + int(fontSize * 1.5))
self.font = ImageFont.truetype(font, fontSize)
def cutPic(self, img: ImageFile) -> Image:
# 等比放小50%
img = img.resize((int(img.width * 0.5), int(img.height * 0.5)))
left = (img.width - self.itemSize[0])/2
top = (img.height - self.itemSize[1])/2
right = (img.width + self.itemSize[0])/2
bottom = (img.height + self.itemSize[1])/2
return img.crop((left, top, right, bottom))
def drawComponent(self, pic: ImageFile, text: str, startX: int = 0, startY: int = 0) -> Image:
components = Image.new('RGBA', self.actualSize, color=(0, 0, 0, 0))
components.paste(self.cutPic(pic), (0, 0))
draw = ImageDraw.Draw(components)
text_bbox = draw.textbbox((0, 0), text, font=self.font)
# 计算文本宽度(文本框实际宽度)
text_width = text_bbox[2] - text_bbox[0]
# 计算文本居中
item_center_x = (startX + (self.itemSize[0] / 2))
text_y = startY + self.itemSize[1] + self.fontMargin
draw.text((item_center_x - (text_width / 2), text_y), text, fill=(255, 255, 255), font=self.font)
return components
def generate(self, picList: list[PicItem]) -> Image:
backImage = Image.new('RGB', self.picSize, color=(255, 255, 255))
backImage.paste(self.backImage, (0, 0))
num: int = len(picList)
# 计算某行的实际宽度
vSize = num * (self.actualSize[0] + num - 1) if num <= 5 else 5 * (self.actualSize[0] + num - 1)
# 计算左右边距以确保当前行居中展示
mSize = (self.picSize[0] - vSize) / 2 - self.margin * 2
# 如果只有一行则计算居中如果两行则设置为200
marginTop = int(self.picSize[1] / 2) - int(self.itemSize[1] / 2) if num <= 5 else 200
nextYStart = marginTop + self.actualSize[1] + 50 if num > 5 else -1
nextViewSize = (num % 5) * (self.itemSize[0] + num - 1) if num < 10 else 5 * (self.itemSize[0] + num - 1)
nextMarginSize = (self.picSize[0] - nextViewSize) / 2 - self.margin * 2
for idx, img in enumerate(picList):
calc_X = int((self.itemSize[0] + self.margin) * idx + mSize) if idx < 5 else int((self.itemSize[0] + self.margin) * (idx % 5) + nextMarginSize)
calc_Y = marginTop if idx < 5 else nextYStart
# print((calc_X, calc_Y))
component = self.drawComponent(img.pic, img.label, 0, 0)
backImage.paste(component, (calc_X, calc_Y), mask=component)
return backImage
def config(self, picSize: tuple, itemSize: tuple, margin: int, itemNum: int, fontMargin: int, font: str, fontSize: int):
self.picSize = picSize
self.itemSize = itemSize
self.margin = margin
self.itemNum = itemNum
self.fontSize = fontSize
self.fontMargin = fontMargin
self.actualSize = (itemSize[0], itemSize[1] + fontMargin + int(fontSize * 1.5))
self.font = ImageFont.truetype(font, fontSize)
generator = PictureMatrixGenerater(
background="./pic/background.jpg",
picSize=(1920, 1080),
itemSize=(320, 320),
margin=50,
itemNum=10,
fontMargin=20,
font="./font/HarmonyOS_Sans_SC_Medium.ttf",
fontSize=26
)
picList = [PicItem(Image.open('./sucai/' + i), i) for i in os.listdir("./sucai/")]
print(picList)
Sol = generator.generate(picList)
# 写入结果
with open('./finalc.png', 'wb') as f:
Sol.save(f)