Commit Graph

127 Commits

Author SHA1 Message Date
8d754017fa Clean up low-severity code quality issues
- Share IMAGE_EXTENSIONS between discovery.rs and watcher.rs (DRY)
- Extract compute_renamed_path() to deduplicate ~100 lines in executor
- Extract estimate_text_dimensions() to deduplicate watermark calc (3 copies)
- Fix encoder fallback defaults: WebP 85, AVIF 63 (match QualityPreset::High)
- Extract watch_config_dir() and load_watches() helpers in CLI (4 copies)
- Remove redundant else branches after unwrap_or_default()
- Rename misleading chrono_timestamp() to unix_timestamp()
2026-03-08 00:22:24 +02:00
7e5d19ab03 Fix 12 medium-severity bugs across all crates
- Escape backslashes in Nautilus preset names preventing Python injection
- Fix tiled watermarks starting at (spacing,spacing) instead of (0,0)
- Fix text watermark width overestimation (1.0x to 0.6x multiplier)
- Fix output_dpi forcing re-encoding for metadata-only presets
- Fix AVIF/WebP compression detection comparing against wrong preset values
- Add shared batch_updating guard for Ctrl+A/Ctrl+Shift+A select actions
- Fix overwrite conflict check ignoring preserve_directory_structure
- Add changes_filename()/changes_extension() for smarter overwrite checks
- Fix watch folder hardcoding "Blog Photos" preset
- Fix undo dropping history for partially-trashed batches
- Fix skipped files inflating size statistics
- Make CLI watch config writes atomic
2026-03-07 23:35:32 +02:00
1a174d40a7 Fix 5 deferred performance/UX issues from audit
M8: Pre-compile regex once before rename preview loop instead of
recompiling per file. Adds apply_simple_compiled() to RenameConfig.

M9: Cache font data in watermark module using OnceLock (default font)
and Mutex<HashMap> (named fonts) to avoid repeated filesystem walks
during preview updates.

M12: Add 150ms debounce to watermark opacity, rotation, margin, and
scale sliders to avoid spawning preview threads on every pixel of
slider movement.

M13: Add 150ms debounce to compress per-format quality sliders (JPEG,
PNG, WebP, AVIF) for the same reason.

M14: Move thumbnail loading to background threads instead of blocking
the GTK main loop. Each thumbnail is decoded via image crate in a
spawned thread and delivered to the main thread via channel polling.
2026-03-07 23:11:00 +02:00
9fcbe237bd Fix 16 medium-severity bugs from audit
CLI: add UTC suffix to timestamps, validate image extensions on
single-file input, canonicalize watch paths for reliable matching,
derive counter_enabled from template presence, warn when undo count
exceeds available batches.

Core: apply space/special-char transforms in template rename path,
warn on metadata preservation for unsupported formats, derive AVIF
speed from compress preset quality level.

GTK: use buffer size for apples-to-apples compress preview comparison,
shorten approximate format labels, cache file sizes to avoid repeated
syscalls on checkbox toggle, add batch-update guard to prevent O(n^2)
in select/deselect all, use widget names for reliable progress/log
lookup, add unique suffix for duplicate download filenames.
2026-03-07 23:02:57 +02:00
9ef33fa90f Fix CLI/GTK history timestamp format mismatch
CLI now stores Unix seconds (matching GTK) so age-based history
pruning works correctly. Human-readable formatting applied only
at display time in cmd_history and cmd_undo.
2026-03-07 22:35:25 +02:00
e65ed866eb Fix 5 high-risk bugs from 13th audit pass
- cleanup_placeholder now removes 1-byte marker files on error (regression)
- {width}/{height} template vars replaced with "0" when dimensions unavailable
- Text watermark width multiplier 0.6->1.0 to prevent CJK/wide char clipping
- cmd_undo preserves history entries when trash operations fail
- cmd_watch_remove exits on write failure instead of silent discard
2026-03-07 22:27:37 +02:00
d1cab8a691 Fix 40+ bugs from audit passes 9-12
- PNG chunk parsing overflow protection with checked arithmetic
- Font directory traversal bounded with global result limit
- find_unique_path TOCTOU race fixed with create_new + marker byte
- Watch mode "processed" dir exclusion narrowed to prevent false skips
- Metadata copy now checks format support before little_exif calls
- Clipboard temp files cleaned up on app exit
- Atomic writes for file manager integration scripts
- BMP format support added to encoder and convert step
- Regex DoS protection with DFA size limit
- Watermark NaN/negative scale guard
- Selective EXIF stripping for privacy/custom metadata modes
- CLI watch mode: file stability checks, per-file history saves
- High contrast toggle preserves and restores original theme
- Image list deduplication uses O(1) HashSet lookups
- Saturation/trim/padding overflow guards in adjustments
2026-03-07 22:14:48 +02:00
adef810691 Fix 30 critical and high severity bugs from audit passes 6-8
Critical fixes:
- Prevent path traversal via rename templates (sanitize_filename)
- Prevent input == output data loss (paths_are_same check)
- Undo now uses actual executor output paths instead of scanning directory
- Filter empty paths from output_files (prevents trashing CWD on undo)
- Sanitize URL download filenames to prevent path traversal writes

