A native GTK3 image viewer and tag organizer, written in C# for .NET 10.
A companion Firefox extension adds original images and their existing tags from Danbooru and Gelbooru. It supports Firefox 140 and later on Linux desktop.
Install the .NET 10 SDK and GTK3 runtime, then run from this directory:
dotnet build PawprintTagger.slnx
dotnet run --project src/PawprintTagger.Gtk/PawprintTagger.Gtk.csprojThe only external managed dependency is GtkSharp 3.24.24.95. The first restore needs NuGet access. GTK3 must be installed separately
(for example, libgtk-3-0 on Debian/Ubuntu or gtk3 on Arch/Artix).
To use a particular library without changing your saved preference:
dotnet run --project src/PawprintTagger.Gtk/PawprintTagger.Gtk.csproj -- --library /path/to/libraryTo publish an application directory:
dotnet publish src/PawprintTagger.Gtk/PawprintTagger.Gtk.csproj -c Release -o artifacts/PawprintTagger
./artifacts/PawprintTagger/PawprintTaggerThe published application requires the .NET 10 runtime and GTK3. The included
desktop launcher can be installed after placing the published executable on
your PATH.
- Import images… copies selected files into your library. Source files remain untouched. Identical content is detected with SHA-256 and imported once, even when filenames differ. Equal filenames with different contents can coexist. Imports run in the background, report failures per file, and can be cancelled; already imported images remain saved.
- The left tag tree takes 15% of the window width. Create categories with
+ Group, then create tags with + Tag. The equally sized + Tag,
+ Group, Edit, and Delete controls sit below All images.
Selecting a category makes
it the parent of new entries. For example, create
Appearance, thenHairinside it, then the tagBlonde hairinsideHair. - Edit changes an entry's name, parent category, and optional color label. Colors appear in the tree and are inherited by child entries. Turning off an entry's own color restores inheritance. Categories cannot be moved into their descendants. Delete asks before removing an entry and its descendants, and removes their tag assignments from images.
- Selecting a tag filters the gallery to images with that tag. Selecting a category includes images with any of its descendant tags. All images clears the tree filter while keeping the search query.
- Select a thumbnail to see its preview, dimensions, original filename, file size, import date, and tag checklist on the right. The preview section uses 40% of the panel's height and resizes with the window. Check or uncheck tags to save assignments immediately. Categories organize tags; they are not assigned directly to images.
- Double-click a thumbnail or press Enter on it to open an image across the application window. Its aspect ratio is preserved as the window resizes. Back or Escape returns to the gallery; Left/Right or Previous/Next browses the current results.
- Library folder… opens or creates a library at a different location and saves that choice. Each folder is a separate library. Switching folders does not migrate your existing library; to move one, close the app, copy its entire folder to the new location, and open that folder.
The gallery scrolls through all results. Thumbnails are decoded asynchronously, cached on disk, and retained in the grid only near the current viewport. The gallery starts empty; it does not add sample files or tags to your library.
Words match filenames and full tag paths, case-insensitively. Terms are combined with AND. Quote phrases with spaces, or write tag names with underscores. A leading minus excludes a term. The tree selection and search are combined.
While typing, a themed dropdown suggests library tags by name or category path.
Use Up/Down and Enter to choose a suggestion, or click it; Escape dismisses the
dropdown. Choosing a tag completes the term at the cursor and preserves other
search terms, including exclusions such as -tag:. Suggestions also work with
booru underscores and quoted names, and update when tags are added, edited, or
imported. Filename and numeric fields keep their normal behavior.
| Query | Matches |
|---|---|
Blonde_hair |
Filename or tag path containing “blonde hair” |
tag:"Blonde hair" |
An assigned tag path containing “blonde hair” |
tag:Appearance/Hair |
Tags within this path |
file:holiday -tag:portrait |
Holiday filenames without portrait tags |
ext:png width:>=1920 height:>1080 |
PNGs meeting both dimension constraints |
is:untagged |
Images without assigned tags |
size:<1048576 |
Files smaller than 1 MiB |
Inside quoted values, use \" for a literal quotation mark and \\ for a
literal backslash. Tag suggestions insert the required quoting automatically.
name: is an alias for file:. Numeric fields accept =, >, >=, <,
and <=; a bare number means equality. The ? button shows help in the app.
Use Ctrl+F to focus search and Ctrl+O to import images.
The initial library is Pictures/PawprintTagger in your home folder. Your saved
library choice is in $XDG_CONFIG_HOME/pawprint-tagger/settings.json, or
~/.config/pawprint-tagger/settings.json when XDG_CONFIG_HOME is unset.
PawprintTagger/
library.json # Versioned image metadata, categories, tags and assignments
images/ # Owned image copies with collision-resistant filenames
thumbnails/ # Rebuildable PNG thumbnails
.pawprint.lock # Prevents two instances writing to the same library
Metadata writes use a temporary file followed by an atomic replacement. Failed
writes leave the previous catalog and in-memory state intact. An invalid catalog
is reported without resetting it. Back up library.json and images/ together.
You can clear thumbnails/ while the application is closed to reclaim cache
space; thumbnails will be rebuilt.
Image support depends on installed GdkPixbuf loaders. Common GTK installations support PNG, JPEG, GIF, BMP and TIFF; other formats depend on your system. GIF and other animated images currently display a static frame. JPEG embedded orientation is applied to previews and the viewer. Full-window viewing fits the image to the window; zoom and animated playback are not implemented yet.
The test executable has no additional test framework dependencies:
dotnet run --project tests/PawprintTagger.Tests/PawprintTagger.Tests.csprojIt checks original preservation, duplicates and filename collisions, tag editing and persistence, category filtering, search syntax, tag suggestions and completion, Unicode and escaped names, cancellation, write failures, damaged catalogs, library locking, settings, booru tag/source imports, original checksums, native-message framing, active-library routing, and closed-app browser imports. It creates isolated temporary libraries and does not touch your saved library.
For the native GTK check, run in a graphical desktop session:
G_DEBUG=fatal-criticals dotnet run --project tests/PawprintTagger.Tests/PawprintTagger.Tests.csproj -- --gtk-smokeThis creates real image fixtures and checks import controls, tag checkboxes,
thumbnails, tag suggestions while typing and keyboard selection, category/search
filtering, image activation, viewing after resize,
Back, empty results, GTK cleanup, and bounded thumbnail retention while
scrolling a 182-image library, plus browser imports into the active window.
Optionally set
PAWPRINT_SCREENSHOT=/tmp/pawprint-tagger.png to capture
the test window. On a headless machine, run the command under xvfb-run if Xvfb
is installed.
Source is separated into a UI-independent PawprintTagger.Core library, the
PawprintTagger.Gtk application, and integration checks. The example/ project
is reference material and is not part of the new solution.