1+ """Exporter for Google Earth Engine (GEE)."""
2+
3+ from typing import Any , Dict , Optional
4+
5+ from palettize .core import Colormap , ScalingFunction
6+ from ._base import BaseExporter
7+
8+
9+ class GEEExporter (BaseExporter ):
10+ """
11+ Exporter for Google Earth Engine JavaScript code snippets.
12+ """
13+
14+ @property
15+ def identifier (self ) -> str :
16+ return "gee"
17+
18+ @property
19+ def name (self ) -> str :
20+ return "Google Earth Engine Snippet"
21+
22+ @property
23+ def default_file_extension (self ) -> str :
24+ return "js"
25+
26+ def export (
27+ self ,
28+ colormap : Colormap ,
29+ scaler : ScalingFunction ,
30+ domain_min : float ,
31+ domain_max : float ,
32+ options : Optional [Dict [str , Any ]] = None ,
33+ ) -> str :
34+ """
35+ Exports the colormap to a GEE JavaScript snippet.
36+
37+ Accepted options:
38+ type (str): 'default' or 'sld'. Default is 'default'.
39+ num_colors (int): Number of color steps to generate. Default 256.
40+ """
41+ options = options or {}
42+ export_type = options .get ("type" , "default" )
43+ num_colors = options .get ("num_colors" , 256 )
44+ if not isinstance (num_colors , int ):
45+ raise ValueError ("Option 'num_colors' must be an integer." )
46+
47+ if export_type == "default" :
48+ return self ._export_default (colormap , domain_min , domain_max , num_colors )
49+ elif export_type == "sld" :
50+ return self ._export_sld (colormap , domain_min , domain_max , num_colors )
51+ else :
52+ raise ValueError (f"Unsupported GEE export type: { export_type } " )
53+
54+ def _export_default (self , colormap : Colormap , domain_min : float , domain_max : float , num_colors : int ) -> str :
55+ """Exports a GEE visualization palette."""
56+ if num_colors < 2 :
57+ raise ValueError ("Number of colors must be at least 2." )
58+
59+ # GEE palette colors are hex strings without the '#'
60+ colors = []
61+ for i in range (num_colors ):
62+ position = i / (num_colors - 1 )
63+ color_hex = colormap .get_color (position , output_format = "hex" )
64+ if isinstance (color_hex , str ):
65+ colors .append (color_hex [1 :])
66+
67+ palette_str = ", " .join ([f"'{ c } '" for c in colors ])
68+ return f"var palettize_viz = {{min: { domain_min } , max: { domain_max } , palette: [{ palette_str } ]}};"
69+
70+ def _export_sld (self , colormap : Colormap , domain_min : float , domain_max : float , num_colors : int ) -> str :
71+ """Exports a GEE SLD-style palette."""
72+ if num_colors < 2 :
73+ raise ValueError ("Number of colors must be at least 2 for SLD ramp." )
74+
75+ entries = []
76+ for i in range (num_colors ):
77+ position = i / (num_colors - 1 )
78+
79+ value = domain_min + position * (domain_max - domain_min )
80+ # a bit of rounding to avoid long float strings
81+ if abs (value - round (value )) < 1e-9 :
82+ value = int (round (value ))
83+ else :
84+ value = round (value , 4 )
85+
86+ color_hex_any = colormap .get_color (position , output_format = "hex" )
87+ if isinstance (color_hex_any , str ):
88+ color_hex = color_hex_any
89+ else :
90+ color_hex = "#000000" # Fallback, should not be reached with hex format
91+ # Each entry is a JS string literal concatenated with '+'
92+ entry = f' \' <ColorMapEntry color="{ color_hex } " quantity="{ value } " label="{ value } " />\' +'
93+ entries .append (entry )
94+
95+ # remove the last ' +' from the last entry
96+ if entries :
97+ entries [- 1 ] = entries [- 1 ].rstrip (" +" )
98+
99+ entries_str = "\n " .join (entries )
100+
101+ # Using a multiline f-string for better readability and correctness
102+ final_string = f"""var palettize_sld =
103+ '<RasterSymbolizer>' +
104+ '<ColorMap type="ramp" extended="false" >' +
105+ { entries_str }
106+ '</ColorMap>' +
107+ '</RasterSymbolizer>';"""
108+
109+ return final_string
0 commit comments