11import os
22import io
3- import requests
43
54from flask import Flask
65from PIL import Image , ImageDraw , ImageFont , ImageChops
6+ from concurrent .futures import ThreadPoolExecutor , as_completed
77from math import ceil
88
9- from .utils import valid_platforms
9+ from .s3 import download_asset
10+ from .utils import valid_platforms , plat_dimensions
1011
1112parent_app = None
1213
@@ -69,16 +70,33 @@ def preferred_grouping(platforms):
6970 if len (selection ) == len (selection & platforms ):
7071 return selection
7172
72- def load_image_from_url ( url , fallback ):
73+ def load_image_from_id ( id , fallback ):
7374 try :
74- resp = requests . get ( url , timeout = 5 )
75- resp . raise_for_status ( )
76- return Image .open (io . BytesIO ( resp . content ) ).convert ("RGBA" )
75+ file = io . BytesIO ( )
76+ download_asset ( id , file )
77+ return Image .open (file ).convert ("RGBA" )
7778 except Exception as e :
7879 if fallback :
7980 return fallback
8081 raise e
8182
83+ def load_images_parallel (ids_with_fallbacks ):
84+ output = {}
85+ with ThreadPoolExecutor (max_workers = 5 ) as executor :
86+ future_to_key = {
87+ executor .submit (load_image_from_id , id , fallback ): key
88+ for key , (id , fallback ) in ids_with_fallbacks .items ()
89+ }
90+
91+ for future in as_completed (future_to_key ):
92+ key = future_to_key [future ]
93+ try :
94+ output [key ] = future .result ()
95+ except Exception as e :
96+ output [key ] = None
97+
98+ return output
99+
82100def draw_text_ellipsized (draw , text , font , xy , max_width ):
83101 if draw .textlength (text , font = font ) <= max_width :
84102 draw .text (xy , text , font = font , fill = text_color )
@@ -96,17 +114,17 @@ def draw_text_ellipsized(draw, text, font, xy, max_width):
96114
97115 draw .text (xy , trimmed + ellipsis , font = font , fill = text_color )
98116
99- def platform_image_in_border (canvas , image_url , top_left , platform ):
117+ def platform_image_in_border (canvas , image , top_left , platform ):
100118 border = platform_borders [platform ]
101- img = load_image_from_url ( image_url , border [ 'fallback' ] )
119+ image = image . resize ( plat_dimensions [ platform ], resample = Image . NEAREST )
102120
103121 if platform == 'chalk' :
104- img .putalpha (chalk_mask )
122+ image .putalpha (chalk_mask )
105123
106124 ix = top_left [0 ] + border ['offset' ][0 ]
107125 iy = top_left [1 ] + border ['offset' ][1 ]
108126
109- canvas .alpha_composite (img , (ix , iy ))
127+ canvas .alpha_composite (image , (ix , iy ))
110128
111129 canvas .alpha_composite (border ['image' ], top_left )
112130
@@ -117,10 +135,20 @@ def generate_preview_image(title, developer, icon, screenshots):
117135 platforms = preferred_grouping (screenshots .keys ())
118136 start_x = ceil ((canvas .width - sum (platform_borders [platform ]['image' ].width for platform in platforms )) / 2 )
119137
138+ image_ids = {}
139+
140+ if icon :
141+ image_ids ['icon' ] = (icon , None )
142+
143+ for platform in platforms :
144+ image_ids [platform ] = (screenshots [platform ], platform_borders [platform ]['fallback' ])
145+
146+ loaded_images = load_images_parallel (image_ids )
147+
120148 for platform in platforms :
121149 platform_image_in_border (
122150 canvas = canvas ,
123- image_url = screenshots [platform ],
151+ image = loaded_images [platform ],
124152 top_left = (start_x , 0 ),
125153 platform = platform
126154 )
@@ -130,13 +158,10 @@ def generate_preview_image(title, developer, icon, screenshots):
130158 author_position = base_author_position
131159 text_space = base_text_space
132160
133- icon_image = None
134- try :
135- icon_image = load_image_from_url (icon , None )
136- except Exception as e :
137- icon_image = None
161+ icon_image = loaded_images ['icon' ] if 'icon' in loaded_images else None
138162
139163 if icon_image :
164+ icon_image = icon_image .resize ((80 ,80 ))
140165 icon_image .putalpha (ImageChops .multiply (icon_mask , icon_image .split ()[3 ]))
141166 canvas .alpha_composite (icon_image , icon_position )
142167 title_position = (title_position [0 ] + 88 , title_position [1 ])
0 commit comments