High severity fixes:
- Fix EXIF orientation 5/7 transforms per spec
- Atomic file creation in find_unique_path (TOCTOU race)
- Clean up 0-byte placeholder files on encoding failure
- Cap canvas padding to 10000px, total dimensions to 65535
- Clamp crop dimensions to minimum 1px
- Clamp DPI to 65535 before u16 cast in JPEG encoder
- Force pixel path for non-JPEG/TIFF metadata stripping
- Fast path now applies regex find/replace on rename stem
- Add output_dpi to needs_pixel_processing check
- Cap watermark image scale dimensions to 16384
- Cap template counter padding to 10
- Cap URL download size to 100MB
- Fix progress bar NaN when total is zero
- Fix calculate_eta underflow when current > total
- Fix loaded.len()-1 underflow in preview callbacks
- Replace ListItem downcast unwrap with if-let
- Fix resize preview division by zero on degenerate images
- Clamp rename cursor position to prevent overflow panic
- Watch mode: skip output dirs to prevent infinite loop
- Watch mode: drop tx sender so channel closes on exit
- Watch mode: add delay for partially-written files
- Watch mode: warn and skip unmatched files instead of wrong preset
- Clean temp download directory on app close
- Replace action downcast unwrap with checked if-let
- Add BatchResult.output_files for accurate undo tracking
2026-03-07 20:49:10 +02:00
b432cc7431 Fix 26 bugs, edge cases, and consistency issues from fifth audit pass
Critical: undo toast now trashes only batch output files (not entire dir),
JPEG scanline write errors propagated, selective metadata write result returned.

High: zero-dimension guards in ResizeConfig/fit_within, negative aspect ratio
rejection, FM integration toggle infinite recursion guard, saturating counter
arithmetic in executor.

Medium: PNG compression level passed to oxipng, pct mode updates job_config,
external file loading updates step indicator, CLI undo removes history entries,
watch config write failures reported, fast-copy path reads image dimensions for
rename templates, discovery excludes unprocessable formats (heic/svg/ico/jxl),
CLI warns on invalid algorithm/overwrite values, resolve_collision trailing dot
fix, generation guards on all preview threads to cancel stale results, default
DPI aligned to 0, watermark text width uses char count not byte length.

Low: binary path escaped in Nautilus extension, file dialog filter aligned with
discovery, reset_wizard clears preset_mode and output_dir.
2026-03-07 19:47:23 +02:00
270a7db60d Fix step indicator layout warnings on narrow windows 2026-03-06 18:44:41 +02:00
4f23d25511 Add AppImage packaging, app icon, and AppStream metainfo 2026-03-06 18:31:18 +02:00
704f556867 Add EXIF auto-orient and aspect ratio lock toggle
- Implement auto_orient_from_exif() that reads EXIF Orientation tag
  and applies the correct rotation/flip for all 8 EXIF orientations
- Add aspect ratio lock toggle to resize step Width/Height mode
- When lock is active, changing width auto-calculates height from
  the first loaded image's aspect ratio, and vice versa
