diff --git a/.gitignore b/.gitignore index 175ee7f..136bb25 100644 --- a/.gitignore +++ b/.gitignore @@ -42,4 +42,4 @@ tests/animation/ demo/ events.jsonl NEW-TODO.md -NEW-TODO.md~ +work/ diff --git a/CHANGELOG.md b/CHANGELOG.md index c8d16b6..fae9d91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- **JPEG XL output** — `map` and `diff` accept `--format jxl` or infer JXL from a `.jxl` output + filename. `git` and `hg` support `.jxl` for static snapshots, and `watch` supports `.jxl` + snapshots. Install the optional encoder with `pip install "dirplot[jxl]"`. + - **Manual reload and auto-reload controls in `serve`** — the web UI gained a toolbar **Reload** button that rescans the source and updates the treemap in place (preserving the current zoom and without touching the sidebar). A new **Auto-reload** toggle in the Settings tab connects or diff --git a/README.md b/README.md index fcd96cc..8da756f 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ dirplot map . --inline # display inline in terminal (iTerm2 / Kitty / Ghostty) ## Features - Squarified treemap layout; file area proportional to size; per-extension colours (GitHub Linguist palette for known types, configurable Matplotlib colormap for the rest). -- PNG, animated PNG (APNG), MP4, and MOV output for single frames and animations; interactive SVG for static maps; renders at terminal pixel size or a custom `WIDTHxHEIGHT`. +- PNG, optional JPEG XL (JXL), animated PNG (APNG), MP4, and MOV output; interactive SVG for static maps; renders at terminal pixel size or a custom `WIDTHxHEIGHT`. - **Inline terminal display** — renders directly into iTerm2, Kitty, Ghostty, WezTerm, and Warp without opening a separate window; protocol auto-detected. - **Animate git history** (`dirplot git`), **Mercurial history** (`dirplot hg`), and **replay filesystem event logs** (`dirplot replay`) — output APNG, MP4, or MOV. **Watch live filesystems** (`dirplot watch`) with optional snapshot and event logging. - **Scan metrics** (`dirplot metrics`) — file/dir counts, total size, depth, top extensions by count or size, largest files and directories with percentage of total; JSON output supported. diff --git a/docs/installation.md b/docs/installation.md index d96b51a..9b8b1ca 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -36,6 +36,7 @@ Install only what you need: | `ssh` | Scan remote servers via SSH (adds [paramiko](https://www.paramiko.org/)) | `pip install "dirplot[ssh]"` | | `s3` | Scan AWS S3 buckets (adds [boto3](https://boto3.amazonaws.com/)) | `pip install "dirplot[s3]"` | | `libarchive` | Additional archive formats: `.tar.zst`, `.iso`, `.dmg`, `.rpm`, `.cab`, … (requires system [libarchive](https://libarchive.org/)) | `pip install "dirplot[libarchive]"` | +| `jxl` | JPEG XL (`.jxl`) output for static treemaps and snapshots | `pip install "dirplot[jxl]"` | **Remote backend CLIs** — no Python package needed; dirplot shells out to these directly: diff --git a/pyproject.toml b/pyproject.toml index ad29dea..55ba4f6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,6 +62,9 @@ dev = [ libarchive = [ "libarchive-c>=5.0", ] +jxl = [ + "pillow-jxl-plugin>=1.3.8", +] [project.urls] Repository = "https://github.com/deeplook/dirplot" diff --git a/src/dirplot/commands/diff.py b/src/dirplot/commands/diff.py index ec5c1cd..f19a93d 100644 --- a/src/dirplot/commands/diff.py +++ b/src/dirplot/commands/diff.py @@ -57,7 +57,7 @@ def diff_cmd( fmt: str | None = typer.Option( None, "--format", - help="Output format: png or svg (inferred from --output extension if omitted)", + help="Output format: png, svg, or jxl (inferred from --output extension if omitted)", metavar="FORMAT", ), show: bool = typer.Option(True, "--show/--no-show", help="Display the image after rendering"), @@ -469,13 +469,16 @@ def _collect_paths(node: Node) -> list[str]: # Resolve format if fmt is not None: - if fmt not in ("png", "svg"): - typer.echo(f"Unknown format '{fmt}'. Valid options: png, svg", err=True) + output_format = fmt.lower() + if output_format not in ("png", "svg", "jxl"): + typer.echo(f"Unknown format '{fmt}'. Valid options: png, svg, jxl", err=True) raise typer.Exit(1) - use_svg = fmt == "svg" - elif output is not None and output.suffix.lower() == ".svg": - use_svg = True + use_svg = output_format == "svg" + elif output is not None and output.suffix.lower() in (".svg", ".jxl"): + output_format = output.suffix.lower()[1:] + use_svg = output_format == "svg" else: + output_format = "png" use_svg = False label_a = title_a or Path(tree_a).name @@ -513,12 +516,23 @@ def _collect_paths(node: Node) -> list[str]: ) t_render = time.monotonic() - t_render_start + if output_format == "jxl": + from dirplot.image_formats import encode_jxl + + try: + output_buf = encode_jxl(buf) + except RuntimeError as exc: + typer.echo(f"Error: {exc}", err=True) + raise typer.Exit(1) from None + else: + output_buf = buf + if output is not None: if to_stdout: - sys.stdout.buffer.write(buf.read()) + sys.stdout.buffer.write(output_buf.read()) buf.seek(0) else: - output.write_bytes(buf.read()) + output.write_bytes(output_buf.read()) _info(f"Saved diff to {output} [{t_render:.1f}s]") buf.seek(0) diff --git a/src/dirplot/commands/treemap.py b/src/dirplot/commands/treemap.py index 5ced8c1..a09b4c5 100644 --- a/src/dirplot/commands/treemap.py +++ b/src/dirplot/commands/treemap.py @@ -83,7 +83,7 @@ def main( fmt: str | None = typer.Option( None, "--format", - help="Output format: png or svg. Defaults to svg if --output ends in .svg, else png.", + help="Output format: png, svg, or jxl. Defaults from --output extension, otherwise png.", metavar="FORMAT", ), show: bool = typer.Option(True, "--show/--no-show", help="Display the image after rendering"), @@ -371,14 +371,18 @@ def _collect_paths(node: Node) -> list[str]: _info(f"Terminal size: {width_px}x{height_px}px") # Resolve output format: explicit --format > inferred from --output extension > png + output_format: str if fmt is not None: - if fmt not in ("png", "svg"): - typer.echo(f"Unknown format '{fmt}'. Valid options: png, svg", err=True) + output_format = fmt.lower() + if output_format not in ("png", "svg", "jxl"): + typer.echo(f"Unknown format '{fmt}'. Valid options: png, svg, jxl", err=True) raise typer.Exit(1) - use_svg = fmt == "svg" - elif output is not None and output.suffix.lower() == ".svg": - use_svg = True + use_svg = output_format == "svg" + elif output is not None and output.suffix.lower() in (".svg", ".jxl"): + output_format = output.suffix.lower()[1:] + use_svg = output_format == "svg" else: + output_format = "png" use_svg = False _stderr_console = _Console(stderr=True) @@ -413,12 +417,23 @@ def _collect_paths(node: Node) -> list[str]: ) t_render = time.monotonic() - t_render_start + if output_format == "jxl": + from dirplot.image_formats import encode_jxl + + try: + output_buf = encode_jxl(buf) + except RuntimeError as exc: + typer.echo(f"Error: {exc}", err=True) + raise typer.Exit(1) from None + else: + output_buf = buf + if output is not None: if to_stdout: - sys.stdout.buffer.write(buf.read()) + sys.stdout.buffer.write(output_buf.read()) buf.seek(0) else: - output.write_bytes(buf.read()) + output.write_bytes(output_buf.read()) if header: _info(f"Saved dirplot to {output} [{t_render:.1f}s]") buf.seek(0) diff --git a/src/dirplot/commands/vcs.py b/src/dirplot/commands/vcs.py index 06feb73..e59b54f 100644 --- a/src/dirplot/commands/vcs.py +++ b/src/dirplot/commands/vcs.py @@ -410,8 +410,8 @@ def git_cmd( "Error: animation --output must be a .png (APNG), .mp4, or .mov file.", err=True ) raise typer.Exit(1) - if not is_animation and output.suffix.lower() not in {".png", ".svg"}: - typer.echo("Error: snapshot --output must be a .png or .svg file.", err=True) + if not is_animation and output.suffix.lower() not in {".png", ".svg", ".jxl"}: + typer.echo("Error: snapshot --output must be a .png, .svg, or .jxl file.", err=True) raise typer.Exit(1) period_dt: datetime | None = None @@ -747,6 +747,14 @@ def git_cmd( display_inline(out_buf, cols=inline_cols) else: assert output is not None + if output.suffix.lower() == ".jxl": + from dirplot.image_formats import encode_jxl + + try: + out_buf = encode_jxl(out_buf) + except RuntimeError as exc: + typer.echo(f"Error: {exc}", err=True) + raise typer.Exit(1) from None output.write_bytes(out_buf.read()) if not quiet: typer.echo(f"Wrote {output}", err=True) @@ -937,8 +945,8 @@ def hg_cmd( "Error: animation --output must be a .png (APNG), .mp4, or .mov file.", err=True ) raise typer.Exit(1) - if not is_animation and output.suffix.lower() not in {".png", ".svg"}: - typer.echo("Error: snapshot --output must be a .png or .svg file.", err=True) + if not is_animation and output.suffix.lower() not in {".png", ".svg", ".jxl"}: + typer.echo("Error: snapshot --output must be a .png, .svg, or .jxl file.", err=True) raise typer.Exit(1) period_dt: datetime | None = None @@ -1214,6 +1222,14 @@ def hg_cmd( display_inline(out_buf, cols=inline_cols) else: assert output is not None + if output.suffix.lower() == ".jxl": + from dirplot.image_formats import encode_jxl + + try: + out_buf = encode_jxl(out_buf) + except RuntimeError as exc: + typer.echo(f"Error: {exc}", err=True) + raise typer.Exit(1) from None output.write_bytes(out_buf.read()) if not quiet: typer.echo(f"Wrote {output}", err=True) diff --git a/src/dirplot/commands/watch.py b/src/dirplot/commands/watch.py index 9822390..93329bf 100644 --- a/src/dirplot/commands/watch.py +++ b/src/dirplot/commands/watch.py @@ -44,7 +44,7 @@ def watch_cmd( None, "--snapshot", help=( - "Also write the current treemap as a PNG or SVG on each change. " + "Also write the current treemap as a PNG, SVG, or JXL on each change. " "Convenient for small trees; avoid on large directories as rendering adds latency." ), metavar="FILE", @@ -117,7 +117,7 @@ def watch_cmd( """Watch directories and record filesystem events as JSONL for later replay. Use `dirplot replay` to turn the recording into an animated treemap. - Pass --snapshot to also write a live PNG/SVG on each change (best for small trees). + Pass --snapshot to also write a live PNG/SVG/JXL on each change (best for small trees). Example: dirplot watch src --output events.jsonl """ diff --git a/src/dirplot/image_formats.py b/src/dirplot/image_formats.py new file mode 100644 index 0000000..ac2e097 --- /dev/null +++ b/src/dirplot/image_formats.py @@ -0,0 +1,25 @@ +"""Helpers for optional raster output formats.""" + +from __future__ import annotations + +import io + + +def encode_jxl(png: io.BytesIO) -> io.BytesIO: + """Encode a rendered PNG buffer as JPEG XL using the optional Pillow plugin.""" + try: + import pillow_jxl # noqa: F401 # Registers JXL with Pillow. + except ImportError: + raise RuntimeError( + "JPEG XL output requires an optional dependency. Install it with: " + "pip install 'dirplot[jxl]'" + ) from None + + from PIL import Image + + png.seek(0) + with Image.open(png) as image: + result = io.BytesIO() + image.save(result, format="JXL", lossless=True) + result.seek(0) + return result diff --git a/src/dirplot/watch.py b/src/dirplot/watch.py index 25d3d3c..2d240d1 100644 --- a/src/dirplot/watch.py +++ b/src/dirplot/watch.py @@ -55,6 +55,7 @@ def __init__( self.cushion = cushion self.dark = dark self.use_svg = snapshot is not None and snapshot.suffix.lower() == ".svg" + self.use_jxl = snapshot is not None and snapshot.suffix.lower() == ".jxl" self.logscale = logscale self.debounce = debounce self.output = output @@ -140,6 +141,10 @@ def _collect(n: _Node) -> list[str]: logscale=self.logscale, ) if self.snapshot is not None: + if self.use_jxl: + from dirplot.image_formats import encode_jxl + + buf = encode_jxl(buf) self.snapshot.write_bytes(buf.read()) print(f"Updated {self.snapshot}", file=sys.stderr) self._prev_rect_map = rect_map diff --git a/tests/test_cli.py b/tests/test_cli.py index fe5ff56..a6bf604 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -110,6 +110,43 @@ def test_cli_stdout_svg(sample_tree: Path) -> None: assert " None: + import dirplot.image_formats + + monkeypatch.setattr(dirplot.image_formats, "encode_jxl", lambda _buf: BytesIO(b"mock-jxl")) + output = tmp_path / "map.jxl" + result = runner.invoke( + app, ["map", str(sample_tree), "--no-show", "--output", str(output), "--canvas", "100x100"] + ) + assert result.exit_code == 0, result.output + assert output.read_bytes() == b"mock-jxl" + + +def test_map_jxl_format_option( + sample_tree: Path, tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + import dirplot.image_formats + + monkeypatch.setattr(dirplot.image_formats, "encode_jxl", lambda _buf: BytesIO(b"mock-jxl")) + output = tmp_path / "map.data" + result = runner.invoke( + app, + [ + "map", + str(sample_tree), + "--no-show", + "--output", + str(output), + "--format", + "jxl", + "--canvas", + "100x100", + ], + ) + assert result.exit_code == 0, result.output + assert output.read_bytes() == b"mock-jxl" + + def test_cli_literal_dash_paths_after_separator(tmp_path: Path) -> None: for name in ("--no-color", "--legend"): target = tmp_path / name diff --git a/tests/test_highlight.py b/tests/test_highlight.py index ffa3af2..bba23f1 100644 --- a/tests/test_highlight.py +++ b/tests/test_highlight.py @@ -16,6 +16,14 @@ runner = CliRunner() +def _image_pixels(img: Image.Image) -> list[tuple[int, ...]]: + """Return pixels without using Pillow's deprecated ``getdata`` on new versions.""" + get_flattened_data = getattr(img, "get_flattened_data", None) + if get_flattened_data is not None: + return list(get_flattened_data()) + return list(img.getdata()) + + # --------------------------------------------------------------------------- # resolve_highlight_specs # --------------------------------------------------------------------------- @@ -144,7 +152,7 @@ def test_png_highlight_border_pixels(tmp_path: Path) -> None: # Check that at least one red-ish pixel exists in the image # (the highlight border is drawn in pure red (255, 0, 0)) - pixels = list(img.getdata()) + pixels = _image_pixels(img) assert any(r > 200 and g < 50 and b < 50 for r, g, b in pixels), ( "Expected at least one red border pixel from the highlight" ) @@ -159,7 +167,7 @@ def test_png_no_highlight_no_red_border(tmp_path: Path) -> None: buf = create_treemap(root, width_px=400, height_px=300, cushion=False) img = Image.open(buf).convert("RGB") - pixels = list(img.getdata()) + pixels = _image_pixels(img) # The Linguist palette for .py and .md does not use pure red pure_red = sum(1 for r, g, b in pixels if r > 240 and g < 20 and b < 20) assert pure_red == 0, f"Unexpected {pure_red} pure-red pixels without highlights" @@ -181,7 +189,7 @@ def test_png_custom_color_highlight(tmp_path: Path) -> None: highlights={target: "green"}, ) img = Image.open(buf).convert("RGB") - pixels = list(img.getdata()) + pixels = _image_pixels(img) # Expect at least one clearly greenish pixel assert any(g > 100 and r < 50 and b < 50 for r, g, b in pixels), "Expected green border pixels" diff --git a/tests/test_image_formats.py b/tests/test_image_formats.py new file mode 100644 index 0000000..5246da8 --- /dev/null +++ b/tests/test_image_formats.py @@ -0,0 +1,24 @@ +"""Tests for optional raster image encoders.""" + +from __future__ import annotations + +from io import BytesIO + +import pytest +from PIL import Image + +from dirplot.image_formats import encode_jxl + + +def test_encode_jxl_round_trip() -> None: + pytest.importorskip("pillow_jxl") + + source = BytesIO() + Image.new("RGB", (3, 2), (12, 34, 56)).save(source, format="PNG") + + result = encode_jxl(source) + + with Image.open(result) as decoded: + assert decoded.format == "JXL" + assert decoded.size == (3, 2) + assert decoded.convert("RGB").getpixel((0, 0)) == (12, 34, 56) diff --git a/tests/test_jxl_cli.py b/tests/test_jxl_cli.py new file mode 100644 index 0000000..05fb772 --- /dev/null +++ b/tests/test_jxl_cli.py @@ -0,0 +1,141 @@ +"""CLI coverage for JPEG XL output across supported commands.""" + +from __future__ import annotations + +import shutil +import subprocess +from io import BytesIO +from pathlib import Path +from types import SimpleNamespace + +import pytest +from typer.testing import CliRunner + +from dirplot.main import app +from dirplot.scanner import Node + +runner = CliRunner() + + +@pytest.mark.parametrize( + ("output_name", "format_args"), + [("diff.jxl", []), ("diff.data", ["--format", "jxl"])], +) +def test_diff_jxl_output( + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, + output_name: str, + format_args: list[str], +) -> None: + import dirplot.image_formats + + monkeypatch.setattr(dirplot.image_formats, "encode_jxl", lambda _buf: BytesIO(b"mock-jxl")) + tree_a = tmp_path / "a" + tree_b = tmp_path / "b" + tree_a.mkdir() + tree_b.mkdir() + (tree_a / "file.txt").write_text("before") + (tree_b / "file.txt").write_text("after") + output = tmp_path / output_name + result = runner.invoke( + app, + [ + "diff", + str(tree_a), + str(tree_b), + "--no-show", + "--canvas", + "100x100", + "--output", + str(output), + *format_args, + ], + ) + + assert result.exit_code == 0, result.output + assert output.read_bytes() == b"mock-jxl" + + +@pytest.mark.parametrize(("command", "repo_marker"), [("git", ".git"), ("hg", ".hg")]) +def test_vcs_jxl_snapshot( + command: str, + repo_marker: str, + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, +) -> None: + import dirplot.git_scanner as git_scanner + import dirplot.hg_scanner as hg_scanner + import dirplot.image_formats + import dirplot.render_png + + repo = tmp_path / "repo" + repo.mkdir() + (repo / repo_marker).mkdir() + output = tmp_path / f"{command}.jxl" + node = Node(name="repo", path=repo, size=4, is_dir=True) + + monkeypatch.setattr(shutil, "which", lambda _name: "/usr/bin/mock-vcs") + monkeypatch.setattr(subprocess, "run", lambda *_args, **_kwargs: SimpleNamespace(stdout="1\n")) + monkeypatch.setattr(git_scanner, "git_log", lambda *_args: [("a" * 40, 1_700_000_000, "first")]) + monkeypatch.setattr(git_scanner, "git_initial_files", lambda *_args: {"file.txt": 4}) + monkeypatch.setattr(hg_scanner, "hg_log", lambda *_args: [("b" * 40, 1_700_000_000, "first")]) + monkeypatch.setattr(hg_scanner, "hg_initial_files", lambda *_args: {"file.txt": 4}) + monkeypatch.setattr(git_scanner, "build_node_tree", lambda *_args: node) + monkeypatch.setattr(hg_scanner, "build_node_tree", lambda *_args: node) + monkeypatch.setattr( + dirplot.render_png, "create_treemap", lambda *_args, **_kwargs: BytesIO(b"mock-png") + ) + monkeypatch.setattr(dirplot.image_formats, "encode_jxl", lambda _buf: BytesIO(b"mock-jxl")) + + result = runner.invoke( + app, + [command, str(repo), "--output", str(output), "--canvas", "100x100", "--quiet"], + ) + + assert result.exit_code == 0, result.output + assert output.read_bytes() == b"mock-jxl" + + +@pytest.mark.parametrize(("command", "revision_range"), [("git", "HEAD~1..HEAD"), ("hg", "0:tip")]) +def test_vcs_jxl_rejected_for_animations( + command: str, + revision_range: str, + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, +) -> None: + output = tmp_path / f"{command}.jxl" + monkeypatch.setattr(shutil, "which", lambda _name: "/usr/bin/mock-vcs") + + result = runner.invoke( + app, + [command, ".", "--range", revision_range, "--output", str(output)], + ) + + assert result.exit_code == 1 + assert "animation --output must be a .png (APNG), .mp4, or .mov" in result.output + assert not output.exists() + + +def test_watch_jxl_snapshot( + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, +) -> None: + import dirplot.image_formats + from dirplot.watch import TreemapEventHandler + + (tmp_path / "file.txt").write_text("contents") + output = tmp_path / "watch.jxl" + monkeypatch.setattr(dirplot.image_formats, "encode_jxl", lambda _buf: BytesIO(b"mock-jxl")) + handler = TreemapEventHandler( + [tmp_path], + snapshot=output, + width_px=100, + height_px=100, + font_size=12, + colormap="tab20", + cushion=False, + ) + + handler._regenerate() + + assert output.read_bytes() == b"mock-jxl" diff --git a/uv.lock b/uv.lock index 6b375d6..daefb94 100644 --- a/uv.lock +++ b/uv.lock @@ -656,6 +656,9 @@ dev = [ { name = "pytest-cov" }, { name = "ruff" }, ] +jxl = [ + { name = "pillow-jxl-plugin" }, +] libarchive = [ { name = "libarchive-c" }, ] @@ -678,6 +681,7 @@ requires-dist = [ { name = "mypy", marker = "extra == 'dev'", specifier = ">=1.10" }, { name = "paramiko", marker = "extra == 'ssh'", specifier = ">=3.0" }, { name = "pillow", specifier = ">=9.0" }, + { name = "pillow-jxl-plugin", marker = "extra == 'jxl'", specifier = ">=1.3.8" }, { name = "pre-commit", marker = "extra == 'dev'", specifier = ">=3.0" }, { name = "py7zr", specifier = ">=0.20" }, { name = "pytest", marker = "extra == 'dev'", specifier = ">=8.0" }, @@ -690,7 +694,7 @@ requires-dist = [ { name = "uvicorn", extras = ["standard"], specifier = ">=0.29" }, { name = "watchdog", specifier = ">=6.0.0" }, ] -provides-extras = ["ssh", "s3", "dev", "libarchive"] +provides-extras = ["ssh", "s3", "dev", "libarchive", "jxl"] [[package]] name = "distlib" @@ -1482,6 +1486,86 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f2/26/c56ce33ca856e358d27fda9676c055395abddb82c35ac0f593877ed4562e/pillow-12.1.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:cb9bb857b2d057c6dfc72ac5f3b44836924ba15721882ef103cecb40d002d80e", size = 7029880, upload-time = "2026-02-11T04:23:04.783Z" }, ] +[[package]] +name = "pillow-jxl-plugin" +version = "1.3.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, + { name = "pillow" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/02/75/810608d489c2d453e16a0866de5edea2bedd728e8830da22a1ec633f3b80/pillow_jxl_plugin-1.3.8.tar.gz", hash = "sha256:4430fd7757899742079c548a7d2537d6d63cf0f1d323180095bc0f6f03d9d4fa", size = 1602233, upload-time = "2026-07-17T03:23:50.387Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e6/2f/13fcf0700d7de9e270dede2448a39f2f39764356f48b030e93aa00b378c3/pillow_jxl_plugin-1.3.8-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:8e5917812ab609951211c771726cfc99f161238b09a9175ea1fb122c94227b22", size = 2360623, upload-time = "2026-07-17T03:22:54.101Z" }, + { url = "https://files.pythonhosted.org/packages/95/96/b9e8c5521590308a9ae441f163a593af403130ff12f6e954f9710d18d369/pillow_jxl_plugin-1.3.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b1f80e18334215195eb7f5a19e20b8448778740aab6ffb058da551c1c1d95b70", size = 2667999, upload-time = "2026-07-17T03:22:45.733Z" }, + { url = "https://files.pythonhosted.org/packages/af/0c/ce07ec0035dce02cfc00df05900b8b2f129c170d55e62eca57470353c49b/pillow_jxl_plugin-1.3.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b4c60dadc9656e2d3093310c64fc8b521dfcea299913838bef9ff496e777f65", size = 2791586, upload-time = "2026-07-17T03:22:18.684Z" }, + { url = "https://files.pythonhosted.org/packages/53/e6/f72e4c8e3ea000bb9472cd83bf3a7e78f5f6ab34ed22ff6c2e1743d5bcf7/pillow_jxl_plugin-1.3.8-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:06a0d4d530c8e36f098301f426611dac4c3a7693cfb3121663f1ca8f71ba4517", size = 2504840, upload-time = "2026-07-17T03:22:27.829Z" }, + { url = "https://files.pythonhosted.org/packages/fb/fa/92212283b7fe3c71cbabb9443b8a8ed940fb73804bdebc86d08e52cf8349/pillow_jxl_plugin-1.3.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5bd82982ff69470b6dfdfdca7f4308cb32c1c6910f95511db58dc59fc0411e59", size = 2508263, upload-time = "2026-07-17T03:22:36.647Z" }, + { url = "https://files.pythonhosted.org/packages/a0/d5/40f52b1892105d33510d0ff472f6743d570e750c33c37d3e9697fde99f94/pillow_jxl_plugin-1.3.8-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:be5ea80860966bcea91a6e91aaaa3dd510d537cdf5245c811d41cd3a5538f8f1", size = 9730153, upload-time = "2026-07-17T03:23:02.54Z" }, + { url = "https://files.pythonhosted.org/packages/59/ba/e232759c07440d07479973d753a906715000cc71dd56fe7df70fd58304df/pillow_jxl_plugin-1.3.8-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:537a6f702b066bd8c69ba8202f1350a3d1e05e23bbe28f0d5f1567588a5bb16e", size = 8391469, upload-time = "2026-07-17T03:23:15.114Z" }, + { url = "https://files.pythonhosted.org/packages/a3/ab/410e078dddb769bcbf238837add920a788cd063aea43c04fbff29ea9d02b/pillow_jxl_plugin-1.3.8-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:85d8496e35035e1a228daf52578bde6f94fcd908202324f32dfe3b7b0430efd0", size = 9037205, upload-time = "2026-07-17T03:23:26.945Z" }, + { url = "https://files.pythonhosted.org/packages/b8/a0/3dcd7f6aa750ec4d01f467abb481aacca000f06f67ed1724beac6dcdfff3/pillow_jxl_plugin-1.3.8-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0a04950cff6e0550574117512b2cf5dc3d084d2abd95c752bd7ab219f5511e79", size = 9237632, upload-time = "2026-07-17T03:23:38.387Z" }, + { url = "https://files.pythonhosted.org/packages/bc/27/3cfca1046155b0c8561d4f68fc12971853c9f3fd25aa9dae5a44544615d7/pillow_jxl_plugin-1.3.8-cp310-cp310-win32.whl", hash = "sha256:812a8f0a24d1bc751bbe4119ead7d458726558b2c1af72f99e6c381cb6d48025", size = 4557913, upload-time = "2026-07-17T03:24:04.921Z" }, + { url = "https://files.pythonhosted.org/packages/7d/fb/339b34a676805d8949350d607bdd0247401cf887c565e8fab03ba2a019ec/pillow_jxl_plugin-1.3.8-cp310-cp310-win_amd64.whl", hash = "sha256:ec20f55bfad78d96376b7274671870311f53ef724e07d9d5af8bba36c363f77f", size = 4942011, upload-time = "2026-07-17T03:23:57.29Z" }, + { url = "https://files.pythonhosted.org/packages/db/46/9591ffeae92e62b70b0a297cf0de858ee69cda369a9a540b8989850f5c38/pillow_jxl_plugin-1.3.8-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:42bfc37327ca71e9b9c4a3d569d338db6789e0966eb89dd1fffef5fcf3c2462d", size = 2361103, upload-time = "2026-07-17T03:22:55.63Z" }, + { url = "https://files.pythonhosted.org/packages/df/f7/1dc8ddbfa056e39307d67286f45c8300695c9a0137ed98f60775a2c37322/pillow_jxl_plugin-1.3.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ceaca73f77fa0dc6409e85ca77da24560270d0929bdbee579714da05614c67ec", size = 2667692, upload-time = "2026-07-17T03:22:47.217Z" }, + { url = "https://files.pythonhosted.org/packages/a0/27/018351fecb8ebf35103408484dca3072f1a0ff28247193f46377ff6341f0/pillow_jxl_plugin-1.3.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c3109317d54918fe10d25d9978c2e445edefee04546f08ef47e077dc3dbe7e6", size = 2791235, upload-time = "2026-07-17T03:22:20.337Z" }, + { url = "https://files.pythonhosted.org/packages/12/09/cd6dff8524153196150bc778bfb828f44b65e301e06c34a1c7ca39049c49/pillow_jxl_plugin-1.3.8-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f9fd3a2c5d48faca23200176015e00b4004862f4fb9016fd17a0fa374019574e", size = 2505571, upload-time = "2026-07-17T03:22:29.564Z" }, + { url = "https://files.pythonhosted.org/packages/7a/1e/453f3268eb67190930294875628890b8eacd297364a2abadf206d715cdcf/pillow_jxl_plugin-1.3.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97a627c02fc660e6d36010c2bf57f1c346ce2a58cd7e83e43241f5ad174c3f18", size = 2508619, upload-time = "2026-07-17T03:22:38.406Z" }, + { url = "https://files.pythonhosted.org/packages/dc/80/a5859f365485fbc9e741d48c596f3913fa47fb2f4df77a134560d7766380/pillow_jxl_plugin-1.3.8-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:17fd143e6fe5c2cbb8eac1862046d63ada83ed48b6cea4753b9615a6df6f4d08", size = 9729439, upload-time = "2026-07-17T03:23:04.669Z" }, + { url = "https://files.pythonhosted.org/packages/2b/51/afa9751b8a397ad91e19a5e8afde925511abdf2a70fe98da13f6d77a567b/pillow_jxl_plugin-1.3.8-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:a86df5b196225d230c51e391f1005e86e136142d0fce98267df285651f3b0621", size = 8390938, upload-time = "2026-07-17T03:23:17.05Z" }, + { url = "https://files.pythonhosted.org/packages/50/a6/656248d1e5ce08d6154a3c904332a12093c48f22daef3779ed344a449c02/pillow_jxl_plugin-1.3.8-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:bcd116d028fe87379c934238cd3a984325bb4fde80c86526873a513a4d3c3b81", size = 9037333, upload-time = "2026-07-17T03:23:28.992Z" }, + { url = "https://files.pythonhosted.org/packages/34/35/d669758c1b49b04673b95e6bb275d59ed9f901d7a8346c8f560d5b6136fa/pillow_jxl_plugin-1.3.8-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:2f11b1d5d20013a8bdab06d9d3244488db0e00a5d57e5daaefa78f67eb70f474", size = 9237613, upload-time = "2026-07-17T03:23:40.223Z" }, + { url = "https://files.pythonhosted.org/packages/61/af/15ddbdd53a96005c8f048ce1aafab2e825e6445a3565408989e9f37bc237/pillow_jxl_plugin-1.3.8-cp311-cp311-win32.whl", hash = "sha256:d8ff168cbc04a5978f0a9320958e1ac2111e53ba4f7f7ae14a09f49c04b4e936", size = 4556704, upload-time = "2026-07-17T03:24:06.495Z" }, + { url = "https://files.pythonhosted.org/packages/dc/57/ff6381e1df975840a0af201adca7d54bb6d7cd116514527c5179f8f599f5/pillow_jxl_plugin-1.3.8-cp311-cp311-win_amd64.whl", hash = "sha256:85649ffbb6a21b2830022ce723de8625fc4d33621ed09ec4687eaf57b5044f4c", size = 4941456, upload-time = "2026-07-17T03:23:58.841Z" }, + { url = "https://files.pythonhosted.org/packages/6b/16/8c9bad406251c6a7e828641102e9bae75d2e3880b866855a699bf8b6e62b/pillow_jxl_plugin-1.3.8-cp311-cp311-win_arm64.whl", hash = "sha256:d72cbe293981677e989cf4314cb18e743e42ac84269508c0693e06c8f7e66604", size = 2333977, upload-time = "2026-07-17T03:23:51.631Z" }, + { url = "https://files.pythonhosted.org/packages/78/bb/093aced52ebaafcd050eb21ab07ddcab7efffaa687e264f64d3f0423a4ba/pillow_jxl_plugin-1.3.8-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:7f6fd0fa12dd0d98bb55df6bbfff7ad913e4ea27306fbdf5e8543fe1fa40772c", size = 2361426, upload-time = "2026-07-17T03:22:56.906Z" }, + { url = "https://files.pythonhosted.org/packages/8e/9f/f272fd205ab511475b135772e85bcaa71e5f3d081e6604b08e6e1d3982a6/pillow_jxl_plugin-1.3.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:01b632dbca07b59f7d6e106dad3ac8391e9ffdab1f94f2068a3e8edff1bbd180", size = 2660368, upload-time = "2026-07-17T03:22:48.663Z" }, + { url = "https://files.pythonhosted.org/packages/74/1a/3445d2b4f6d6e4e26f10e9ccd75b60a14295b2d8eb280f0b1bd0bd7caac3/pillow_jxl_plugin-1.3.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6459d131af2cbccab20742f6fe43a3022b021dcd1ee20b05f99b1fb54d0ec525", size = 2788244, upload-time = "2026-07-17T03:22:21.809Z" }, + { url = "https://files.pythonhosted.org/packages/26/f2/3855e83fd1e4043bd7ab286d3f0ca434fbf935598fae57f1af2777620891/pillow_jxl_plugin-1.3.8-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9b9a546ac71757f53f0ca2b14ea8f99c33b70e298a7873477f4548e2d83f817", size = 2500550, upload-time = "2026-07-17T03:22:30.993Z" }, + { url = "https://files.pythonhosted.org/packages/f0/13/d9befae0e705474e550b16c90bb6d33c3f07837af63a0e8ce4c84fb546fb/pillow_jxl_plugin-1.3.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd2afd5153e2a7ef230a3e48a679a9e1cb3e59032f79c78bb2f78010a4e9bfc1", size = 2504336, upload-time = "2026-07-17T03:22:40.143Z" }, + { url = "https://files.pythonhosted.org/packages/52/2c/3e671c8dd84f6ed4e47d588df1dc15aae61b0df0302f4bfff7b5c743045b/pillow_jxl_plugin-1.3.8-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9b987fb202dd1c71d7f6e103363afd1128d347ffcf540d8416c257c8f1041ff3", size = 9727025, upload-time = "2026-07-17T03:23:06.554Z" }, + { url = "https://files.pythonhosted.org/packages/27/89/a63b75d9c05deb0017ff51ddf3674cef19dbfe9c2fb74117d7e4a66b9a93/pillow_jxl_plugin-1.3.8-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:c05cf62a992f48434a6b876fe010e5cae12bd54039854ce9ae0f05c13a58c7ad", size = 8386443, upload-time = "2026-07-17T03:23:19.195Z" }, + { url = "https://files.pythonhosted.org/packages/c7/4f/b6ead8f5a50103e2c6b264a6d4778b8fcd08006c957b2ad0bccbbb306e97/pillow_jxl_plugin-1.3.8-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0392e5349b67522130ecff9d8dca4713e4c84662a310d2170291b229965e8fd1", size = 9032022, upload-time = "2026-07-17T03:23:30.993Z" }, + { url = "https://files.pythonhosted.org/packages/ea/53/b9aa7c156427ad4d94d8c90bd87cb502e7d6326d2689c309aa574baf1ab7/pillow_jxl_plugin-1.3.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:88b06a4e5fc0d882b188824990b6571e201ad775d22a09487c8d5ab8aed9c3b7", size = 9233286, upload-time = "2026-07-17T03:23:42.022Z" }, + { url = "https://files.pythonhosted.org/packages/32/e3/b25194909cfef9081f6a1f0e40e699e95ea96b211cae30bbf0f965d6b450/pillow_jxl_plugin-1.3.8-cp312-cp312-win32.whl", hash = "sha256:3345a45a09ba3149001c3e9a1b6991be8aab72c33097c0633e414a254cd283fa", size = 4552597, upload-time = "2026-07-17T03:24:08.129Z" }, + { url = "https://files.pythonhosted.org/packages/c3/c9/01efd23cb4827f8a1731e1a7652023a06375e933f85e3169e0761d916d6f/pillow_jxl_plugin-1.3.8-cp312-cp312-win_amd64.whl", hash = "sha256:5b1c0d7a0c7e451014b288f0504545bff0f543f2ee1581af628e01e885b75f50", size = 4937252, upload-time = "2026-07-17T03:24:00.294Z" }, + { url = "https://files.pythonhosted.org/packages/db/ef/b3aee5725df66399f529c41d97f71893e2b38f665c9278a99519112f03f3/pillow_jxl_plugin-1.3.8-cp312-cp312-win_arm64.whl", hash = "sha256:230a1d086ef5b66055e0dbc9837914becf1d1ca58d45d1404660de0a11fb63c3", size = 2330507, upload-time = "2026-07-17T03:23:53.22Z" }, + { url = "https://files.pythonhosted.org/packages/b9/10/18bb2d6ed82184e2427f7501a17c1b413eb50bdcd4ebb42bbfb187bb4290/pillow_jxl_plugin-1.3.8-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:fe24e957016dcb0c2ec35f72ff3bb8ae78a9468b282f0d423485556de492975c", size = 2361184, upload-time = "2026-07-17T03:22:58.376Z" }, + { url = "https://files.pythonhosted.org/packages/89/3e/5e1156e5c5b402d84ef924153e046ba937ac46e8b14decb3ab6e01a6f40e/pillow_jxl_plugin-1.3.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d648ef965002bee0c98dbf144b9b3c994146856fa4d3c54008b75dda10f69915", size = 2659163, upload-time = "2026-07-17T03:22:50.003Z" }, + { url = "https://files.pythonhosted.org/packages/e9/fe/e610196142343f80c98502fd204f28e901a1101db6988be6ccc40c0e8ca0/pillow_jxl_plugin-1.3.8-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34685b27d01e55aabb09d9436d4ddb1f446e8805da82ffd6448c07bbf563354c", size = 2787568, upload-time = "2026-07-17T03:22:23.469Z" }, + { url = "https://files.pythonhosted.org/packages/6e/18/a862b140f82be55ce62c681b63c38bf61c962f0c27e32797ebebc0d47548/pillow_jxl_plugin-1.3.8-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:288eb07090c91891ee0dc782786d937af8e53a117835606d7982c29e31072b90", size = 2499957, upload-time = "2026-07-17T03:22:32.414Z" }, + { url = "https://files.pythonhosted.org/packages/59/29/d430cd5f82c08d2950e292d195081e9dd4e2a038a7e1722d79ba7c6e7ed9/pillow_jxl_plugin-1.3.8-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b39ac44cbe5a98b8a364ed98a16c8c1e197ee997e32731be4be727c55e629e4", size = 2504367, upload-time = "2026-07-17T03:22:41.501Z" }, + { url = "https://files.pythonhosted.org/packages/f4/68/6806df96fdd625943c795beca932ac033c255a323b63b051903df96935b6/pillow_jxl_plugin-1.3.8-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0e1550f30768a0aa3f756da10b7807f6fac7fd2e5a18991eb8e00ec5908089d8", size = 9726010, upload-time = "2026-07-17T03:23:08.579Z" }, + { url = "https://files.pythonhosted.org/packages/12/df/d12f42d6e31bb47e2002fcba2db9d92aad19dc3db9ae7d4b2b76152e268a/pillow_jxl_plugin-1.3.8-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:b13f860c280d9d5770f49a1909926f15c6e26e50935da52ecb78700f7c377857", size = 8386305, upload-time = "2026-07-17T03:23:20.983Z" }, + { url = "https://files.pythonhosted.org/packages/92/ee/4dc11ad5a90aa6d2eeae6eb0be2376cde0c365423036a078746b3476eca2/pillow_jxl_plugin-1.3.8-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:273908ffb85f68a2374b0934700939c572f32b355c9d128d4e3b6924e72ef274", size = 9031514, upload-time = "2026-07-17T03:23:32.948Z" }, + { url = "https://files.pythonhosted.org/packages/ae/76/b3125f13c9551862ad3ae7137d86959cde159b759083f3e7b5e720525fd0/pillow_jxl_plugin-1.3.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2be721646718af722f2ca5c1d6b06bf056a61a0db355cf944df53c3723119d4b", size = 9233009, upload-time = "2026-07-17T03:23:44.276Z" }, + { url = "https://files.pythonhosted.org/packages/13/16/1aa669ae22a6c36810a925bbbfb1f4521df1d0402180052331b39ef8dee0/pillow_jxl_plugin-1.3.8-cp313-cp313-win32.whl", hash = "sha256:a2716f1367ed9647da36ce15882a12b4d424892cb5a03ab4b0783039d701c7c2", size = 4551381, upload-time = "2026-07-17T03:24:09.552Z" }, + { url = "https://files.pythonhosted.org/packages/0e/e7/823f58aaea0d969f876f593a39c85c39fefe1b8ee9ca10a6ffbafe1a254a/pillow_jxl_plugin-1.3.8-cp313-cp313-win_amd64.whl", hash = "sha256:2388374b3493df9add4ef3d97cc70d6a5f51ed188dfe10d2b83ebc55e82e48d4", size = 4936720, upload-time = "2026-07-17T03:24:01.9Z" }, + { url = "https://files.pythonhosted.org/packages/3e/12/e04b73832d1b8af3c5c4646127949a362f9ca3d30f42b05156ca5ffc61ea/pillow_jxl_plugin-1.3.8-cp313-cp313-win_arm64.whl", hash = "sha256:48d13d81d1c4933e5d42dd09366a9827583808be0a2fe842abd7358653c7d92f", size = 2330087, upload-time = "2026-07-17T03:23:54.604Z" }, + { url = "https://files.pythonhosted.org/packages/66/30/c37d161345302ebda07f29d8230b15ba83b43c586f14fec98d088b18e982/pillow_jxl_plugin-1.3.8-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:30b72accb8505a46b05f709871da40f09975aea3a6b6f3cb1d646ff0a9aaba5e", size = 2362140, upload-time = "2026-07-17T03:22:59.694Z" }, + { url = "https://files.pythonhosted.org/packages/a7/be/01613af0307c31e77aced40bdf9cf3d25ce1333b3e99bb85575bdcbfeca5/pillow_jxl_plugin-1.3.8-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b5bbc933487207e634802f21990c365b6e61473cea34f6621420f4eda8ffd1df", size = 2660381, upload-time = "2026-07-17T03:22:51.351Z" }, + { url = "https://files.pythonhosted.org/packages/c5/8b/89636d315a31eb805681e60e569fe38d5eef3d09f13b1b6f576574387942/pillow_jxl_plugin-1.3.8-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1d06fd4eb038f431db27f1ab2e483fd6967bafb21a7757e1bd5f76b6fd93649", size = 2787875, upload-time = "2026-07-17T03:22:24.736Z" }, + { url = "https://files.pythonhosted.org/packages/2b/e0/7b9bdc388d89773a5f9ae74ff0be3b06080ef1a60be57b5897d929012622/pillow_jxl_plugin-1.3.8-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f65361ce18db59e8949c60599bfa46b7de187e28917fc39b5d816ab4b81cb16d", size = 2500834, upload-time = "2026-07-17T03:22:33.928Z" }, + { url = "https://files.pythonhosted.org/packages/24/25/0903ba5a4c8d948df9217e48182ff7d872098ddf86fe512402569f4041cc/pillow_jxl_plugin-1.3.8-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b881a40737c647a24270b73cd3f506dd16d634202e5214cb492f9270bd1b02", size = 2504805, upload-time = "2026-07-17T03:22:42.911Z" }, + { url = "https://files.pythonhosted.org/packages/4b/ef/77a15b2f3227854d4ef2563250ea57b03538ed962f406f1248c9caf045aa/pillow_jxl_plugin-1.3.8-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d4049e48f09947a38047fc5d70817c6dffa90ffb5f14585c8c00e8b534d17c9b", size = 9725768, upload-time = "2026-07-17T03:23:10.845Z" }, + { url = "https://files.pythonhosted.org/packages/c6/95/486fc1fabd1e6cb8b520dce9898b51f2e29e991ba54e632381fe7f287300/pillow_jxl_plugin-1.3.8-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:6ce20ef0887efb6dace5245f714f94b4f070ef39a1ec45161b35879c48faf30a", size = 8386447, upload-time = "2026-07-17T03:23:22.87Z" }, + { url = "https://files.pythonhosted.org/packages/05/28/7979927eb5dc79e40b31e4e07d074057722656743d324182f4a68056c2a9/pillow_jxl_plugin-1.3.8-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:845e61add39272ca8545f4a0e6ead977ebb7e89fa017014bb8e17273a7a09c6c", size = 9032664, upload-time = "2026-07-17T03:23:34.78Z" }, + { url = "https://files.pythonhosted.org/packages/92/b7/f606ed6fcb5fd9e177ce2b15a613a405ac22ceafc2c03bb3f58cd500ca04/pillow_jxl_plugin-1.3.8-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:915b8fee6a97aaf5486d0d625f26faae2e9f0d9b5892f1076f5a29b8103125a4", size = 9233868, upload-time = "2026-07-17T03:23:46.277Z" }, + { url = "https://files.pythonhosted.org/packages/a4/6d/d10a4426fc3b394d2222cb694774451e67ab052df2e15a488dfac22be561/pillow_jxl_plugin-1.3.8-cp314-cp314-win32.whl", hash = "sha256:d63d1c3566a8c9ebdd1ec6b75da816b9475d95c4f69656827d6d3957d2594ecb", size = 4554691, upload-time = "2026-07-17T03:24:11.39Z" }, + { url = "https://files.pythonhosted.org/packages/47/77/0f0297c265f1743784b6d1df719e62e49dabd1d9ede8efb0a9ba93174293/pillow_jxl_plugin-1.3.8-cp314-cp314-win_amd64.whl", hash = "sha256:6b23c83aabf4615b92ae609293d8597ca1a8d14d01ab16c703bb3a3df359796b", size = 4939714, upload-time = "2026-07-17T03:24:03.288Z" }, + { url = "https://files.pythonhosted.org/packages/ca/cf/2db398fb1a41c46fd382bad96ee90283589eaed0ec2c50cfe4afda3df72c/pillow_jxl_plugin-1.3.8-cp314-cp314-win_arm64.whl", hash = "sha256:60c36bec3d8d4ef23cf2aed0f792213f999312dd3d8cd5225ae1494c430e16f6", size = 2330667, upload-time = "2026-07-17T03:23:55.913Z" }, + { url = "https://files.pythonhosted.org/packages/58/a6/2e08df50151b3a399ee18b4c8987e25dd754547060d1a368cda4edb2513d/pillow_jxl_plugin-1.3.8-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e33d2b965d4306271ca811dfbb14f8dc313e7bc6408617760fae7ae275686218", size = 2362588, upload-time = "2026-07-17T03:23:01.11Z" }, + { url = "https://files.pythonhosted.org/packages/72/3e/70b1c9c18839b7c6980edb6f4e0c4dd6b52be96df380adf2da55be8e6f7d/pillow_jxl_plugin-1.3.8-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:323ba7ab8fe6aceddbf571853b47c8900a293c6430649be31c3a743b12d0bcfc", size = 2668471, upload-time = "2026-07-17T03:22:52.738Z" }, + { url = "https://files.pythonhosted.org/packages/d5/6f/295bd97058531eee2d3e3a0c73795c95aace572c918d13688201d9f45abd/pillow_jxl_plugin-1.3.8-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:66a1bbe948021af26a5550b9bccad011e1131f6e10a90821690e3c19a417f59b", size = 2793160, upload-time = "2026-07-17T03:22:26.35Z" }, + { url = "https://files.pythonhosted.org/packages/3a/62/74ae963d945cf8c0da64a1a5b1a8e32b49cb1ac8cf3f81e1b63c25466250/pillow_jxl_plugin-1.3.8-pp311-pypy311_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9adee3403a29b42b203b6903923ef84cff70bb33aa6ed069775b6b8f721fe7c7", size = 2506776, upload-time = "2026-07-17T03:22:35.262Z" }, + { url = "https://files.pythonhosted.org/packages/9d/4f/0f00dab8c1b4b026cb62909e01b26a8f12f9f536bb6b002c71a15a638004/pillow_jxl_plugin-1.3.8-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab40c82ead318b058804211a7f6d6e2715f65015f73792dee63813731105f74c", size = 2509592, upload-time = "2026-07-17T03:22:44.31Z" }, + { url = "https://files.pythonhosted.org/packages/53/f6/1ea001b109ff39165e013e663822adba393340d1599e165dbc62f68772a8/pillow_jxl_plugin-1.3.8-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:81864c18c03084754c4a9d673a0ec9d6161af5f7695ab1d4bb112059af2e968b", size = 9732562, upload-time = "2026-07-17T03:23:13.06Z" }, + { url = "https://files.pythonhosted.org/packages/d0/87/1ea5bb4cd84c5be48b542cbb579f43932c7977f5317d9992d674f409377b/pillow_jxl_plugin-1.3.8-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:42f39d55dfb7ba29509cea3f0270bd0e8a2fb924d979f2caa43f445e30d709e5", size = 8392645, upload-time = "2026-07-17T03:23:25.036Z" }, + { url = "https://files.pythonhosted.org/packages/0a/45/1e39b708d0260eb04aeb672558522bea63df4f7df3a9c27710faef0736b6/pillow_jxl_plugin-1.3.8-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:027f091b8ff8ecb26712d709847d25359994eb6a6543736d7fbc07b7b6b86fd7", size = 9039036, upload-time = "2026-07-17T03:23:36.555Z" }, + { url = "https://files.pythonhosted.org/packages/5b/d9/c54bce2efd22f3d79e83fa9948fa5ca0184422c6bd9c38c4d28861ee9a50/pillow_jxl_plugin-1.3.8-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:75351073d967c85c24a330f9e375b17b809bff9779cd08c8d0e90d659b39be5a", size = 9239329, upload-time = "2026-07-17T03:23:48.617Z" }, +] + [[package]] name = "platformdirs" version = "4.9.4"