# 文件掃描 把一張紙拍成掃描檔

把紙拍下來，回來的是一份看起來像掃描的東西。

> 把手機拍的紙張照片變成一份擺正、亮度均勻的 PDF。四個角替你找好，透視給你掰正，陰影除掉。全部在你的瀏覽器裡跑，什麼都不上傳。

本頁是一個完全在你的瀏覽器裡執行的互動式工具，地址是 https://abox.tools/zh-TW/document-scanner/。你交給它的任何內容都不會被上傳。下面是這個頁面用文字對該工具的全部說明；要使用它，請開啟這個地址。

## 你的文件**不會上傳**。這裡根本沒有伺服器。

照片的解碼、擺正、清理，以及寫成 PDF，全由你自己的瀏覽器完成，用的只是算術和它本來就帶著的編解碼器。這個工具沒有任何聯網功能，不取東西，也不發東西。這一點在這裡為什麼要緊，看看人們都拍些什麼紙就知道了：護照、工資單、租房合同，或者某個單位讓你「掃描後發回來」的表格。

- ✗ 不上傳
- ✗ 不用註冊
- ✗ 沒有水印
- ✓ 斷網也能用
- ✓ 開源

## 怎麼用手機鏡頭掃描文件

1. **把紙拍下來。** 從上方拍，讓整張紙都在畫面裡，四個角看得見或者接近看得見。不用正對，也不用光線均勻，傾斜和陰影正是這個工具存在的理由。要緊的是把畫面填滿：從房間那頭拍的一張紙，裡面根本沒有可以救回來的細節。
2. **核對四個角。** 照片讀進來時就替你找好了，拿不準的時候頁面也會說。放在跟紙同色的桌子上的紙，邊緣確實很難看清。在照片上隨便按一下，最近的那個角就到你手指這裡來了；也可以用 `Tab` 選中一個角，再用方向鍵挪。
3. **決定光怎麼處理。** 「彩色，去掉不勻」把紙的亮度在整頁上量一遍再除掉，於是陰影消失，而印章和簽字保住自己的顏色。「黑白」走得更遠，掃描檔能小到可以發郵件，靠的就是它。螢幕上看到的就是真結果，寫檔案的是同一段程式碼。
4. **把其餘的頁加進來。** 每加一張照片，就是同一份文件的下一頁，順序就是列表裡的順序，每一頁各自保留自己的四個角。縮圖條上那一頁的箭頭可以把它往前或者往後挪。
5. **存成 PDF，發出去之前先開啟看一眼。** 文件就在這裡、在這一頁的記憶體裡做出來。做它的過程沒有上傳任何東西，關於它也沒有向任何地方報告過什麼。

## 說得更細的版本