- Uses recursive update guard (Cell<bool>) to prevent infinite loops
2026-03-06 18:18:04 +02:00
0a7a6ee95c Implement watermark rotation for text and image watermarks
- Add rotate_watermark_image() using imageproc rotate_about_center
  for 45/-45 degree rotations and image::rotate90 for 90 degrees
- Add render_text_to_image() helper that renders text to a
  transparent buffer for rotation before compositing
- Apply rotation to single text, tiled text, single image, and
  tiled image watermark modes
- Fix tiled image watermark to use actual overlay dimensions
  (which change after rotation) instead of pre-rotation values
2026-03-06 18:14:53 +02:00
a666fbad05 Fix pipeline order, add selective metadata stripping, rename case/regex
- Move watermark step after compress in processing pipeline to match
  design doc order (resize, adjustments, convert, compress, metadata,
  watermark, rename)
- Implement selective EXIF metadata stripping for Privacy and Custom
  modes using little_exif tag filtering (GPS, camera, software,
  timestamps, copyright categories)
- Add case conversion support to rename (none/lower/upper/title)
- Add regex find-and-replace on original filenames
- Wire case and regex controls in rename step UI to JobConfig
- Add regex crate dependency to pixstrip-core
2026-03-06 18:12:18 +02:00
5104d66aaf Add EXIF-based rename template variables
Support {date}, {exif_date}, {camera}, and {original_ext} in rename
templates. Reads DateTimeOriginal and Model from EXIF metadata via
little_exif when these variables are used in templates.
2026-03-06 18:03:12 +02:00
5352b67887 Add thumbnail re-render preview to resize step
Shows an actual resized thumbnail alongside the dimension rectangle
visualization. Updates live when width/height values change.
2026-03-06 17:56:44 +02:00
e2aee57bd9 Integrate watch folder monitoring into GTK app
Active watch folders from settings are now monitored using the notify
crate. When new images appear, they are automatically processed using
the folder's linked preset. Toast notifications inform the user.
2026-03-06 17:53:41 +02:00
afabdf3548 Persist advanced options expand/collapse state per section
Each ExpanderRow now remembers its expanded state between sessions
using a per-section key stored in SessionState. Replaces the global
detailed_mode toggle with granular per-section persistence.
2026-03-06 17:49:07 +02:00
d8bb1a726a Add watermark tiling, rotation types, margin/scale controls
Wire tiled, margin, and scale UI controls to JobConfig and pass
through to WatermarkConfig. Add tiled text and image watermark
implementations that repeat across the full image. Add font family
filesystem search for named fonts. Add WatermarkRotation enum.
2026-03-06 17:36:07 +02:00
45247cdac5 Add collapsible watch folders panel in main window
Toggle button in the header bar reveals a bottom panel showing active
watch folders with their linked presets and watching status. The add
button opens Settings for full watch folder configuration.
2026-03-06 17:29:02 +02:00
0460763d42 Add fixed output folder option in settings
Users can now choose between subfolder-next-to-originals or a fixed
output folder in Settings > General. The fixed path is selectable via
a folder picker dialog and persisted across sessions.
2026-03-06 17:23:57 +02:00
fbb9cddbb8 Add PNG DPI support via pHYs chunk and fix font picker
PNG files now embed pHYs chunk for DPI when output_dpi is set, matching
the existing JPEG DPI support. Also fixed FontDialogButton signal handler
to properly unwrap the Option<FontDescription>.
2026-03-06 17:16:43 +02:00
d9ce1f8731 Add font family selector for watermark text
Font picker using GTK FontDialog/FontDialogButton lets users choose
any installed system font for text watermarks. The selected font family
is passed through the processing pipeline and used to find the matching
font file on disk.
2026-03-06 17:12:23 +02:00
3109f97786 Add overwrite confirmation dialog and preset file drop import
- When overwrite behavior is "Ask", show dialog before processing
  listing conflicting files with Overwrite/Skip/Auto-rename options
