diff --git a/folium/utilities.py b/folium/utilities.py index e9807ad91d..7bfdb9bdfb 100644 --- a/folium/utilities.py +++ b/folium/utilities.py @@ -273,6 +273,11 @@ def mercator(x): for j in range(nblayers): out[:, i, j] = np.interp(latslats, mercator(lats), array[:, i, j]) + # Keep integer images (e.g. uint8 RGBA) in their original dtype, otherwise + # write_png treats them as float data and rescales each channel. + if np.issubdtype(array.dtype, np.integer): + out = np.round(out).astype(array.dtype) + # Eventually flip the image. if origin == "upper": out = out[::-1, :, :] diff --git a/tests/test_raster_layers.py b/tests/test_raster_layers.py index 918568b3cb..bddc6c446a 100644 --- a/tests/test_raster_layers.py +++ b/tests/test_raster_layers.py @@ -4,6 +4,7 @@ """ +import numpy as np import pytest import xyzservices @@ -113,6 +114,16 @@ def test_image_overlay(): assert bounds == [[0, -180], [90, 180]], bounds +def test_image_overlay_mercator_project_keeps_uint8_colors(): + data = np.full((4, 3, 4), (100, 50, 200, 255), dtype="uint8") + bounds = [[40, 0], [50, 10]] + + plain = folium.raster_layers.ImageOverlay(data, bounds) + projected = folium.raster_layers.ImageOverlay(data, bounds, mercator_project=True) + + assert projected.url == plain.url + + @pytest.mark.parametrize( "tiles", ["CartoDB DarkMatter", xyzservices.providers.CartoDB.DarkMatter] ) diff --git a/tests/test_utilities.py b/tests/test_utilities.py index 26d346ca39..d7c81ce1b6 100644 --- a/tests/test_utilities.py +++ b/tests/test_utilities.py @@ -12,6 +12,7 @@ get_obj_in_upper_tree, if_pandas_df_convert_to_numpy, javascript_identifier_path_to_array_notation, + mercator_transform, normalize_bounds_type, parse_font_size, parse_options, @@ -171,6 +172,15 @@ def test_normalize_bounds_type(bounds, expected): assert normalize_bounds_type(bounds) == expected +def test_mercator_transform_keeps_integer_dtype(): + # A uint8 image must stay uint8, otherwise write_png treats the result as + # float data and stretches every channel to its maximum. + data = np.full((4, 3, 4), (100, 50, 200, 255), dtype="uint8") + out = mercator_transform(data, (40, 50)) + assert out.dtype == np.uint8 + np.testing.assert_array_equal(out, data) + + def test_camelize(): assert camelize("variable_name") == "variableName" assert camelize("variableName") == "variableName"