No description
  • Python 96.9%
  • Shell 1.8%
  • PowerShell 1.3%
Find a file
Grok c283d44b1b
All checks were successful
CI / lint (push) Successful in 11s
CI / test (push) Successful in 2m22s
CI / windows-exe (push) Successful in 12m31s
CI / build-windows-exe (push) Successful in 0s
CI / appimage (push) Successful in 13m43s
CI / build-appimage (push) Successful in 0s
feat: Grid viewer crop and mirror tools (0.4.0, issue #147) (#150)
## Summary

Implements issue #147: crop and horizontal mirror tools in the Grid image viewer, released as **0.4.0**.

- Dynamic toolbar when opening the viewer from Grid (thumbnail slider hidden): **Rotate 90°**, mirror (`< >`), **Crop**, aspect presets, **↻** rotate crop selection, **Accept**
- Interactive crop overlay (corner/edge handles, dimmed exterior, directional cursors, free or fixed aspect)
- Enter/Accept applies crop with backup under workspace `.originals/` (skipped by scans); session undo/redo restores or re-applies and refreshes thumbnails/viewer
- Settings: default crop aspect; optional purge of `.originals` on workspace close/exit
- Docs: USER_GUIDE, DESIGN, TECHNICAL_OUTLINE, DR-033, CHANGELOG for 0.4.0

## Test plan

- [x] `pytest tests/test_viewer_crop_mirror.py` (21 tests)
- [x] `ruff check` / `ruff format --check`
- [x] `./scripts/check-version-bump.sh origin/main`
- [ ] Manual: open image from Grid → mirror, crop free/fixed aspect, Accept, undo/redo, Esc cancel
- [ ] Manual: crop with border near image edge; aspect **None** keeps selection; purge `.originals` setting

Closes #147

Co-authored-by: Grok <grok@devstation.vglan>
Reviewed-on: #150
2026-07-18 16:16:31 +00:00
.forgejo/ISSUE_TEMPLATE Update .forgejo/ISSUE_TEMPLATE/feature.yaml 2026-06-09 05:29:45 +00:00
.github/workflows ci: harden tag-ref detection for workflow_dispatch canonical releases (#132) 2026-06-22 13:39:16 +00:00
.grok/agents docs(agents): codify disciplined development practices for agents 2026-05-31 22:35:05 -07:00
docs feat: Grid viewer crop and mirror tools (0.4.0, issue #147) (#150) 2026-07-18 16:16:31 +00:00
resources feat: Grid viewer crop and mirror tools (0.4.0, issue #147) (#150) 2026-07-18 16:16:31 +00:00
scripts feat(grid): add Reveal in Filesystem to the grid context menu (#116) (#144) 2026-06-25 06:26:49 +00:00
src/bulk_image_organizer feat: Grid viewer crop and mirror tools (0.4.0, issue #147) (#150) 2026-07-18 16:16:31 +00:00
tests feat: Grid viewer crop and mirror tools (0.4.0, issue #147) (#150) 2026-07-18 16:16:31 +00:00
.gitignore docs: document Forgejo MCP server usage, keep local URL out of repo (#97) 2026-06-17 01:45:55 +00:00
AGENTS.md fix(ci): refactor release pipeline triggers, naming, and cleanup (#103) (#104) 2026-06-19 16:04:07 +00:00
CHANGELOG.md feat: Grid viewer crop and mirror tools (0.4.0, issue #147) (#150) 2026-07-18 16:16:31 +00:00
CLAUDE.md docs: document Forgejo MCP server usage, keep local URL out of repo (#97) 2026-06-17 01:45:55 +00:00
DEVELOPMENT.md Canonical cross-platform release artifacts and CI refactor (fixes #62) (#75) 2026-06-13 06:21:31 +00:00
LICENSE docs: Polish README and design docs; switch to MIT-only license 2026-06-08 18:32:05 -07:00
pyproject.toml feat(settings): configurable image types filter (issue #28 / DR-019) (#42) 2026-06-11 17:50:28 +00:00
README.md feat: Grid viewer crop and mirror tools (0.4.0, issue #147) (#150) 2026-07-18 16:16:31 +00:00
VERSION feat: Grid viewer crop and mirror tools (0.4.0, issue #147) (#150) 2026-07-18 16:16:31 +00:00

Bulk Image Organizer

A fast, keyboard-centric desktop application for power users who need to review, tag, deduplicate, and organize large batches of images—1,000 to 10,000 or more—in a single directory tree.

Everything stays on your machine. Tags and staging for deletion replace destructive edits until you explicitly confirm. Duplicate detection is ad-hoc—you run it when you need it. The filesystem is always the source of truth; a portable cache database beside your images keeps thumbnails and metadata fast.

Supported formats: JPEG, PNG, WEBP, TIFF, GIF, BMP (HEIC/HEIF not supported). Subsets can be enabled/disabled globally in Settings → Image Types; disabled formats are ignored by scans.

Platforms: Windows 11 and Linux (tested on Linux Mint)


Why Bulk Image Organizer?

Large photo dumps, wallpaper collections, and download folders are painful to triage in a file manager. Bulk Image Organizer is built for that workflow:

  • Non-destructive by default — Tag images or stage them for deletion; nothing hits the recycle bin until you confirm.
  • Responsive at scale — Background scanning and lazy thumbnails keep the UI usable while tens of thousands of files are indexed.
  • Tag-driven organization — Filter, sort, bulk-assign, and eventually sort into folders by tag.
  • Ad-hoc duplicate tools — Exact and perceptual duplicate scans on demand.
  • Keyboard-first — Customizable shortcuts across grid, viewer, duplicates, and trash workbenches.

Features

Grid workbench

  • Recursive directory scan with progressive thumbnail loading
  • Adjustable thumbnail size (display scale and cache resolution in Settings)
  • Multi-select, sorting (filename, date, size, resolution, tag priority), and rich tag filtering (AND/OR, untagged-only, hide staged deletions, horizontal/vertical orientation)
  • Tag badges on thumbnails; prominent red overlay on images staged for deletion
  • Session undo/redo for tag assignment and deletion staging (Ctrl+Z / Ctrl+Y)

Image viewer

  • Full-resolution zoom, pan, fit/fill, and 1:1 modes
  • Carousel and filmstrip navigation (global preferences)
  • Rotation saved to the image file after a short debounce
  • From Grid: horizontal mirror and interactive crop (aspect presets, undoable; originals backed up under .originals/)
  • Quality metadata overlay to compare similar shots
  • Background preloading of adjacent images for smooth prev/next

Tagging

  • Unlimited custom tags per workspace, with fourteen preset colors (including black and white) or a custom picker
  • New Tag and Bulk Create in the right column — bulk mode accepts one name per line with per-line colors or inline {#rrggbb} hex suffixes
  • Single-click toggles tags on the current selection; creation requires an open directory
  • Stage images for deletion to review them later in the Trash workbench
  • Sort into Folders… moves images that have exactly one non-duplicate tag into subfolders named after that tag

Duplicates workbench

Duplicate detection is ad-hoc. When you run a scan:

  • Exact duplicates — Full-file cryptographic hash (F-DUPE_# tags)
  • Visual duplicates — Perceptual hash with configurable similarity (V-DUPE_# tags)

Review groups in a comparison grid or single-image viewer. Keep Best stages lower-quality copies for deletion and advances to the next group. Duplicate membership is ordinary tags—you can rename, recolor, or remove them like any other tag.

Trash workbench

  • Review everything staged for deletion without grid overlays
  • Confirm Delete sends displayed rows to the system recycle bin via send2trash
  • Filter-scoped Clear Deleted Flag and Unset Applied Tags

Settings & help

  • Dark and light themes
  • Customizable global keyboard shortcuts
  • Startup, tag-filter defaults, thumbnail cache, duplicate defaults, viewer modes, and advanced tunables
  • Bundled user guide and About dialog inside the app

Data & privacy

  • All processing is local; no network features
  • Local folders: .bulk_image_organizer.db lives beside your images and travels with the folder
  • Network folders: Thumbnails stay on your computer; tags and metadata can optionally sync to a lightweight database on the share when you close the workspace

Quick start

Run a packaged build

Linux — Extract a release tarball, then run the bulk_image_organizer binary inside.

Windows — Run bulk_image_organizer.exe. On first launch, Nuitka unpacks into %LOCALAPPDATA%\ValleyGeek\Bulk Image Organizer\.

Run from source

git clone <repository-url>
cd bulk-image-organizer

python -m venv .venv
source .venv/bin/activate   # Linux/macOS
# .venv\Scripts\activate    # Windows

pip install -e ".[dev]"
python -m bulk_image_organizer

On Linux, ./scripts/launch-linux.sh sets up the virtual environment, installs dependencies if needed, and configures Qt platform plugins.


Basic workflow

  1. Open a directory (Ctrl+O) — The app scans in the background and fills the grid as thumbnails are ready.
  2. Tag and filter — Create tags with New Tag, Bulk Create, or Create from Sub-directories in the right column; use Tag Filter on the sub-toolbar to narrow the grid.
  3. Review in the viewer — Double-click or press Enter; use arrow keys, carousel, or filmstrip to move through images.
  4. Find duplicates (optional) — Switch to Duplicates, run an exact or visual scan, review groups, and use Keep Best.
  5. Clean up — Stage rejects for deletion, review them in Trash, then confirm delete to send files to the recycle bin.
  6. Organize — Use Sort into Folders… for images with a single tag.

Default shortcuts and full workbench details are in the in-app Help guide (resources/help/USER_GUIDE.md).


Building releases

Linux — AppImage (BulkImageOrganizer_{version}.AppImage) or standalone folder under build/linux/:

./scripts/build-linux-appimage.sh
./scripts/build-linux.sh

Windows — single executable in an output directory (BulkImageOrganizer_{version}.exe):

scripts\manual-build-windows.ps1 -OutputPath C:\builds

CI runs lint and tests first, then parallel Linux AppImage and Windows release jobs. main publishes versioned Forgejo releases (v{version}) with both .AppImage and .exe artifacts; development branches publish dev-{branch-slug} releases with branch-named artifacts that are pruned when the branch is deleted. Versioning policy: docs/VERSIONING.md. See DEVELOPMENT.md for local validation, test layout, and contributor workflow.

Security scanning

Nuitka-compiled binaries (especially Windows .exe files) are sometimes flagged by antivirus software as false positives due to how compiled Python code is structured. Both release CI jobs scan their build artifact before publishing it, so you can verify a release independently of that risk:

  • ClamAV scans the artifact after it's built; a detection fails the build, so a published release was never flagged by ClamAV's signature database at build time.
  • Static analysis runs checksec/readelf/file on the Linux AppImage and an Authenticode signature check + PE section/entropy dump (via pefile) on the Windows executable. This is informational only and never fails the build.
  • VirusTotal (optional — only runs when the VT_API_KEY secret is configured) uploads the artifact for a multi-engine scan and links the report. Also informational only.

Each job's summary (visible on the workflow run page) includes the artifact's SHA256 hash and the scan results — compare the hash against what you downloaded, and check the summary before trusting a build if you're unsure. The scanning logic lives in scripts/security-scan-artifact.py and scripts/virustotal-scan.py.


Development

ruff check .
ruff format --check .
pytest

Architecture, design decisions, and the implementation history live in docs/DESIGN.md, docs/TECHNICAL_OUTLINE.md, and docs/DECISIONS.md.


License

MIT License. You may use, modify, and distribute this software freely. Redistributions and derivative works must include the original copyright notice and license text, attributing Bulk Image Organizer to its authors.