Skip to content

Commit b15a1c8

Browse files
committed
Merge branch 'exporter-plaintext'
merge pr from @loganbyers plus some cli behavior updates
2 parents 08e0ff9 + 51c40fb commit b15a1c8

File tree

3 files changed

+115
-19
lines changed

3 files changed

+115
-19
lines changed

src/palettize/cli.py

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ class ExitCodes:
4949
class AppState:
5050
def __init__(self):
5151
self.verbose_level = 0
52-
self.quiet = False
5352

5453

5554
app_state = AppState()
@@ -76,9 +75,7 @@ def verbosity_callback(ctx: typer.Context, param: typer.CallbackParam, value: in
7675
return value
7776

7877

79-
def quiet_callback(ctx: typer.Context, param: typer.CallbackParam, value: bool):
80-
app_state.quiet = value
81-
return value
78+
8279

8380

8481
@app.callback()
@@ -101,15 +98,6 @@ def global_options(
10198
help="Increase output verbosity. Use -vv for more detail.",
10299
show_default=False,
103100
),
104-
quiet: Optional[bool] = typer.Option(
105-
False,
106-
"--quiet",
107-
"-q",
108-
callback=quiet_callback,
109-
is_flag=True,
110-
help="Suppress all informational output; only errors will be shown.",
111-
show_default=False,
112-
),
113101
):
114102
"""
115103
Palettize: Generate, preview, and export colormaps from the command line.
@@ -203,7 +191,7 @@ def _create_colormap_from_options(
203191
f"[bold red]An unexpected error occurred during colormap creation:[/bold red] {e}",
204192
style="bold red",
205193
)
206-
if app_state.verbose_level > 0:
194+
if app_state.verbose_level > 1:
207195
console.print(
208196
Panel(
209197
traceback.format_exc(),
@@ -249,7 +237,7 @@ def _render_colormap_to_terminal(
249237
actual_width = width if width is not None else console_width
250238
actual_width = max(10, actual_width)
251239

252-
if not app_state.quiet:
240+
if app_state.verbose_level > 0:
253241
console.print(
254242
f"Rendering preview of '{colormap_obj.name or 'custom'}' ({actual_width}x{height} chars):"
255243
)
@@ -481,7 +469,7 @@ def create(
481469
overall_success = False
482470
continue
483471

484-
if not app_state.quiet:
472+
if app_state.verbose_level > 0:
485473
console.print(f"Exporting to [cyan]{fmt}[/cyan] format...")
486474

487475
# Combine global and format-specific options
@@ -509,7 +497,7 @@ def create(
509497
output_path = Path(output_path_str)
510498
output_path.parent.mkdir(parents=True, exist_ok=True)
511499
output_path.write_text(output_str)
512-
if not app_state.quiet:
500+
if app_state.verbose_level > 0:
513501
console.print(f"[green]Successfully wrote to {output_path}[/green]")
514502
else:
515503
# If no output path, print to stdout
@@ -519,7 +507,7 @@ def create(
519507
console.print(
520508
f"[bold red]Failed to export to {fmt}:[/bold red] {e}", style="bold red"
521509
)
522-
if app_state.verbose_level > 0:
510+
if app_state.verbose_level > 1:
523511
console.print(
524512
Panel(
525513
traceback.format_exc(),
@@ -532,5 +520,5 @@ def create(
532520
if not overall_success:
533521
raise typer.Exit(code=ExitCodes.EXPORT_ERROR)
534522

535-
if not app_state.quiet:
523+
if app_state.verbose_level > 0:
536524
console.print("[bold green]Export process completed.[/bold green]")

src/palettize/exporters/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from .mapgl import MapglExporter
1515
from .observable_plot import ObservablePlotExporter
1616
from .gee import GEEExporter
17+
from .plaintext import HexExporter, RGBAExporter
1718

1819
# Global registry for exporters
1920
# Maps an identifier string to an instantiated exporter object or a callable that returns one.
@@ -86,6 +87,8 @@ def list_available_exporters() -> Dict[str, str]:
8687
MapglExporter(),
8788
ObservablePlotExporter(),
8889
GEEExporter(),
90+
HexExporter(),
91+
RGBAExporter(),
8992
]
9093

9194
for exporter_instance in _BUILTIN_EXPORTERS:
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
"""Exporter for plain text files - newline delimited representations of color."""
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 HexExporter(BaseExporter):
10+
"""
11+
Exporter for plain text hashed hex values for rgb.
12+
"""
13+
14+
@property
15+
def identifier(self) -> str:
16+
return "hex"
17+
18+
@property
19+
def name(self) -> str:
20+
return "Plaintext Hashed Hexadecimal"
21+
22+
@property
23+
def default_file_extension(self) -> str:
24+
return "txt"
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 plain text hash-prefixed hexadecimal format.
36+
37+
Accepted options:
38+
num_colors (int): Number of color steps to generate. Default 256.
39+
"""
40+
options = options or {}
41+
num_colors = options.get("num_colors", 256)
42+
if not isinstance(num_colors, int):
43+
raise ValueError("Option 'num_colors' must be an integer.")
44+
if num_colors < 2:
45+
raise ValueError("Number of colors must be at least 2.")
46+
47+
# palette colors are hex strings with the '#' prefix
48+
colors = []
49+
for i in range(num_colors):
50+
position = i / (num_colors - 1)
51+
color_hex = colormap.get_color(position, output_format="hex")
52+
colors.append(color_hex)
53+
54+
palette_str = "\n".join(colors)
55+
return palette_str
56+
57+
58+
class RGBAExporter(BaseExporter):
59+
"""
60+
Exporter for plain text RGBA values suitable for CSS, for instance.
61+
"""
62+
63+
@property
64+
def identifier(self) -> str:
65+
return "rgba"
66+
67+
@property
68+
def name(self) -> str:
69+
return "Plaintext RGBA"
70+
71+
@property
72+
def default_file_extension(self) -> str:
73+
return "txt"
74+
75+
def export(
76+
self,
77+
colormap: Colormap,
78+
scaler: ScalingFunction,
79+
domain_min: float,
80+
domain_max: float,
81+
options: Optional[Dict[str, Any]] = None,
82+
) -> str:
83+
"""
84+
Exports the colormap to a plain text rgba(intR, intG, intB, intA) format.
85+
86+
Accepted options:
87+
num_colors (int): Number of color steps to generate. Default 256.
88+
"""
89+
options = options or {}
90+
num_colors = options.get("num_colors", 256)
91+
if not isinstance(num_colors, int):
92+
raise ValueError("Option 'num_colors' must be an integer.")
93+
if num_colors < 2:
94+
raise ValueError("Number of colors must be at least 2.")
95+
96+
colors = []
97+
for i in range(num_colors):
98+
position = i / (num_colors - 1)
99+
r, g, b, a = colormap.get_color(position, output_format="rgba_tuple")
100+
color_string = f"rgba({r}, {g}, {b}, {a})"
101+
colors.append(color_string)
102+
103+
palette_str = "\n".join(colors)
104+
return palette_str
105+

0 commit comments

Comments
 (0)