Appendix H · Command-Line Tool and Installed Build (v1.9.0)#
The main handbook teaches the algorithms “from the Python code outwards”. Since v1.8 the project also ships two ways to complete the whole workflow without writing a single line of code: the graphical interface (see Ch. 2 and Ch. 10) and the command-line tool nsf5stego. This appendix is a quick reference for installing and using both; the commands work in Windows PowerShell and in Linux/macOS terminals alike.
Version note | This appendix is updated for v1.9.0 (2026-10). On top of the v1.8 commands
embed / extract / analyze / gui, v1.9.0 adds the JPEG compressed domain (--jpeg) and one-command re-runs of an experiment record (repro). Existing pixel-domain usage is unaffected.
H.1 Three ways to install#
Form |
Who it is for |
How to install |
Where output lands |
|---|---|---|---|
Windows installer (recommended for end users) |
No Python, just want the app |
Download |
|
Portable zip |
No installation, carry it around |
|
The unzipped folder |
Source / PyPI |
Reading the code, scripting, CI |
Source: |
The current working directory |
Installer highlights:
Start menu (desktop shortcut optional) → nsF5 隐写工具; double-clicking opens the GUI, and no Python is required;
Ticking “add to user PATH” in the wizard makes the
nsf5stegocommand available (reopen the terminal); uninstalling removes it from PATH again;If SmartScreen warns on first launch, choose “Run anyway” — the project is not code-signed.
Watch out | The project supports Python 3.9, but the JPEG compressed domain depends on the companion project
yccstego, which requires Python >= 3.10. That dependency is installed automatically via an environment marker; when it is missing,jpegstego.available()isFalseand--jpegreports a readable install hint, while the pixel-domain features are completely unaffected (the same degradation pattern as a missinglightgbmfor ML judgment).
H.2 Subcommand quick reference#
nsf5stego --help # overview; --version prints the version
nsf5stego embed cover.png -m "secret text" -p passphrase -o stego.png
nsf5stego extract stego.png -p passphrase
nsf5stego analyze stego.png --sensitivity 宽松 --json
nsf5stego repro experiment.json -m "secret text"
nsf5stego gui # GUI (identical to python src/gui.py)
Subcommand |
What it does |
Key options |
|---|---|---|
|
Embed text into an image |
|
|
Decode the text back |
|
|
Blind steganalysis (chi-square + RS [+ ML]) |
|
|
Re-run from an experiment record and verify item by item |
|
|
Launch the GUI (tkinter) |
— |
Three semantics worth knowing:
--methodand--hamming-papply to the pixel domain only; the JPEG compressed domain is always nsF5 and does not accept them;analyzeexpands wildcards itself (the Windows shell does not), sonsf5stego analyze *.pngworks on all three platforms; an unreadable image in a batch is recorded as anerroritem and the rest still run, with an overall non-zero exit;The shape of
--jsonunderanalyze: a single image prints an object, several images print an array of objects (each carrying animagekey), so scripts can parse it reliably.
H.3 Pixel domain vs JPEG compressed domain: the domain must match#
# Pixel domain (default): flips LSBs of gray pixels, writes PNG
nsf5stego embed cover.png -m "secret" -o stego.png
nsf5stego extract stego.png
# JPEG compressed domain (v1.9.0): embeds in quantized DCT coefficients, writes a standard .jpg
nsf5stego embed cover.png --jpeg -m "secret" --quality 85
nsf5stego extract cover_stego.jpg --jpeg # your embed used --jpeg, so decode needs it too
# Blind analysis: with --jpeg the main signal is the |c|=1 coefficient fingerprint (ML is unavailable there)
nsf5stego analyze stego.png
nsf5stego analyze cover_stego.jpg --jpeg
Watch out | In the compressed domain the payload lives in the quantized coefficients of the JPEG bitstream, so the stego
.jpgmust be stored and transferred byte-for-byte — re-encoding it with any tool destroys the payload. The pixel domain is the opposite: PNG/BMP are lossless, so bit planes never shift.
Decoding must match embedding in four respects: domain (whether --jpeg was used), method (--method), Hamming parameter p, and passphrase. When they disagree the output is not the original text; the CLI exits with a non-zero code and says so instead of printing replacement characters.
H.4 Experiment records and one-command re-runs (v1.9.0)#
Every embed can export an experiment record: embed --json (or “export experiment record” in the GUI) prints parameters, image hashes and modification statistics as JSON with schema nsf5stego.experiment/1. The record contains no plaintext, so a re-run needs the original text again.
nsf5stego embed cover.png -m "secret" --json > experiment_20261003.json
nsf5stego repro experiment_20261003.json -m "secret" # re-run and verify item by item
The verification strength of repro depends on the domain:
the pixel domain is always byte-deterministic;
the JPEG domain is byte-deterministic too when the
yccstegoversion matches, and automatically falls back to round-trip verification (extraction must agree) when the version recorded in the record differs — older records stay compatible.
The passphrase is recorded only as present/absent, never its content, so repro needs you to pass it again (-p).
H.5 Exit codes and common errors#
Exit code |
Meaning |
|---|---|
|
Success |
|
Runtime failure: capacity exceeded / passphrase or parameters mismatched / unreadable image |
|
Argument error (argument-parsing layer) |
Scripts can judge success straight from the exit code. The three mistakes newcomers hit most:
Decoding with
--jpegafter embedding without it (or the reverse) — the domains disagree, so nothing decodes;A mismatched p or passphrase — the output is invalid text; the CLI exits non-zero with a hint;
Using
--jpegon Python 3.9 —yccstegois missing; the error carries an install hint, and installing it or switching to the pixel domain fixes it.
H.6 The GUI: the whole loop in one minute#
The GUI loads a demo cover on first launch, and a guidance bar at the top tracks your progress and always tells you where to click next: press “Embed and save” (watch the modified-pixel count and the output path) → tick “Show diff” to zoom in on which pixels changed → press “Decode / extract” to confirm the text comes back intact. The whole loop takes under a minute; only then go back to the matching chapter to understand why it works.
The GUI and the CLI share one set of parameter semantics (domain / method / p / passphrase); the CLI entry point is src/cli.py, while the algorithm core is still ns5_core.py.
To go further: the command line only runs the workflow — the principles behind the options are still in the main text. Domains and bit planes are in Ch. 1, JPEG and DCT in Ch. 1½, matrix embedding and wet paper in Ch. 4 and 5, and the design of experiment records in Ch. 9.