[怎麼用手機掃描文件](https://abox.tools/zh-TW/guides/scan-a-document-with-your-phone/): 一張紙的照片和這張紙的掃描檔之間差在哪裡：傾斜、不勻的光，還有檔案大小。照片怎麼拍，之後要修什麼，以及為什麼這些都不需要伺服器。

## 工具箱裡還有

- [從影片裡提取音訊](https://abox.tools/zh-TW/extract-audio-from-video/): 把影片拖進來，聲音就取出來了。畫面從不解碼，也不上傳任何東西。
- [音訊剪輯](https://abox.tools/zh-TW/trim-audio/): 邊聽邊標出值得留的段落。它們會合成一個檔案回來，就切在你說的位置。
- [音訊編輯](https://abox.tools/zh-TW/edit-audio/): 倒著放、快慢隨你調、把錄輕了的聲音提上來，全在你這臺機器上。
- [PDF 合併與拆分](https://abox.tools/zh-TW/merge-pdf/): 挪動頁面，不用往伺服器跑一趟。

## 常見問題

### 我的文件會被上傳嗎？

不會。照片的解碼、擺正、清理，以及寫成 PDF，全都由你自己的瀏覽器在你自己的硬體上完成。這個工具沒有任何聯網功能，從不取東西，也從不發東西，頁面的 `Content-Security-Policy` 裡寫著它能聯絡的每一個地址，沒有一個屬於本站。把頁面載入一次，斷網，它照樣能用。

### 沒有模型，它怎麼找到紙的四個角？

靠找出組成一個四邊形的那四條又長又直的邊。照片先縮小，取梯度，也就是看影像在哪裡變、朝哪個方向變，然後每一個落在邊緣上的畫素都為自己應該落在的那條直線投一票。強的直線兩兩配成候選四邊形，每個候選再走一遍自己的四條邊打分：每條邊下面究竟有多少真的是邊緣，以及這四條邊是不是同一樣東西的邊界。紙要麼比周圍亮，要麼比周圍暗，但四條邊上是同一種關係，正是這一點讓一行字不會被當成紙的下邊緣。沒有權重，不下載任何東西，任何文件進來算的都是同一套算術。

### 它找的角不對，怎麼辦？

拖過去就行。四個角是起點，從來不是決定，掃描的是四個角最後停在哪裡。在照片上隨便按一下，最近的那個角就跳到你手指這裡來，比去戳一個小手柄容易得多；方向鍵每次把當前選中的角挪一個畫素。角是猜出來的而不是找出來的時候，頁面也會說，並在縮圖條上給那一頁做個標記。常見的原因是紙放在跟它顏色差不多的桌上，那裡確實幾乎沒有邊緣可找。

### 擺正之後的紙為什麼形狀是對的，不是被壓扁的？

因為形狀是從透視裡還原出來的，不是從邊緣量出來的。斜著拍的紙，遠端那條邊會被壓短，所以最順手的辦法，也就是取最長的一對對邊當成比例，會做出一張明顯偏矮胖的 A4，網上多數掃描工具給你的就是這個。其實一張四邊形的照片裡，只要相機是臺普通相機，資訊就足夠同時還原出這個四邊形的真實長寬比和相機的焦距。這是 Zhang 和 He 在 2003 年的結果，`src/geometry.js` 做的就是這個。正對著拍的照片沒有透視可用，也不需要，因為那時邊緣本來就是準的，於是它退回去用邊緣，並且頁面會說明是哪一種給出了答案。

### 「清理」到底對影像做了什麼？

把光除掉。紙自己的亮度在整頁上量一遍：分成一格一格的小塊，每塊取亮度的一個高分位數，文字太暗也太稀疏，動不了這個數；然後每個畫素都除以那一點估出來的紙的亮度。剩下的就是墨跡，光線均勻，陰影和邊角發暗都沒有了。這跟提高對比度不是一回事：把一張拍下來的紙提高對比度，亮的地方變白，暗的地方變黑，暗處寫的字也跟著看不見了。「自動色階」把這類圖片弄得更糟而不是更好，原因就在這裡。

### 黑白模式為什麼小那麼多？

因為只有兩種顏色的影像，資料量確實只是一千六百萬色影像的一個零頭，這裡也就真按那樣存：每畫素一位，八個一組塞進一個位元組，再精確壓縮，而不是把一張黑白圖片存成 JPEG。在同樣的頁面上，它比彩色模式小十八倍左右，於是二十頁的合同從十五兆左右降到一兆以內。閾值用的是 Sauvola 的方法，每個畫素是拿它自己鄰域的均值和離散程度來判，而不是拿整頁一個數字，這正是陰影裡的字還看得清的原因。它沒有中間調，所以帶照片的頁面應該換別的模式。

### 可以把好幾頁放進同一個 PDF 嗎？

可以。每加一張照片就是下一頁，順序就是列表裡的順序，每一頁各自保留自己的四個角，於是接連拍下來的一疊紙就成了一份文件。縮圖條上每一頁的箭頭可以把它往前或者往後挪。清理設定是所有頁共用的，這是故意的：同一份文件裡清理方式不同的頁面，看起來像兩份文件。

### 它會識別文字，讓 PDF 可以搜尋嗎？

不會。這裡沒有文字層，也沒有字元識別，出來的是一頁紙的影像放在一頁上。真要做好就得用 OCR 引擎，那是幾十兆的模型要下載，而一個在讀你的工資單之前先去取模型的文件掃描工具，就是一個有理由為工資單往家裡打電話的工具。你要是需要文字，黑白模式做出來的檔案，恰恰是你自己機器上的 OCR 軟體最好處理的那一種。

### 拍糊了，為什麼？

幾乎總是因為紙在照片裡太小。預覽下面那一欄會寫紙填滿了畫面的多少，以及在那個尺寸的紙上大致相當於每英寸多少點。低到 150 DPI 上下，列印出來的掃描檔就顯得發虛，而檔案裡本來就沒有的細節，任何工具都變不出來。別用變焦，直接走近；端穩；按下之前先讓相機在紙上對上焦。另一個原因是手抖，那也救不回來。

### 免費嗎？要註冊嗎？

免費，沒有帳號，不用登入，沒有試用期，不限頁數，也沒有水印。照片多大也沒有限制，因為根本沒有伺服器在為它掏錢，工作是在你自己的機器上乾的。本站靠廣告養活，廣告那邊拿不到關於你文件的任何東西。

## 這條隱私承諾怎麼核實

- **你的文件沒有地方可去。** Content-Security-Policy 裡寫著這一頁能聯絡的每一個地址，沒有一個屬於本站。這裡沒有一個能收集你照片的介面，就算有，程式碼裡也沒有任何東西會把它們送出去。
- **根本沒有模型，所以既不用下載，也不用問誰。** 找出一張紙的四個角靠的是算術：影像的梯度，對其中直線的一次投票，再檢查勝出那個四邊形的每條邊下面到底有什麼。沒有權重，沒有推理執行時，第一次用時也不去取任何東西，更沒有什麼會在別人的文件上表現得不一樣。看 `src/detect.js`。
- **文件裡不寫日期、不寫作者、不寫機器名。** 掃描檔是人發給別人的東西，通常還是因為某個單位要。除了頁面本身，PDF 裡寫進去的只有這個工具的名字，你要是打了標題，就再加一個標題。沒有建立日期，沒有作者，沒有序列號，也沒有任何從你的時鐘、檔名或者電腦推出來的東西。看 `src/document.js`。
- **這裡沒有任何東西去取任何東西。** `src/` 裡的任何地方都沒有 `fetch`，沒有 `XMLHttpRequest`，也沒有 `sendBeacon`。要做的工作就是 `getImageData`、幾段在位元組上跑的迴圈，還有瀏覽器自己的 JPEG 編碼器，這些全都早就裝在你的機器上了。
- **斷網也能用。** 把網路斷掉，這個工具一點不變，因為它裡面從來就沒有聯網那一步。這是最簡單的證明，也是掃護照之前值得先跑一遍的那個。

**你可以自己核對。**上面這些不用你信。這個頁面是儲存庫裡的模板和配置產生出來的，構建指令碼你能讀，也能自己跑一遍，跑出來的結果就提交在 `dist` 分支上。拿實際發給你的內容，跟你自己從原始碼構建出來的結果對一遍就知道了： https://github.com/A-Box-of-Tools/website

最值得先讀的幾個檔案：`config/site.toml` 裡是 Content-Security-Policy，四個角是怎麼在沒有模型的情況下找出來的，看 `src/detect.js`；擺正在 `src/warp.js`；不勻的光是怎麼被除掉的，看 `src/clean.js`。
