|
16 | 16 | # You should have received a copy of the GNU General Public License |
17 | 17 | # along with this program. If not, see <https://www.gnu.org/licenses/>. |
18 | 18 |
|
| 19 | +import copy |
19 | 20 | import os |
20 | 21 | import queue |
21 | 22 | import sys |
@@ -62,6 +63,13 @@ def __init__(self, com_port: str = "AUTO", display_width: int = 320, display_hei |
62 | 63 | # mixed with other requests in-between |
63 | 64 | self.update_queue_mutex = threading.Lock() |
64 | 65 |
|
| 66 | + # Create a cache to store opened images, to avoid opening and loading from the filesystem every time |
| 67 | + self.image_cache = {} # { key=path, value=PIL.Image } |
| 68 | + |
| 69 | + # Create a cache to store opened fonts, to avoid opening and loading from the filesystem every time |
| 70 | + self.font_cache = {} # { key=(font, size), value=PIL.ImageFont } |
| 71 | + |
| 72 | + |
65 | 73 | def get_width(self) -> int: |
66 | 74 | if self.orientation == Orientation.PORTRAIT or self.orientation == Orientation.REVERSE_PORTRAIT: |
67 | 75 | return self.display_width |
@@ -194,7 +202,7 @@ def DisplayPILImage( |
194 | 202 | pass |
195 | 203 |
|
196 | 204 | def DisplayBitmap(self, bitmap_path: str, x: int = 0, y: int = 0, width: int = 0, height: int = 0): |
197 | | - image = Image.open(bitmap_path) |
| 205 | + image = self.open_image(bitmap_path) |
198 | 206 | self.DisplayPILImage(image, x, y, width, height) |
199 | 207 |
|
200 | 208 | def DisplayText( |
@@ -235,10 +243,12 @@ def DisplayText( |
235 | 243 | ) |
236 | 244 | else: |
237 | 245 | # The text bitmap is created from provided background image : text with transparent background |
238 | | - text_image = Image.open(background_image) |
| 246 | + text_image = self.open_image(background_image) |
239 | 247 |
|
240 | 248 | # Get text bounding box |
241 | | - font = ImageFont.truetype("./res/fonts/" + font, font_size) |
| 249 | + if (font, font_size) not in self.font_cache: |
| 250 | + self.font_cache[(font, font_size)] = ImageFont.truetype("./res/fonts/" + font, font_size) |
| 251 | + font = self.font_cache[(font, font_size)] |
242 | 252 | d = ImageDraw.Draw(text_image) |
243 | 253 | left, top, right, bottom = d.textbbox((x, y), text, font=font, align=align, anchor=anchor) |
244 | 254 |
|
@@ -294,7 +304,7 @@ def DisplayProgressBar(self, x: int, y: int, width: int, height: int, min_value: |
294 | 304 | bar_image = Image.new('RGB', (width, height), background_color) |
295 | 305 | else: |
296 | 306 | # A bitmap is created from provided background image |
297 | | - bar_image = Image.open(background_image) |
| 307 | + bar_image = self.open_image(background_image) |
298 | 308 |
|
299 | 309 | # Crop bitmap to keep only the progress bar background |
300 | 310 | bar_image = bar_image.crop(box=(x, y, x + width, y + height)) |
@@ -372,7 +382,7 @@ def DisplayRadialProgressBar(self, xc: int, yc: int, radius: int, bar_width: int |
372 | 382 | bar_image = Image.new('RGB', (diameter, diameter), background_color) |
373 | 383 | else: |
374 | 384 | # A bitmap is created from provided background image |
375 | | - bar_image = Image.open(background_image) |
| 385 | + bar_image = self.open_image(background_image) |
376 | 386 |
|
377 | 387 | # Crop bitmap to keep only the progress bar background |
378 | 388 | bar_image = bar_image.crop(box=bbox) |
@@ -464,3 +474,10 @@ def DisplayRadialProgressBar(self, xc: int, yc: int, radius: int, bar_width: int |
464 | 474 | font=font, fill=font_color) |
465 | 475 |
|
466 | 476 | self.DisplayPILImage(bar_image, xc - radius, yc - radius) |
| 477 | + |
| 478 | + # Load image from the filesystem, or get from the cache if it has already been loaded previously |
| 479 | + def open_image(self, bitmap_path: str) -> Image: |
| 480 | + if bitmap_path not in self.image_cache: |
| 481 | + logger.debug("Bitmap " + bitmap_path + " is now loaded in the cache") |
| 482 | + self.image_cache[bitmap_path] = Image.open(bitmap_path) |
| 483 | + return copy.copy(self.image_cache[bitmap_path]) |
0 commit comments