From 2965af668a76b48ee499ef91b99c93c62074f71d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cain=C3=A3?= <51023074+rupestre-campos@users.noreply.github.com> Date: Tue, 9 Apr 2024 09:42:43 -0300 Subject: [PATCH] pixelated images when needed (#176) * pixelated images when needed * black formatted --- .gitignore | 2 +- examples/pages/image_overlay.py | 46 +++++++++++++++++++++++++ streamlit_folium/__init__.py | 5 +++ streamlit_folium/frontend/src/index.tsx | 29 ++++++++++++++++ 4 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 examples/pages/image_overlay.py diff --git a/.gitignore b/.gitignore index c3d003d..5f3f1e7 100644 --- a/.gitignore +++ b/.gitignore @@ -77,5 +77,5 @@ package-lock.json .envrc .streamlit/ - +.venv/ test-results.xml \ No newline at end of file diff --git a/examples/pages/image_overlay.py b/examples/pages/image_overlay.py new file mode 100644 index 0000000..6d31049 --- /dev/null +++ b/examples/pages/image_overlay.py @@ -0,0 +1,46 @@ +import folium +import streamlit as st + +from streamlit_folium import st_folium + +st.set_page_config( + layout="wide", + page_title="streamlit-folium documentation: Misc Examples", + page_icon="random", +) +""" +# streamlit-folium: Image Overlay + +By default, st_folium renders images using browser image rendering mechanism. +Use st_folium(map, pixelated=True) in order to see image pixels without resample. +""" + +url_image = "https://i.postimg.cc/kG2FSxSR/image.png" +image_bounds = [[-20.664910, -46.538223], [-20.660001, -46.532977]] + +m = folium.Map() +m1 = folium.Map() + +folium.raster_layers.ImageOverlay( + image=url_image, + name="image overlay", + opacity=1, + bounds=image_bounds, +).add_to(m) +folium.raster_layers.ImageOverlay( + image=url_image, + name="image overlay", + opacity=1, + bounds=image_bounds, +).add_to(m1) + +m.fit_bounds(image_bounds, padding=(0, 0)) +m1.fit_bounds(image_bounds, padding=(0, 0)) + +col1, col2 = st.columns(2) +with col1: + st.markdown("## Pixelated off") + st_folium(m, use_container_width=True, pixelated=False, key="pixelated_off") +with col2: + st.markdown("## Pixelated on") + st_folium(m1, use_container_width=True, pixelated=True, key="pixelated_on") diff --git a/streamlit_folium/__init__.py b/streamlit_folium/__init__.py index b7f46c6..bb6150e 100644 --- a/streamlit_folium/__init__.py +++ b/streamlit_folium/__init__.py @@ -209,6 +209,7 @@ def st_folium( return_on_hover: bool = False, use_container_width: bool = False, layer_control: folium.LayerControl | None = None, + pixelated: bool = False, debug: bool = False, ): """Display a Folium object in Streamlit, returning data as user interacts @@ -251,6 +252,9 @@ def st_folium( layer_control: folium.LayerControl or None If you want to have layer control for dynamically added layers, you can pass the layer control here. + pixelated: bool + If True, add CSS rules to render image crisp pixels which gives a pixelated + result instead of a blurred image. debug: bool If True, print out the html and javascript code used to render the map with st.code @@ -376,6 +380,7 @@ def bounds_to_dict(bounds_list: list[list[float]]) -> dict[str, dict[str, float] feature_group=feature_group_string, return_on_hover=return_on_hover, layer_control=layer_control_string, + pixelated=pixelated, ) return component_value diff --git a/streamlit_folium/frontend/src/index.tsx b/streamlit_folium/frontend/src/index.tsx index 0da2d80..7d12138 100644 --- a/streamlit_folium/frontend/src/index.tsx +++ b/streamlit_folium/frontend/src/index.tsx @@ -144,6 +144,29 @@ function onLayerClick(e: any) { debouncedUpdateComponentValue(window.map) } +function getPixelatedStyles(pixelated: boolean) { + if (pixelated) { + const styles = ` + .leaflet-image-layer { + /* old android/safari*/ + image-rendering: -webkit-optimize-contrast; + image-rendering: crisp-edges; /* safari */ + image-rendering: pixelated; /* chrome */ + image-rendering: -moz-crisp-edges; /* firefox */ + image-rendering: -o-crisp-edges; /* opera */ + -ms-interpolation-mode: nearest-neighbor; /* ie */ + } + ` + return styles + } + const styles = ` + .leaflet-image-layer { + } + ` + return styles + +} + window.initComponent = (map: any, return_on_hover: boolean) => { map.on("click", onMapClick) map.on("moveend", onMapMove) @@ -182,6 +205,7 @@ function onRender(event: Event): void { const feature_group: string = data.args["feature_group"] const return_on_hover: boolean = data.args["return_on_hover"] const layer_control: string = data.args["layer_control"] + const pixelated: boolean = data.args["pixelated"] if (!window.map) { // Only run this if the map hasn't already been created (and thus the global @@ -241,6 +265,11 @@ function onRender(event: Event): void { const html_div = document.createElement("div") html_div.innerHTML = html document.body.appendChild(html_div) + const styles = getPixelatedStyles(pixelated) + var styleSheet = document.createElement("style") + styleSheet.innerText = styles + document.head.appendChild(styleSheet) + } }