File size: 6,334 Bytes
bac55b4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
from PIL import Image, ImageDraw, ImageFont
from io import BytesIO

# カード画像関連
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'
}

# カード画像各領域のピクセル位置情報
# 写真
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_LT_XY = (65, 45) 
TITLE_RB_XY = (647, 132) # マーク挿入部分と重ならないような位置
TITLE_SIZE = (TITLE_RB_XY[0] - TITLE_LT_XY[0], TITLE_RB_XY[1] - TITLE_LT_XY[1])

# 説明欄区切り線
DESCRIPTION_LINE_L_XY = (52, 1024)
DESCRIPTION_LINE_R_XY = (816, 1024)

# 史跡種類
HS_TYPE_LT_XY = (56, 972)

# 訪問難度
DIFFICULTY_LT_XY = (444, 972)

# 説明文本体
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_selif_path = 'data/fonts/SourceHanSerif-Bold.otf'
# ゴシック体
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):

    # 画像の読み込みとトリミング
    picture_img = Image.open(img_bytearray)
    picture_img = crop_max_square(picture_img)
    picture_img = picture_img.resize(PICTURE_SIZE)


    # カードの読み込み
    card_img = Image.open(card_frame_path_dict[option_dict['色']])

    # マークの追加
    mark_image = Image.open(card_mark_path_dict[option_dict['マーク']])
    card_img.paste(mark_image, mask=mark_image)

    # 写真の埋め込み
    card_img.paste(picture_img, PICTURE_LT_XY)

    # 各種書き込み準備
    card_imgdraw = ImageDraw.Draw(card_img)

    # カード枠線の追加
    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)

    # 説明欄区切り線の追加
    card_imgdraw.line((DESCRIPTION_LINE_L_XY, DESCRIPTION_LINE_R_XY), fill='black', width=3)

    # タイトル埋め込み
    # (複数行対応は必要ならば対応)
    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')

    # 史跡種類埋め込み
    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')

    # 訪問難度埋め込み
    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')

    # 説明文埋め込み
    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)

    # バイナリデータの出力
    output_img_bytearray = BytesIO()
    card_img.convert('RGB').save(output_img_bytearray, "JPEG", quality=95)
    output_img_bytearray.seek(0) # 画像の先頭にシークしないと空データになってしまう。

    return output_img_bytearray