- Workflow page accepts .pixstrip-preset file drag-and-drop for import
- Split run_processing into two phases to support async dialog
2026-03-06 17:07:53 +02:00
f8fd073735 Add drag-and-drop import for .pixstrip-preset files
- Workflow page accepts .pixstrip-preset file drops
- Dropped preset files are imported and applied to current config
- Saved to user presets automatically on successful import
2026-03-06 17:06:02 +02:00
0ceec7eec4 Add preset export/delete buttons and single-instance support
- User preset rows now have export and delete action buttons
- Export opens file save dialog for .pixstrip-preset files
- Delete removes preset from storage and UI
- Single-instance via GIO HANDLES_OPEN for file manager integration
- Screen reader announcements on step navigation
2026-03-06 17:04:18 +02:00
683422f8f5 Improve screen reader support for wizard navigation
- Announce step number and name when navigating between steps
- Add accessible label to batch queue toggle button
- Add accessible label to navigation view with shortcut hint
- Step transitions update accessible property for screen readers
2026-03-06 17:02:04 +02:00
b9775d5632 Add single-instance file handling via GIO HANDLES_OPEN
- App flag HANDLES_OPEN enables receiving files from file manager
- connect_open handler filters for image files and activates window
- load-external-files action receives paths and adds to loaded files
- Auto-navigates to step 2 (images) when files arrive externally
- Second instance sends files to existing window instead of launching
2026-03-06 16:58:23 +02:00
a7dda7ad6f Enhance history dialog with expandable details and DPI support
- History entries now use ExpanderRow with detailed sub-rows
- Show formatted timestamp, input/output directories, size breakdown
- Clickable output directory row opens file manager
- Per-entry undo and open folder action buttons
- Error count shown for batches with failures
2026-03-06 16:56:23 +02:00
1ab21307d6 Apply output DPI to JPEG files via mozjpeg pixel density
- Add output_dpi field to EncoderOptions
- Set JFIF pixel density header in JPEG output when DPI > 0
- Wire output_dpi from ProcessingJob through to encoder in both
  parallel and sequential execution paths
2026-03-06 16:53:32 +02:00
5a56e25c2c Add sequential batch queue processing
- After a batch completes, automatically start next pending batch
- Mark completed/failed batches in queue with correct status
- Failed batches don't block the queue - next pending batch starts
- Queue processes batches in order, one at a time
2026-03-06 16:17:25 +02:00
a0bb00eddf Add Watch Folders settings page with full CRUD
- New settings page: Watch Folders with add/remove/edit controls
- Each watch folder has: path, linked preset dropdown, recursive toggle,
  active/inactive switch, and remove button
- Watch folder config persisted in AppConfig
- Empty state message when no folders configured
2026-03-06 16:13:14 +02:00
e976ca2c0a Add rename template presets and watermark color picker
- Rename step: quick-fill buttons for common patterns (Date+Name,
  EXIF Date+Name, Sequential, Dimensions, Camera+Date, Web-safe)
