Switch to py-staticmaps

This commit is contained in:
Liam Steckler 2024-08-25 11:00:39 -07:00
parent aae40e22ad
commit 4aa7e32273
2 changed files with 40 additions and 68 deletions

View file

@ -1,20 +1,28 @@
appdirs==1.4.4
blurhash==1.1.4
certifi==2024.7.4
charset-normalizer==3.3.2
decorator==5.1.1
future==1.0.0
geographiclib==2.0
greenlet==3.0.3
idna==3.8
pip-install==1.3.5
Mastodon.py==1.8.1
numpy==2.1.0
pillow==10.4.0
pip-install==1.3.5
py-staticmaps==0.4.0
python-dateutil==2.9.0.post0
python-magic==0.4.27
python-slugify==8.0.4
PyYAML==6.0.2
requests==2.32.3
s2sphere==0.2.5
shapely==2.0.6
six==1.16.0
SQLAlchemy==2.0.32
staticmap==0.5.7
svgwrite==1.4.3
text-unidecode==1.3
typing_extensions==4.12.2
urllib3==2.2.2

98
scl.py
View file

@ -5,13 +5,13 @@ from typing import Optional
import mastodon
import requests
import shapely
import staticmaps
import yaml
from mastodon import Mastodon
from PIL import Image, ImageDraw, ImageFont
from PIL import Image, ImageDraw
from sqlalchemy import create_engine, select
from sqlalchemy.exc import NoResultFound
from sqlalchemy.orm import DeclarativeBase, Mapped, Session, mapped_column
from staticmap import CircleMarker, Polygon, StaticMap
from geospatial import convert_outage_geometry
@ -36,47 +36,6 @@ mastodon_client = Mastodon(
)
class AttribStaticMap(StaticMap, object):
def __init__(self, *args, **kwargs):
self.attribution = "© Stadia Maps © OpenMapTiles © OpenStreetMap"
super(AttribStaticMap, self).__init__(*args, **kwargs)
def _draw_features(self, image):
super(AttribStaticMap, self)._draw_features(image)
txt = Image.new("RGBA", image.size, (255, 255, 255, 0))
# get a font
# fnt = ImageFont.truetype('FreeMono.ttf', 12)
fnt = ImageFont.load_default()
# get a drawing context
d = ImageDraw.Draw(txt)
textSize = fnt.getbbox(self.attribution)
textPosition = (image.size[0] - textSize[2], image.size[1] - textSize[3])
offset = 2
options = {"fill": (255, 255, 255, 180)}
d.rectangle(
[
(textPosition[0] - (2 * offset), textPosition[1] - (2 * offset)),
(
textSize[2] + textPosition[0] + (2 * offset),
textSize[3] + textPosition[1] + (2 * offset),
),
],
**options,
)
# draw text, full opacity
d.text(
(textPosition[0] - offset, textPosition[1] - offset),
self.attribution,
font=fnt,
fill="black",
)
image.paste(txt, (0, 0), txt)
def classify_event_size(num_people: int) -> dict[str, str | bool]:
if num_people < 250:
return {
@ -98,6 +57,15 @@ def classify_event_size(num_people: int) -> dict[str, str | bool]:
}
# Only needed for workaround for https://github.com/flopp/py-staticmaps/issues/39
def textsize(self: ImageDraw.ImageDraw, *args, **kwargs):
x, y, w, h = self.textbbox((0, 0), *args, **kwargs)
return w, h
ImageDraw.ImageDraw.textsize = textsize
def get_hashtag_string(event) -> str:
city = str()
try:
@ -131,22 +99,28 @@ def do_initial_post(
# Fallback location from the SCL API in case one couldn't be reverse geocoded
area_text = event["city"]
try:
map = AttribStaticMap(
512,
512,
url_template="https://tiles.stadiamaps.com/tiles/outdoors/{z}/{x}/{y}.png?api_key="
+ stadiamaps_api_key,
context = staticmaps.Context()
tile_provider = staticmaps.TileProvider(
"stadia-outdoors",
"https://tiles.stadiamaps.com/tiles/outdoors/$z/$x/$y.png?api_key=$k",
shards=["a", "b", "c", "d"],
attribution="© Stadia Maps © OpenMapTiles © OpenStreetMap",
api_key=stadiamaps_api_key,
)
context.set_tile_provider(tile_provider)
assert event["polygons"]["type"] == "polygon"
for ring in event["polygons"]["rings"]:
polygon = Polygon(
ring,
# Appending 7F to the fill_color makes it 50% transparent
fill_color="{}7F".format(event_class["outage_color"]),
outline_color=event_class["outage_color"],
simplify=True,
context.add_object(
staticmaps.Area(
[staticmaps.create_latlng(lat, lon) for lon, lat in ring],
fill_color=staticmaps.parse_color(
"{}7F".format(event_class["outage_color"])
),
width=2,
color=staticmaps.parse_color(event_class["outage_color"]),
)
)
map.add_polygon(polygon)
try:
outage_center: shapely.Point = outage_geometries.centroid
@ -158,16 +132,6 @@ def do_initial_post(
# SE Corner
assert outage_center.y > 47.2 and outage_center.x < -122
marker_outline = CircleMarker(
(outage_center.x, outage_center.y), "white", 18
)
marker = CircleMarker(
(outage_center.x, outage_center.y), event_class["outage_color"], 12
)
map.add_marker(marker_outline)
map.add_marker(marker)
# Zoom level 17 ensures that we won't get any building/POI names, just street names
geocode_url = "{nominatim_url}/reverse?lat={lat}&lon={lon}&format=geocodejson&zoom=17".format(
nominatim_url=nominatim_url,
@ -227,10 +191,10 @@ def do_initial_post(
except Exception:
alt_text = "A map showing the location of the outage."
map_image = map.render()
map_image: Image = context.render_pillow(512, 512)
with io.BytesIO() as map_image_file:
map_image.save(map_image_file, format="PNG", optimize=True)
map_image.save(map_image_file, format="PNG")
map_media_post = mastodon_client.media_post(
map_image_file.getvalue(),
mime_type="image/png",