Skip to content

Commit 891ed50

Browse files
authored
Refactor: Optimize PNGs (#25)
* optimize pngs * .
1 parent d67f1e3 commit 891ed50

File tree

1 file changed

+27
-13
lines changed

1 file changed

+27
-13
lines changed

wavey/__main__.py

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import datetime
22
import io
3+
import itertools
34
import logging
5+
from concurrent.futures import ThreadPoolExecutor
46
from pathlib import Path
57

68
import matplotlib
@@ -59,30 +61,30 @@ def utc_to_pt(dt: datetime.datetime) -> datetime.datetime:
5961
return dt.astimezone(tz=TZ_PACIFIC)
6062

6163

62-
def savefig(path: Path) -> None:
64+
def quantize_png(in_png: str | Path | io.BytesIO, out_path: Path, dither: bool) -> None:
6365
"""
64-
Save matplotlib figure to PNG file.
65-
66-
We perform a bit of optimization to make the output filesize smaller
67-
without sacrificing quality.
66+
Quantize a PNG to save space and save to disk.
6867
6968
Args:
70-
path: Path to output PNG file.
69+
in_png: Input PNG. Should be in "RGBA" format.
70+
out_path: Path to output PNG file.
71+
dither: Whether to use dithering.
7172
"""
7273

73-
bts = io.BytesIO()
74-
plt.savefig(bts, format="png")
75-
76-
with PIL.Image.open(bts) as img:
77-
img2 = img.convert("RGB").convert("P", palette=PIL.Image.Palette.WEB)
78-
img2.save(path, format="png")
74+
with PIL.Image.open(in_png) as img: # RGBA image
75+
if dither:
76+
# converting to RGB will enable dithering
77+
img = img.convert("RGB")
78+
img = img.convert("P", palette=PIL.Image.Palette.WEB)
79+
img.save(out_path, format="png", optimize=True)
7980

8081

8182
def main(
8283
grib_path: Path | None = None,
8384
/,
8485
out_dir: Path = Path("_site"),
8586
resolution: RESOLUTION = "h",
87+
dither: bool = True,
8688
) -> None:
8789
"""
8890
Create plots for significant wave height.
@@ -94,6 +96,7 @@ def main(
9496
out_dir: Path to output directory.
9597
resolution: Resolution of the coastline map. Options are crude, low,
9698
intermediate, high, and full.
99+
dither: Dithering increases image quality, but also increases storage size.
97100
"""
98101

99102
if resolution != "f":
@@ -254,6 +257,9 @@ def main(
254257
LOG.info("Creating colormap frames")
255258
plot_dir = out_dir / "plots"
256259
plot_dir.mkdir(parents=True, exist_ok=True)
260+
261+
# render each frame
262+
frame_pngs_bytes: list[io.BytesIO] = []
257263
for hour_i in tqdm(range(NUM_DATA_POINTS)):
258264
pacific_time = analysis_date_pacific + datetime.timedelta(hours=hour_i)
259265
pacific_time_str = pacific_time.strftime(DATETIME_FORMAT)
@@ -265,7 +271,15 @@ def main(
265271
ax_main.set_title(
266272
f"Significant wave height (ft) and peak wave direction\nHour {hour_i:03} {pacific_time_str}"
267273
)
268-
savefig(plot_dir / f"{hour_i}.png")
274+
275+
png_bytes = io.BytesIO()
276+
plt.savefig(png_bytes, format="png")
277+
frame_pngs_bytes.append(png_bytes)
278+
279+
# quantize each PNG and save to disk
280+
with ThreadPoolExecutor() as exe:
281+
paths = [plot_dir / f"{hour_i}.png" for hour_i in range(NUM_DATA_POINTS)]
282+
exe.map(quantize_png, frame_pngs_bytes, paths, itertools.repeat(dither))
269283

270284
# Get current time and version
271285

0 commit comments

Comments
 (0)