Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add local caching of tiles #23

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 40 additions & 3 deletions staticmap/staticmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import requests
from PIL import Image, ImageDraw
from pathlib import Path


class Line:
Expand Down Expand Up @@ -227,6 +228,9 @@ def __init__(self, width, height, padding_x=0, padding_y=0, url_template="http:/

self.delay_between_retries = delay_between_retries

self.cache_path = Path("~/.cache/staticmap").expanduser()
self.cache_path.mkdir(parents=True, exist_ok=True)

def add_line(self, line):
"""
:param line: line to draw
Expand Down Expand Up @@ -372,6 +376,23 @@ def _y_to_px(self, y):
px = (y - self.y_center) * self.tile_size + self.height / 2
return int(round(px))

def is_tile_cached(self, filename):
fn = self.cache_path / filename
if fn.exists():
print(fn, "exists")
return fn
return False

def cache_tile(self, filename, data):
fn = self.cache_path / filename
tile_image = Image.open(data).convert("RGBA")
tile_image.save(fn)

def draw_tile_on_image(self, image, box, data):
tile_image = Image.open(data).convert("RGBA")
image.paste(tile_image, box, tile_image)
return image

def _draw_base_layer(self, image):
"""
:type image: Image.Image
Expand All @@ -383,6 +404,7 @@ def _draw_base_layer(self, image):

# assemble all map tiles needed for the map
tiles = []
cached_tiles = []
for x in range(x_min, x_max):
for y in range(y_min, y_max):
# x and y may have crossed the date line
Expand All @@ -394,10 +416,23 @@ def _draw_base_layer(self, image):
tile_y = ((1 << self.zoom) - tile_y) - 1

url = self.url_template.format(z=self.zoom, x=tile_x, y=tile_y)
tiles.append((x, y, url))
filename = '_'.join(url.split("/")[2:])
if self.is_tile_cached(filename):
cached_tiles.append((x, y, filename))
else:
tiles.append((x, y, url))

thread_pool = ThreadPoolExecutor(4)

for x, y, filename in cached_tiles:
box = [
self._x_to_px(x),
self._y_to_px(y),
self._x_to_px(x + 1),
self._y_to_px(y + 1),
]
self.draw_tile_on_image(image, box, self.cache_path / filename)

for nb_retry in itertools.count():
if not tiles:
# no tiles left
Expand Down Expand Up @@ -427,14 +462,16 @@ def _draw_base_layer(self, image):
failed_tiles.append(tile)
continue

tile_image = Image.open(BytesIO(response.content)).convert("RGBA")
data = BytesIO(response.content)
filename = '_'.join(url.split("/")[2:])
self.cache_tile(filename, data)
box = [
self._x_to_px(x),
self._y_to_px(y),
self._x_to_px(x + 1),
self._y_to_px(y + 1),
]
image.paste(tile_image, box, tile_image)
image = self.draw_tile_on_image(image, box, data)

# put failed back into list of tiles to fetch in next try
tiles = failed_tiles
Expand Down