Convert camera RAW files (NEF/CR2/CR3/ARW/RAF/ORF/DNG/...), JPG photos, and Apple HEIC/HEIF images to JPG thumbnails, find photos by shooting date, and generate layout previews.
BrandExtensionsNikon.nef, .nrwCanon.cr2, .cr3, .crwSony.arw, .srf, .sr2Fujifilm.rafOlympus/OM.orfPanasonic.rw2Pentax.pefSamsung.srwLeica.rwl, .dngAdobe DNG.dngHasselblad.3fr, .fffPhase One.iiqSigma.x3f
FormatExtensionsNotesJPEG.jpg, .jpeg直接 Pillow 处理
FormatExtensionsNotesHEIC/HEIF.heic, .heif需要 pip install pillow-heif
Declaration file: requirements.txt
Prefer venv: Before running scripts, activate the project-root virtual environment (e.g. .venv/). If it doesn't exist, create one first:
bash
# Create venv and install dependencies (recommended)
python3 -m venv .venv
source .venv/bin/activate
pip install -r photo-toolkit/requirements.txt
# Or use the skill's setup script (checks + installs)
bash photo-toolkit/scripts/setup_deps.sh
# Before each session, activate venv
source .venv/bin/activate
Alternatively, install globally:
bash
brew install libraw # macOS
# apt-get install libraw-dev # Debian/Ubuntu
# dnf install LibRaw-devel # RedHat/CentOS/Fedora
pip3 install -r photo-toolkit/requirements.txt
Verify:
bash
python3 -c "import rawpy; from PIL import Image; import numpy; print('✓ Core dependencies installed')"
python3 -c "from pillow_heif import register_heif_opener; print('✓ HEIC/HEIF support available')" 2>/dev/null || echo "ℹ HEIC/HEIF support not installed (optional: pip install pillow-heif)"
Copy config.example.toml to config.toml and edit to set your directories. See config.example.toml for all available options.
convert.py — Photo → JPG Thumbnails#Supports RAW, JPG, and HEIC/HEIF input. By default, thumbnails are output to {input}/thumbnails/.
bash
# Convert all photo files (thumbnails output to ~/data/RAW/thumbnails/)
python3 scripts/convert.py ~/data/RAW
# Custom settings
python3 scripts/convert.py ~/data/RAW ~/data/output/thumbnails --size 2048 --quality 95
# Read file list from stdin (pipe from find_by_date.py)
python3 scripts/find_by_date.py --date today ~/data/RAW | \
python3 scripts/convert.py --from-stdin
# With report output
python3 scripts/convert.py ~/data/RAW --report /tmp/convert_report.json
# Dry run
python3 scripts/convert.py ~/data/RAW --dry-run
OptionDescriptionDefaultinputPhoto file or directoryfrom configoutput_dirOutput directory{input}/thumbnails/``--sizeMax thumbnail dimension (px)1200--qualityJPEG quality (1-100)85--workersParallel workersauto (max 8)--recursiveSearch subdirectoriesoff--overwriteOverwrite existing filesoff--dry-runPreview onlyoff--no-exifSkip EXIF copyoff--reportOutput processing report JSON pathnone--from-stdinRead file paths from stdin (JSON)off
find_by_date.py — Find Photo Files by Date / Detect Timelapse#Searches for RAW, JPG, and HEIC/HEIF files by EXIF shooting date. Outputs JSON path list to stdout. Also detects timelapse sequences by identifying runs of photos with regular shooting intervals.
bash
# Find by exact date (outputs JSON to stdout)
python3 scripts/find_by_date.py --date 3月15日
python3 scripts/find_by_date.py --date 2026-03-15
# Date range
python3 scripts/find_by_date.py --from 2026-03-10 --to 2026-03-15
# Save output to file
python3 scripts/find_by_date.py --date 3月15日 --output ~/data/found_files.json
# List all dates
python3 scripts/find_by_date.py --list-dates
# Timelapse: detect sequences with regular intervals, exclude casual shots
python3 scripts/find_by_date.py ~/data/RAW --timelapse
python3 scripts/find_by_date.py ~/data/RAW --timelapse --output ~/data/timelapse_found.json
python3 scripts/find_by_date.py ~/data/RAW --timelapse --min-sequence 50
# Pipe to convert.py
python3 scripts/find_by_date.py --date today ~/data/RAW | \
python3 scripts/convert.py --from-stdin
OptionDescriptionDefault--output, -oSave JSON output to filestdout--timelapseDetect timelapse sequences (regular intervals)off--min-sequenceMinimum frames to qualify as timelapse30--interval-toleranceInterval deviation tolerance (0.5 = ±50%)0.5
Supported date formats: 2026-03-15, 03-15, 3月15日, today, yesterday, 3 days ago
layout_preview.py — Layout Preview (Comparison / Grid)#Default: side-by-side comparison (left=original, right=graded)
When --params is provided and contains absolute paths, originals are resolved automatically without --originals.
bash
# Comparison mode with absolute paths in params (--originals not needed)
python3 scripts/layout_preview.py ~/data/output/graded \
--params grading_params.json
# Comparison mode with explicit originals directory
python3 scripts/layout_preview.py ~/data/output/graded \
--originals ~/data/RAW --params grading_params.json
# Grid mode (宫格) — only graded photos
python3 scripts/layout_preview.py ~/data/output/graded --grid \
--params grading_params.json
OptionDescriptionDefaultgraded_dirGraded JPG directory (required)—--originalsOriginal photos directoryauto-detect from params--paramsgrading_params.json pathnone--gridUse grid layout insteadoff (comparison)--cell-sizeRow height / grid cell px800--gapGap between images px6--qualityJPEG output quality92-o/--outputOutput path../layout_preview.jpg
Note: Without
--grid, the script generates side-by-side BEFORE|AFTER comparisons. Use--gridonly when user explicitly requests 四宫格 or 九宫格.
When the user asks to convert photo files or find photos by date:
bash scripts/setup_deps.shinput_dir