3dmodelmaker / src /front_card_image_historic_site.py
ikeda
add 'No Designation' to mark_list(list of designation type ex. Country, City etc.) and skip mark paste process if mark is 'No Designation'
1c5bad2
raw
history blame
6.48 kB
from PIL import Image, ImageDraw, ImageFont
from io import BytesIO
# Card image information
# Historic Site Card files
card_frame_path_dict = {
'橙': 'data/cards/史跡カードフレーム(橙).png',
'白': 'data/cards/史跡カードフレーム(白).png',
'紫': 'data/cards/史跡カードフレーム(紫).png',
'緑': 'data/cards/史跡カードフレーム(緑).png',
'茶': 'data/cards/史跡カードフレーム(茶).png',
'赤': 'data/cards/史跡カードフレーム(赤).png',
'青': 'data/cards/史跡カードフレーム(青).png',
'黄': 'data/cards/史跡カードフレーム(黄).png',
'黒': 'data/cards/史跡カードフレーム(黒).png'
}
card_mark_path_dict = {
'区指定': 'data/cards/史跡カード指定マーク(区指定).png',
'国指定': 'data/cards/史跡カード指定マーク(国指定).png',
'市指定': 'data/cards/史跡カード指定マーク(市指定).png',
'府指定': 'data/cards/史跡カード指定マーク(府指定).png',
'村指定': 'data/cards/史跡カード指定マーク(村指定).png',
'町指定': 'data/cards/史跡カード指定マーク(町指定).png',
'県指定': 'data/cards/史跡カード指定マーク(県指定).png',
'道指定': 'data/cards/史跡カード指定マーク(道指定).png',
'都指定': 'data/cards/史跡カード指定マーク(都指定).png'
}
# Pixel position information for each area of the card image
# Picture
PICTURE_LT_XY = (65, 188)
PICTURE_RB_XY = (802, 925)
PICTURE_SIZE = (PICTURE_RB_XY[0] - PICTURE_LT_XY[0], PICTURE_RB_XY[1] - PICTURE_LT_XY[1])
# Title
# Create some margin
TITLE_LT_XY = (65, 45)
TITLE_RB_XY = (647, 132) # Position to avoid overlapping with the marker insertion point
TITLE_SIZE = (TITLE_RB_XY[0] - TITLE_LT_XY[0], TITLE_RB_XY[1] - TITLE_LT_XY[1])
# Explanation Section Divider
DESCRIPTION_LINE_L_XY = (52, 1024)
DESCRIPTION_LINE_R_XY = (816, 1024)
# Historic Site Type
HS_TYPE_LT_XY = (56, 972)
# Difficulty of Visit
DIFFICULTY_LT_XY = (444, 972)
# Main Body of Description
DESCRIPTION_LT_XY = (46, 1024)
DESCRIPTION_RB_XY = (810, 1174)
DESCRIPTION_SIZE = (DESCRIPTION_RB_XY[0] - DESCRIPTION_LT_XY[0], DESCRIPTION_RB_XY[1] - DESCRIPTION_LT_XY[1])
# Font information
# Ming Typeface
font_selif_path = 'data/fonts/SourceHanSerif-Bold.otf'
# Gothic Typeface
font_sanselif_path = 'data/fonts/SourceHanSans-Bold.otf'
def crop_center(pil_img, crop_width, crop_height):
img_width, img_height = pil_img.size
return pil_img.crop(((img_width - crop_width) // 2,
(img_height - crop_height) // 2,
(img_width + crop_width) // 2,
(img_height + crop_height) // 2))
def crop_max_square(pil_img):
return crop_center(pil_img, min(pil_img.size), min(pil_img.size))
def create_historic_site_card_image(img_bytearray, option_dict):
# Loading and Cropping of Picture
picture_img = Image.open(img_bytearray)
picture_img = crop_max_square(picture_img)
picture_img = picture_img.resize(PICTURE_SIZE)
# Loading of Card Frame
card_img = Image.open(card_frame_path_dict[option_dict['色']])
# Adding a Marker
if option_dict['マーク'] in card_mark_path_dict:
mark_image = Image.open(card_mark_path_dict[option_dict['マーク']])
card_img.paste(mark_image, mask=mark_image)
# Embedding a Picture in the Card
card_img.paste(picture_img, PICTURE_LT_XY)
# Preparing for editting the card image
card_imgdraw = ImageDraw.Draw(card_img)
# Adding a Border to the Card
card_imgdraw.line(( (0, 0), (card_img.size[0], 0) ), fill='black', width=15)
card_imgdraw.line(( (0, 0), (0, card_img.size[1]) ), fill='black', width=15)
card_imgdraw.line(( (card_img.size[0], 0), card_img.size), fill='black', width=15)
card_imgdraw.line(( (0, card_img.size[1]), card_img.size), fill='black', width=15)
# Adding a Divider Line to the Explanation Section
card_imgdraw.line((DESCRIPTION_LINE_L_XY, DESCRIPTION_LINE_R_XY), fill='black', width=3)
# Embedding the Title
# (Support for multiple lines if needed)
title_font_size = 100
while True:
title_font = ImageFont.truetype(font_selif_path, title_font_size)
title_bbox = card_imgdraw.textbbox(TITLE_LT_XY , option_dict['タイトル'], title_font)
if (title_bbox[2] <= TITLE_RB_XY[0] and title_bbox[3] <= TITLE_RB_XY[1]) or title_font_size <= 30:
break
title_font_size -= 1
card_imgdraw.text((TITLE_LT_XY[0], int((TITLE_LT_XY[1] + TITLE_RB_XY[1]) / 2)), option_dict['タイトル'], fill='black', font=title_font, anchor='lm')
# Embedding the Historic Site Type
hs_type_display = f'種類:{option_dict["史跡種類"]}'
hs_typefont = ImageFont.truetype(font_sanselif_path, 40)
card_imgdraw.text(HS_TYPE_LT_XY, hs_type_display, fill='black', font=hs_typefont, anchor='lt')
# Embedding the Difficulty of Visit
difficulty = int(option_dict['訪問難度'])
difficulty = 1 if difficulty < 1 else 5 if difficulty > 5 else difficulty
difficulty_display = '訪問難度:' + '☆' * difficulty + '★' * (5 - difficulty)
difficulty_font = ImageFont.truetype(font_sanselif_path, 40)
card_imgdraw.text(DIFFICULTY_LT_XY, difficulty_display, fill='black', font=difficulty_font, anchor='lt')
# Embedding the Description Text
description_font = ImageFont.truetype(font_sanselif_path, 40)
description_list = []
description_length = len(option_dict['説明文'])
temp_start = 0
for i in range(description_length):
temp_end = i
description_line_bbox = card_imgdraw.textbbox((0, 0), option_dict['説明文'][temp_start:temp_end+1], description_font)
if description_line_bbox[2] > DESCRIPTION_SIZE[0]:
description_list.append(option_dict['説明文'][temp_start:temp_end])
temp_start = i
description_list.append(option_dict['説明文'][temp_start:])
description_display = '\n'.join(description_list)
card_imgdraw.text(DESCRIPTION_LT_XY, description_display, fill='black', font=description_font)
# Outputting Binary Data
output_img_bytearray = BytesIO()
card_img.convert('RGB').save(output_img_bytearray, "JPEG", quality=95)
output_img_bytearray.seek(0) # Seek to the beginning of the image, otherwise it results in empty data
return output_img_bytearray