Files
pholio/README.md
T
chris.giteaandClaude Opus 5.5 06e396b153 feat(credits): render the credits from a single markdown file
src/main/resources/userguide/credits.md now lists every shipped library
with its license (read from the dependencies' POMs), the recognition models
and the map and place data. CreditsView, opened from the ? in Settings,
renders it through the new MarkdownPage helper (per-language loading, links
opened in the browser), which the search help popup now shares, and the
release's distrib step copies it to distrib/CREDITS.md in the same commit
as the release note.

MarkdownToBBCode learns [text](url) links, inside bold too. URLs are quoted
in the generated BBCode: AtlantaFX's parser reads a tag ending in "/]" as
self-closing, so a URL with a trailing slash broke the whole page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011xpLSeYKKHX6o16jzYLgZv
2026-09-30 15:27:51 -04:00

7.2 KiB
Raw Blame History

Pholio

Pholio is a desktop application for managing large photo and video libraries, built for volume and speed.

  • Libraries — point Pholio at one or more folders; it indexes every photo and video into its own embedded database, one per library, and keeps it in sync as files change.
  • Gallery — a justified, date-grouped grid that stays fluid on tens of thousands of files, with a full-screen photo view and an info panel for the selected file.
  • Metadata — reads EXIF, IPTC and XMP (RAW, HEIF and video included), edits capture date, location and rating, and writes them back to the file itself.
  • Places — offline reverse geocoding from a bundled GeoNames dataset, plus optional online place search (LocationIQ).
  • People — local face and animal detection and clustering (ONNX Runtime, nothing leaves the machine); naming a person makes their photos searchable.
  • Search — free text, rating (r:4+), people (p:Alice) and folder (path:Holidays/2024) filters, combined freely — see the in-app guide (the ? next to the search bar) or src/main/resources/userguide.
  • Command line — the same binary runs headless: pholio scan <dir> reports the media files a folder holds.

Built with Java 26, JavaFX (AtlantaFX, GemsFX, Ikonli), Spring Boot, H2, PicoCLI and metadata-extractor.

Build and run

Requirements: a JDK 26 that bundles JavaFX (e.g. Azul Zulu FX 26). Maven comes with the wrapper.

./mvnw verify                      # compile, test, build target/pholio.jar
java -jar target/pholio.jar --ui   # desktop interface
java -jar target/pholio.jar scan ~/Pictures [-R]   # headless scan; -R: do not recurse
java -jar target/pholio.jar -V     # version
java -jar target/pholio.jar        # usage, same as --help

Pholio runs headless by default: only --ui opens the window, so every launcher meant to show one (IDE run configuration, installers) passes it. Any argument Pholio does not recognise is read as a command.

Development

JVM options (-D…)

Option Default Effect
--enable-native-access=javafx.graphics,ALL-UNNAMED — Not a property, but recommended: silences the restricted-method warnings from JavaFX, JNA and the macOS process naming.
-Dpholio.home=<dir> OS user dirs Puts configuration, data (libraries) and cache under one root — keeps a test run out of your real profile.
-Dpholio.skipTheme=true false Starts without the AtlantaFX theme, on JavaFX's default styling (to tell a theme issue from a layout one).
-Dpholio.modalBackend=dialogPane stage Shows dialogs in GemsFX's embedded DialogPane instead of a separate window.
-Djavafx.enablePreview=true set by the app Required for the JavaFX HeaderBar preview API; GuiBootstrap sets it unless you pass a value.
-Dprism.dirtyopts=false set by the app Works around a stale-paint bug in Prism; GuiBootstrap sets it unless you pass a value.

Application settings (--pholio.…= arguments)

Spring Boot settings from application.yaml, overridable on the command line (they bypass PicoCLI, so they never read as a command):

Setting Default Effect
--pholio.dev-tools.enabled= true F12 opens the DevToolsFX scene-graph inspector.
--pholio.library.routing.enabled= true Routes the database to the library picked in the header; false pins spring.datasource.url.
--pholio.pools.cpu= 0 Threads for decoding work (thumbnails, hashes); 0 = cores − 1.
--pholio.pools.scheduler= 2 Scheduler threads.
--pholio.window.default-width= / default-height= 1440 / 900 First-run window size.
--logging.level.org.icroco.pholio= DEBUG Log level of Pholio's own code.

What makes the jar big

target/pholio.jar is ~223 MB, 89 libraries. Almost all of it is recognition: the application's own code is under 1 MB.

Size (in the jar) Entry Why
130.5 MB onnxruntime-1.21.1.jar ONNX Runtime with native libraries for 5 platforms (~590 MB unpacked, win-x64 alone 351 MB). The installers keep only their own platform's — see below.
34.2 MB models/recognition/face_recognition_sface_2021dec.onnx Face embedding model (SFace).
10.2 MB geodata/cities1000.txt.gz GeoNames seed for offline reverse geocoding, imported into H2 on first run.
4.4 MB byte-buddy Runtime agent behind @FxThread.
3.2 MB models/recognition/yolox_nano.onnx Animal detection model.
3.0 MB gemsfx UI controls.
2.6 MB h2 Embedded database.
≤ 2 MB each Spring, Jackson, JNA, AtlantaFX themes, … The remaining ~30 MB.

Deliberately left out of the jar (pom.xml): Lombok and Jilt (compile-time only), the OpenJFX jars (every target runtime already has JavaFX as modules), and the JUnit/AssertJ that devtoolsfx wrongly declares at compile scope.

The native installers go further (distrib/packaging/common.sh): only the target platform's ONNX Runtime natives (130 MB → ~24 MB for macOS arm64) and a jlink'ed runtime (~64 MB) — the macOS arm64 .dmg is ~157 MB.

To re-measure: unzip -v target/pholio.jar | sort -k3 -n -r | head -20 (third column: compressed size).

Credits

src/main/resources/userguide/credits.md is the single list of credits — shipped libraries with their licenses, recognition models, map and place data. The application shows it from the ? in Settings (CreditsView), and each release copies it to distrib/CREDITS.md. Add a library or data source there when you add one to the application.

Useful scripts

  • python3 tools/icons/make-macos-icon.py — regenerates the macOS icon, icon.png and pholio.icns from src/main/resources/images/spo-1024x1024.png.
  • python3 tools/demo/fetch-commons-photos.py <dir> [--quality] [--places Paris Kyoto …] [--per-place N] — downloads a demo library for screenshots from Wikimedia Commons: freely licensed JPEG originals whose own EXIF has a capture date and GPS, one folder per city, with a CREDITS.md (CC BY / BY-SA require the credit wherever the photos are shown). --quality keeps only Commons' Quality/Featured pictures — nicer, fewer, slower. --help for every option.

Release

./mvnw -Prelease validate

Needs a clean working tree (or -Drelease.allowDirty=true) and a logged-in GitHub CLI (gh auth login). In order, it:

  1. bumps the version to YYYY.M.N — same month as the current version: N + 1, otherwise build 0 of the current month;
  2. runs a fresh ./mvnw verify;
  3. writes distrib/release_note/release-note-<version>.md from the Conventional Commits since the previous release (grouped by type, then scope);
  4. creates GitHub release v<version> in Imag-In/Pholio with the jar, its SHA-256 and the release note;
  5. commits pom.xml and tags v<version> locally;
  6. commits the release note in distrib/ and pushes it.

The source repository itself is never pushed to GitHub: Imag-In/Pholio only receives release assets and the distrib/ worktree (an orphan branch), and a local pre-push hook enforces it. See AGENTS.md for the details, and keep commit messages in the Conventional Commits format so they reach the release note.