Show HN:Photoc——面向摄影师的命令行工具
Show HN: Photoc – Command-line tools for photographers

原始链接: https://github.com/ahmetomerv/photoc

**photoc** 是一款基于终端的照片工作流工具,可用于审阅、整理、筛选和预处理图像。它支持 JPEG 处理,以及从 Sony ARW 文件读取元数据;暂不支持其他 RAW 格式、HEIC 和 Windows。 主要功能包括: - 查看元数据、存储统计、时间线、重复照片、锐度以及 JPEG 完整性。 - 按日期、相机、ISO、光圈、GPS 信息等元数据查询照片。 - 预览并应用基于元数据的重命名,或按日期/拍摄场次整理文件夹。 - 创建压缩副本和联系表,不修改原文件。 - 分享前移除 GPS 信息和指定的身份识别元数据。 - 通过 Shell 脚本自动执行工作流;大多数检查命令都支持 JSON 输出。 文件变更默认不会执行:重命名和排序需要使用 `--apply`,清除元数据需要使用 `--in-place`。photoc 绝不会删除或覆盖文件。重命名和排序计划会在执行前进行验证,失败后会尝试回滚,但仍建议事先备份。 在 macOS 或 Linux 上可通过 Homebrew tap 安装,也可使用经过校验和验证的 Shell 安装程序安装预编译可执行文件。运行依赖和平台要求可能不同;此外也支持从源代码安装和手动安装。

Hacker News 最新 | 往期 | 评论 | 提问 | 展示 | 工作 | 提交 登录 **Show HN:Photoc——面向摄影师的命令行工具** (github.com/ahmetomerv) 5 分 由 **ahmetomer** 提交 1 小时前 | 隐藏 | 往期 | 收藏 | 2 条评论 **help** **ctech_** 26 分钟前 [–] 默认先预览的安全机制很不错。你们计划在索尼 ARW 之外支持更多 RAW 元数据吗?还是为了尽量减少依赖,这是有意采用的设计? **回复** **ahmetomer** 27 分钟前 | 上级评论 [–] 我肯定会考虑支持更多 RAW 类型,但目前没有具体的时间表。 --- YC 2027 年冬季批次现已开放申请! 申请截止至 11 月 2 日。 指南 | 常见问题 | 列表 | API | 安全 | 法律 | 申请加入 YC | 联系我们 搜索:
相关文章

原文

photoc: command-line tools for photographers

Version Tests / CI Release / CD License: MIT Platforms: macOS | Linux

Quick start · Commands · Workflows · File safety · Scripting · Installation · Troubleshooting · Contributing · License

Command-line tools for photographers.

photoc helps you review, organize, and prepare photos from the terminal. Summarize a shoot, read metadata, find blurry shots and exact duplicates, rename and sort photos into folders, make contact sheets and smaller copies, or remove GPS location before sharing. Every command works in shell scripts, and most can print JSON.

photoc works with JPEG files and reads metadata from Sony ARW RAW files. Other RAW formats (CR3, NEF, RAF, DNG, …) and HEIC are not supported yet. See File-type support.

photoc query finding low-light shots and wide-angle f/5.6 shots in a folder of photos

photoc never changes your original files unless you ask it to with --apply (rename, sort) or --in-place (scrub). It never overwrites existing files.

Read-only commands only read. Commands that create files write new copies next to your originals or in a folder you choose. See File safety for details.

photoc is not a RAW developer, an image editor, a photo catalog, or a replacement for deep metadata editors such as ExifTool. Windows is not supported yet.

Install photoc from its Homebrew tap (macOS or Linux with Homebrew):

brew install ahmetomerv/photoc/photoc
photoc --version

The qualified name adds the tap automatically; Homebrew installs the required libraries. For a prebuilt executable instead, use the shell installer.

Then try these read-only commands on your own photos:

photoc --help                         # list commands
photoc exif photo.jpg                 # one photo's metadata
photoc stats ./photos --recursive     # summarize a folder and its subfolders
photoc timeline ./photos              # review a shoot by session

For example, photoc rename ./shoot --format '{date}_{camera}_{sequence}.{ext}' previews these three sample JPEGs without changing any files:

session_1000.jpg -> 2026-09-27_Model S_0001.jpg
session_1030.jpg -> 2026-09-27_Model S_0002.jpg
session_1200.jpg -> 2026-09-27_Model S_0003.jpg
Summary: 3 JPEG, 3 planned, 0 unchanged, 0 blocked, 0 applied, 0 rolled back

For help with a specific command, run photoc <command> --help or man photoc.

Directory scans look only inside the chosen folder unless you add --recursive, and they do not follow symlinks. Quote paths containing spaces, such as photoc exif "Summer trip/photo.jpg". Put options before -- when a path begins with -, for example photoc exif -- -photo.jpg.

Each command name links to its guide with options, examples, limits, and a JSON schema where supported. All guides are listed in the documentation index.

Inspect (read-only):

