個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證A black-and-white print that carries its own color. Print photos and documents on any B/W printer; scan them, and the color comes back.
翻譯準備中
取自儲存庫 README
正在載入完整 README。
檢視完整 README ↗Print a color photo or document on any black-and-white printer. It looks like an ordinary grayscale page. Scan it, and Inkhue brings the color back.
Download · How to use · How it works · Benchmark · Wiki · 中文说明
Original · what gets printed (inset: the actual printer dots) · color recovered from the scan, at 2× resolution.
Original · printed · recovered. Bottom row: someone wrote on the printout with a pen — the color still comes back, and the handwriting stays, just as it is on the paper.
Documents too: notes, worksheets and slides keep their highlights, colored text and charts. Photos: public domain / CC0 (NASA, scikit-image).
Upside down, a little crooked, written on? All fine.
| Platform | Installer | Installs to |
|---|---|---|
| macOS (Apple silicon) | Inkhue-vX.Y.Z-macos-arm64.pkg | Applications |
| macOS (Intel) | Inkhue-vX.Y.Z-macos-x64.pkg | Applications |
| Windows 10/11 (64-bit) | Inkhue-vX.Y.Z-windows-x64-setup.exe | your programs folder (or Program Files for all users) |
| Ubuntu / Debian (x86-64) | Inkhue-vX.Y.Z-linux-x64.deb | /opt/Inkhue, app menu, inkhue command |
From the latest release. Every file is listed in
SHA256SUMS.txt and carries a build provenance attestation
(gh attestation verify <file> -R TonyD365/Inkhue).
macOS — open the .pkg. The first time, macOS refuses it: System Settings → Privacy & Security → Open
Anyway, then follow the installer. Once only; updates install themselves without a password.
Windows — run the setup.exe. If SmartScreen appears: More info → Run anyway.
Ubuntu / Debian — sudo apt install ./Inkhue-*.deb. Scanning uses SANE: sudo apt install sane-utils.
More help: installation · printing and scanning · troubleshooting · FAQ
flowchart LR
A[Color image] --> Y[Brightness]
A --> C[Color, 1/8 resolution]
C --> RS[Reed-Solomon + repetition<br/>+ public scatter]
Y --> H{{4×4-dot cells}}
RS --> H
H -->|dot count = brightness<br/>ink lean = 2 bits| P[Black-and-white page]
P --> S[Scan] --> D[Find frame, read cells,<br/>correct errors] --> N[Neural refiner] --> O[Color image, 2×]
A 600 dpi printer can only put a dot or leave paper white. Inkhue groups the dots into cells of 4×4 dots (1/150 inch). Each image pixel becomes one cell, and its brightness is the number of inked dots, 0 to 16 — the same idea as an ordinary halftone. Error diffusion spreads the rounding error to neighbouring cells so smooth gradients stay smooth.
Which of the 16 positions get ink is chosen from the image at full printer resolution: dots go where the picture is darkest inside the cell, so edges and fine detail survive inside a cell instead of being averaged away.
The arrangement also carries data. The centre of mass of the ink in a cell leans towards one of its four corners: left/right is one bit, top/bottom is another. The placement in step 1 is only allowed to choose arrangements whose centre of mass leans clearly enough (a safety margin) towards the corner the data asks for; the eye, seeing a 1/150-inch cell from reading distance, can't tell the difference.
That is 2 bits per cell, about 45,000 bits (5.6 KB) per square inch at 600 dpi — and the bits sit inside the picture, region by region, not in a separate code.
A cell with 0 dots (white paper) or 16 dots (solid black) has no corner to lean towards, so it can't carry bits. Photos have few such cells; a page of notes is mostly white. When more than 20 % of a page would be empty or full, Inkhue keeps 1 to 15 dots in every cell: blank paper gets one faint dot per cell and carries data like everything else. A flag in the header tells the decoder to rescale brightness, so white comes back white.
The page is surrounded by a white margin, a 2-cell black frame, a timing track of alternating black and white cells along the top and left, and a white gap.
For every cell Inkhue measures the ink (→ brightness) and the ink's centre of mass (→ two soft bits: not just 0 or 1, but how confidently). Slow drifts from imperfect alignment are removed. All copies of each bit are added up, weighted by confidence, then Reed-Solomon corrects what's left. A block that is still too damaged leaves its part of the picture gray instead of filling it with random color.
Decoded straight, the photo would be grainy and the color soft (1/8 resolution). A small U-Net (≈1 million parameters) reads the scan dot by dot together with the decoded color and outputs the photo at 2× the cell resolution (300 ppi for a 600 dpi print). It learns to remove the halftone grain, undo toner spread, read the detail that step 1 put inside each cell, and sharpen the color along brightness edges. It was trained on the 800 DIV2K photos and synthetic documents (colored text, highlights, charts), printed and scanned through a simulator with random printer and scanner settings. It ships as a 4 MB ONNX model and runs on the CPU in about a second.
The simulator reproduces toner spread, uneven coverage, paper noise, rotation, keystone, optical blur, tone curves, sensor noise and JPEG compression; the benchmark runs every change through it at several strengths.
How it differs from QR codes and watermarks: those store a few bytes to a few kilobytes, either next to the image or as a faint signature inside it. Inkhue stores information for every region of the picture while the page itself stays a clear photograph.
Every pull request is benchmarked against main: 4 public-domain photos and a text document × 3 seeds, through a
simulated printer and scanner (scripts/benchmark.py). Current main:
| Condition | Decoded | Raw bit errors | ΔE neural | Detail (PSNR @2×) |
|---|---|---|---|---|
| ideal | 100 % | 8.4 % | 2.66 | 28.8 dB |
| typical | 100 % | 8.1 % | 2.52 | 29.2 dB |
| 600 dpi scan | 100 % | 7.8 % | 2.91 | 28.1 dB |
| 400 dpi scan | 100 % | 12.7 % | 3.25 | 27.1 dB |
| handwriting on the page | 100 % | 9.4 % | 3.31 | 22.9 dB |
| harsh (poor print + scan) | 80 % | 19.9 % | 6.65 | 21.9 dB |
ΔE is CIEDE2000 color error (≈2 is barely visible). These are simulations; real-world reports are the most valuable contribution — see below.
git clone https://github.com/TonyD365/Inkhue && cd Inkhue
python3 -m venv .venv && .venv/bin/python -m pip install -r requirements-app.txt
.venv/bin/python -m inkhue # the app
.venv/bin/python -m inkhue.cli encode photo.jpg page.png # command line: encode / simulate / decode
Tests, benchmark, training the refiner and releasing: Development.
Pages printed today must still decode in ten years. The format constants — above all the scatter SEED — are frozen
and pinned by tests/test_format.py; every change since 1.0 has been backwards compatible.
The most useful thing you can do: print a page and scan it, then share the result with the 🖨️ print / scan report template. Code contributions: see CONTRIBUTING.md. Questions and ideas: Discussions. Security: SECURITY.md.
Apache-2.0 — free to use, modify and ship, including commercially. Published openly so the method stays free for everyone. Inkhue was called ColorHide until version 1.1.