- Watermark step: color picker in advanced options using ColorDialogButton
- Add watermark_color field to JobConfig, wire through to core
2026-03-06 16:10:05 +02:00
45aaa02f19 Add URL drag-and-drop support for images from web browsers
Users can now drag image URLs from web browsers into the image
step. URLs ending in common image extensions are downloaded to a
temp directory and added to the batch. Uses GIO for the download
in a background thread.
2026-03-06 16:02:39 +02:00
fe12316bc4 Add thumbnail selection for compression and watermark previews
Users can now click different batch images in a thumbnail strip to
switch which image is used for the quality comparison preview and
watermark position preview. Shows up to 10 thumbnails with accent
highlight on the selected one.
2026-03-06 15:59:44 +02:00
fcb4b0e727 Improve output step with individual operation summary rows
Replace single-line arrow-delimited summary with a proper ListBox
showing each enabled operation as its own row with check icons.
Dynamically rebuilt when navigating to the output step. Also make
walk_widgets public for cross-module use.
2026-03-06 15:57:06 +02:00
a09462fd53 Add batch queue with slide-out side panel
Queue panel with OverlaySplitView sidebar. Users can add batches
from the results page via "Add to Queue" action. Queue shows
pending/active/completed batches with status icons. Toggle via
header bar button. Batches can be removed while pending.
2026-03-06 15:52:18 +02:00
ced65f10ec Add tutorial overlay tour after welcome wizard
Semi-transparent dialog-based tour with 6 stops covering step
indicator, workflow selection, image adding, navigation, menu,
and a final ready message. Skippable at any time. State persisted
via tutorial_complete flag in AppConfig.
2026-03-06 15:48:06 +02:00
33659a323b Enhance save preset dialog with settings summary and update option
Replace simple alert dialog with full dialog showing workflow summary,
new preset name entry, and option to update existing user presets.
Never overwrites built-in presets.
2026-03-06 15:43:45 +02:00
1d33be1e3d Wire DPI setting from resize step through to processing job
Add output_dpi field to JobConfig, ProcessingJob, and Preset.
Connect the DPI SpinRow in the resize step's advanced options to
update the config value.
2026-03-06 15:41:25 +02:00
eb8da4b3e9 Add live watermark preview with position and opacity updates
Shows a thumbnail of the first batch image with the watermark text
overlaid. Preview updates in real-time as user changes text, position
(9-point grid), and opacity.
2026-03-06 15:39:10 +02:00
b50147404a Add file manager integration install/uninstall logic
Implements actual extension file creation for Nautilus (Python
extension), Nemo (.nemo_action files), Thunar (custom actions XML),
and Dolphin (KDE service menu .desktop). Each extension creates a
"Process with Pixstrip" submenu with all presets listed. Toggle
switches in welcome wizard and settings now call install/uninstall.
2026-03-06 15:37:25 +02:00
5bdeb8a2e3 Wire skill level and accessibility settings to UI
- Add detailed_mode to AppState, derived from skill_level setting
- Expand advanced option sections by default in Detailed mode
  (resize, convert, compress, watermark steps)
- Fix high contrast to use HighContrast GTK theme
- Add completion sound via canberra-gtk-play
2026-03-06 15:28:02 +02:00
d6f7fc9c88 Initialize overwrite behavior from app settings
The overwrite behavior in the output step now defaults to the value
configured in Settings rather than always defaulting to "Ask".
2026-03-06 15:24:51 +02:00
4dd868078a Add completion sound, preserve directory structure support
- Play system notification sound via canberra-gtk-play when enabled
- Implement preserve_directory_structure in output_path_for to maintain
  relative paths from input directory in output
2026-03-06 15:24:04 +02:00
1e3ffaadd3 Add history pruning with configurable max entries and max days
- Add history_max_entries (default 50) and history_max_days (default 30)
  to AppConfig
- Add prune() method to HistoryStore that removes old entries by age
  and count limits
- Call prune after each history entry is added in the GUI
- Preserve history settings through settings dialog save/load cycle
2026-03-06 15:22:17 +02:00
5e83cb09ef Add --algorithm and --overwrite flags to CLI
Support resize algorithm selection (lanczos3/catmullrom/bilinear/nearest)
and overwrite behavior (auto-rename/overwrite/skip) in the CLI process
command, matching the GUI functionality.
2026-03-06 15:19:34 +02:00
a29256921e Wire resize algorithm selection, overwrite behavior, and fix rotation/flip scope
- Add ResizeAlgorithm enum (Lanczos3/CatmullRom/Bilinear/Nearest) to core
- Thread algorithm selection from UI ComboRow through ProcessingJob to resize_image
- Add OverwriteBehavior enum (AutoRename/Overwrite/Skip) to core
- Implement overwrite handling in executor with auto-rename suffix logic
- Wire overwrite behavior from output step through to processing job
- Fix rotation/flip to apply when resize step is enabled, not just adjustments
2026-03-06 15:17:59 +02:00
064194df3d Fix imported presets not persisting, remove duplicate help handler 2026-03-06 15:12:06 +02:00
5881fb6eae Restore session settings for convert format, quality preset, and metadata mode
- Parse stored format/quality/metadata strings back to enum values on launch
- Remove duplicate help button handler
- Session now properly round-trips all wizard state between launches
2026-03-06 15:10:28 +02:00