Command Purpose
exif Show dimensions, camera, exposure, capture time, and GPS for one photo
stats Summarize storage, capture dates, cameras, lenses, and exposure settings
timeline Group a shoot by date and session
query Find photos matching metadata filters such as ISO, aperture, camera, or date
duplicates Find byte-identical files and show potential space savings
focus Rank JPEGs by sharpness score, lowest first, to help culling
check Audit JPEGs for structural and decoding problems

Organize (preview by default; add --apply to change files):

Command Purpose
rename Rename photos using metadata templates such as {date}_{camera}_{sequence}.{ext}
sort Move photos into YYYY/MM/DD/ or session-001/ folders

Make copies (originals unchanged by default):

Command Purpose
compress Write smaller JPEG copies at a chosen quality or target file size
contact Make paged JPEG contact sheets with filenames and optional exposure data
scrub Write copies without GPS, private fields, or descriptive metadata

--json works with exif, stats, timeline, query, duplicates, focus, and check. Longer directory operations show progress on stderr; use --no-progress to turn it off.

Command JPEG Sony ARW Other RAW files
exif, stats, timeline, rename, sort Metadata Common TIFF/EXIF metadata Unsupported/skipped
query, check, compress, contact, focus, scrub Supported Unsupported/skipped Unsupported/skipped
duplicates Exact bytes Exact bytes Exact bytes

ARW support is metadata only: no RAW development, pixel decoding, compression, or GPS rewriting. Files are matched by extension (.jpg, .jpeg, .arw, case-insensitive). See Sony ARW metadata support for fields and limits. Want your camera supported? See Contributing.

These recipes combine commands the way you might use them after a shoot. Commands that change files are shown in two steps: preview, then apply.

After a shoot: review, rename, and sort

# See how the day breaks into sessions. Adjust --gap to match how you shoot.
photoc timeline ./shoot --gap 45m

# Preview new names, then apply the same command.
photoc rename ./shoot --format '{date}_{camera}_{sequence}.{ext}'
photoc rename ./shoot --format '{date}_{camera}_{sequence}.{ext}' --apply

# Preview session folders, then apply.
photoc sort ./shoot --by session --gap 45m
photoc sort ./shoot --by session --gap 45m --apply

If any photo lacks the metadata a plan needs, such as a capture date, the whole plan is blocked and nothing changes. The preview lists the blocked files.

Culling: find blurry shots and duplicates

# Lowest sharpness scores first; show only those below the threshold.
photoc focus ./shoot --recursive --threshold 100 --only-blurry

# Byte-identical copies, for example from importing a card twice.
photoc duplicates ./shoot --recursive

Sharpness scores are a review aid, not a verdict: subject detail, noise, and intentional blur all affect them. photoc never deletes files; you decide what to remove.

Before sharing: smaller copies without location

# Write compressed copies into ./share, keeping the originals.
photoc compress ./selects --recursive --target 2MB --output-dir ./share

# Remove location and identifying metadata from those copies.
photoc scrub ./share --privacy --recursive --in-place

# Confirm no copy still has GPS (prints nothing when clean).
photoc query ./share --recursive --has-gps

compress keeps EXIF, including GPS, by default, so scrub after compressing. --in-place is used here only because ./share contains copies; it replaces files without a backup. --privacy can leave data in opaque MakerNotes; see the scrub limits.

photoc query ./photos --recursive --iso ">800" --aperture "<=4"
photoc query ./photos --camera "DSC-RX100M7A"
photoc query ./photos --after 2026-01-01 --before 2026-12-31

Filters are combined with AND, and date bounds include the named days. See query details for matching rules and NUL-separated output.

# Contact sheet with exposure data, sorted by capture time.
photoc contact ./shoot --output sheet.jpg --metadata --sort date

# Check a folder for corrupt or truncated JPEGs.
photoc check ./photos --recursive --only-errors

# Save statistics as JSON for your own scripts.
photoc stats ./photos --recursive --json > stats.json
Command Changes originals? Output Existing files
Inspect commands Never Report on stdout Not touched
rename, sort Only with --apply Renames or moves in place Never overwritten; whole plan checked first
compress Never photo.compressed.jpg copies Skipped (directory) or rejected (single file)
contact Never sheet.jpg, sheet-001.jpg, … Never overwritten
scrub Only with --in-place photo.scrubbed.jpg copies Rejected

Important details:

  • Rename and sort check the whole plan before changing anything. If a rename or move fails, photoc tries to undo earlier changes, but another process changing files at the same time can prevent full recovery. Keep backups of important collections.
  • Compress loses image detail and can produce a larger file. EXIF (including orientation and GPS), ICC color profiles, and XMP are preserved; other APP markers are not copied. If a --target size cannot be reached, photoc still writes a copy at the minimum quality and exits with status 1. 2MB means 2,000,000 bytes; 2MiB means 2,097,152 bytes. See metadata preservation.
  • Scrub copies JPEG image data without recompression. --gps removes EXIF GPS only; --privacy removes supported location and identifier fields; --all-metadata removes descriptive metadata but keeps ICC profiles and orientation. Information in opaque MakerNotes or unknown formats may remain.
  • scrub --in-place creates no backup. It verifies a temporary copy, then replaces the original in one atomic step. Symlinks, hard links, and files that change during processing are refused. Permission bits and group ownership are kept; ACLs and extended attributes are not copied.
  • Check reads without changing anything. An OK result is not a backup or a visual-quality guarantee. See audit limits.

Results go to stdout; status text, warnings, errors, and progress go to stderr. --json output contains only JSON, and missing values are null.

photoc exif photo.jpg --json | jq '.exposure'
photoc timeline ./photos --json | jq '.summary'
photoc query ./photos --recursive --has-gps --print0 | xargs -0 ls -l
Exit code Meaning
0 Success
1 A processing or filesystem operation failed, or a compression target was not met
2 Invalid command usage

Global options work before or after the command: -q/--quiet keeps results but hides status text and non-critical warnings, -v/--verbose adds diagnostics on stderr, and --no-progress disables the progress display.

The scripting guide covers JSON details, per-command exit code rules, progress, and exactly what quiet and verbose modes show.

The Quick start uses the project's Homebrew tap. It builds photoc from source and manages its dependencies. After a new version is published to the tap, update an existing Homebrew installation with:

brew update
brew upgrade photoc
photoc --version

brew update refreshes the tap; brew upgrade photoc installs the newer version. The version badge at the top tracks GitHub releases; Homebrew offers that version after the update pull request for the tap formula is merged. See the installation guide for details.

The shell installer downloads a checksum-verified prebuilt release for macOS arm64, macOS x86_64, or Linux x86_64 to $HOME/.local/bin. Install the runtime libraries for your system first:

# macOS
brew install libexif jpeg-turbo libxml2
# Ubuntu / Debian
sudo apt install libexif12 libturbojpeg libjpeg8 libxml2

Then download and run the installer:

curl -fsSL https://raw.githubusercontent.com/ahmetomerv/photoc/main/scripts/install.sh \
  -o install-photoc.sh
sh install-photoc.sh
photoc --version

Release binaries require macOS 15 or later, or glibc-based Linux with glibc 2.35 or later. The installer verifies the download's SHA-256 checksum and never replaces an existing file. If photoc is not found, see Add photoc to your PATH.

  • Choose a version or directory: sh install-photoc.sh --version vX.Y.Z --install-dir "$HOME/bin"

  • Upgrade: preview and remove the tracked shell installation, then run the installer again; see Upgrading.

  • Uninstall: download the uninstaller, preview, then apply:

    curl -fsSL https://raw.githubusercontent.com/ahmetomerv/photoc/main/scripts/uninstall.sh \
      -o uninstall-photoc.sh
    sh uninstall-photoc.sh          # preview
    sh uninstall-photoc.sh --apply  # remove

    This removes only an unchanged shell-installer installation.

The installation guide also covers source builds, shell completions, install locations, the man page, and upgrade behavior. Source and manual installations have their own uninstall instructions.

photoc: command not found

Check that your install directory is on PATH. For the shell installer, see Add photoc to your PATH.

Which photoc installation am I running?

Run type -a photoc to list matching commands and command -v photoc to see which one your shell selects. A Homebrew installation normally resolves to $(brew --prefix)/bin/photoc. If an older shell-installed copy also appears at ~/.local/bin/photoc, follow the tracked uninstall steps. The same path appearing twice in type -a usually means its directory occurs twice in PATH.

error while loading shared libraries: libturbojpeg.so.0 (Linux) or dyld: Library not loaded (macOS)

A runtime library is missing from a shell or manual installation. Install the packages listed under Shell installer. The prebuilt executable does not bundle these libraries.

macOS says the binary "cannot be opened" or "cannot be verified"

Release binaries are not signed or notarized. The installer downloads with curl, which does not trigger this. If you downloaded a binary in a browser, remove the quarantine flag after verifying its checksum: xattr -d com.apple.quarantine ./photoc-darwin-arm64.

My photos are skipped or reported as unsupported

photoc reads JPEG files and Sony ARW metadata only, matched by file extension. See File-type support.

Rename or sort says the plan is blocked

At least one photo is missing metadata the plan needs, such as a capture date or a field used in your template. The preview names each blocked file. Move those files elsewhere or choose a template that does not need the missing field.

A scan succeeded but some files had warnings

stats and timeline continue past individual file errors and count them in the summary. See exit codes.

For anything else, open an issue with the command you ran, photoc --version, your OS, and the full error output.

Bug reports, documentation fixes, and focused code changes are welcome. You can also help without writing C: photographers can share sample files from other cameras so support for more formats can be tested.

Please follow the code of conduct. For file corruption, unsafe overwrites, or suspected vulnerabilities, follow the private reporting steps in SECURITY.md.

photoc's source is licensed under the MIT License. Dependencies retain their own licenses; see third-party notices. This software is based in part on the work of the Independent JPEG Group.

联系我们 contact @ memedata.com