# 文档扫描 把一张纸拍成扫描件

把纸拍下来，回来的是一份看着像扫描的东西。

> 把手机拍的纸张照片变成一份摆正、亮度均匀的 PDF。四个角替你找好，透视给你掰正，阴影除掉。全部在你的浏览器里跑，什么都不上传。

这是一个浏览器交互工具，地址是 https://abox.tools/zh/document-scanner/。文件在运行该浏览器的设备上处理。主动分享和可选联网功能都在页面上说明。下文是它的文字说明；使用工具请打开该地址。

## 你的文档**在浏览器里处理**，无须上传处理。

照片的解码、摆正、清理，以及写成 PDF，全由你自己的浏览器完成，用的只是算术和它本来就带着的编解码器。这个工具没有任何联网功能，不取东西，也不发东西。这一点在这里为什么要紧，看看人们都拍些什么纸就知道了：护照、工资单、租房合同，或者某个单位让你「扫描后发回来」的表格。

- ✗ 不上传
- ✗ 不用注册
- ✗ 没有水印
- ✓ 断网也能用
- ✓ 开源

## 怎么用手机摄像头扫描文档

1. **把纸拍下来。** 从上方拍，让整张纸都在画面里，四个角看得见或者接近看得见。不用正对，也不用光线均匀，倾斜和阴影正是这个工具存在的理由。要紧的是把画面填满：从房间那头拍的一张纸，里面根本没有可以救回来的细节。
2. **核对四个角。** 照片读进来时就替你找好了，拿不准的时候页面也会说。放在跟纸同色的桌子上的纸，边缘确实很难看清。在照片上随便按一下，最近的那个角就到你手指这儿来了；也可以用 `Tab` 选中一个角，再用方向键挪。
3. **决定光怎么处理。** 「彩色，去掉不匀」把纸的亮度在整页上量一遍再除掉，于是阴影消失，而印章和签字保住自己的颜色。「黑白」走得更远，扫描件能小到可以发邮件，靠的就是它。屏幕上看到的就是真结果，写文件的是同一段代码。
4. **把其余的页加进来。** 每加一张照片，就是同一份文档的下一页，顺序就是列表里的顺序，每一页各自保留自己的四个角。缩略图条上那一页的箭头可以把它往前或者往后挪。
5. **存成 PDF，发出去之前先打开看一眼。** 文档就在这里、在这一页的内存里做出来。做它的过程没有上传任何东西，关于它也没有向任何地方报告过什么。

## 说得更细的版本

[怎么用手机扫描文档](https://abox.tools/zh/guides/scan-a-document-with-your-phone/): 一张纸的照片和这张纸的扫描件之间差在哪里：倾斜、不匀的光，还有文件大小。照片怎么拍，之后要修什么，以及为什么这些都不需要服务器。

## 工具箱里还有

- [从视频里提取音频](https://abox.tools/zh/extract-audio-from-video/): 把视频拖进来，声音就取出来了。画面从不解码，也不上传任何东西。
- [音频剪辑](https://abox.tools/zh/trim-audio/): 边听边标出值得留的段落。它们会合成一个文件回来，就切在你说的位置。
- [音频编辑](https://abox.tools/zh/edit-audio/): 倒着放、快慢随你调、把录轻了的声音提上来，全在你这台机器上。
- [PDF 合并与拆分](https://abox.tools/zh/merge-pdf/): 挪动页面，不用往服务器跑一趟。

## 常见问题

### 我的文档会被上传吗？

不会。照片的解码、摆正、清理，以及写成 PDF，全都由你自己的浏览器在你自己的硬件上完成。这个工具没有任何联网功能，从不取东西，也从不发东西，页面的 `Content-Security-Policy` 里写着它能联系的每一个地址，没有一个属于本站。把页面加载一次，断网，它照样能用。

### 没有模型，它怎么找到纸的四个角？

靠找出组成一个四边形的那四条又长又直的边。照片先缩小，取梯度，也就是看图像在哪里变、朝哪个方向变，然后每一个落在边缘上的像素都为自己应该落在的那条直线投一票。强的直线两两配成候选四边形，每个候选再走一遍自己的四条边打分：每条边下面究竟有多少真的是边缘，以及这四条边是不是同一样东西的边界。纸要么比周围亮，要么比周围暗，但四条边上是同一种关系，正是这一点让一行字不会被当成纸的下边缘。没有权重，不下载任何东西，任何文档进来算的都是同一套算术。

### 它找的角不对，怎么办？

拖过去就行。四个角是起点，从来不是决定，扫描的是四个角最后停在哪里。在照片上随便按一下，最近的那个角就跳到你手指这儿来，比去戳一个小手柄容易得多；方向键每次把当前选中的角挪一个像素。角是猜出来的而不是找出来的时候，页面也会说，并在缩略图条上给那一页做个标记。常见的原因是纸放在跟它颜色差不多的桌上，那里确实几乎没有边缘可找。

### 摆正之后的纸为什么形状是对的，不是被压扁的？

因为形状是从透视里还原出来的，不是从边缘量出来的。斜着拍的纸，远端那条边会被压短，所以最顺手的办法，也就是取最长的一对对边当成比例，会做出一张明显偏矮胖的 A4，网上多数扫描工具给你的就是这个。其实一张四边形的照片里，只要相机是台普通相机，信息就足够同时还原出这个四边形的真实长宽比和相机的焦距。这是 Zhang 和 He 在 2003 年的结果，`src/shared/document-geometry.js` 做的就是这个。正对着拍的照片没有透视可用，也不需要，因为那时边缘本来就是准的，于是它退回去用边缘，并且页面会说明是哪一种给出了答案。

### 「清理」到底对图像做了什么？

把光除掉。纸自己的亮度在整页上量一遍：分成一格一格的小块，每块取亮度的一个高分位数，文字太暗也太稀疏，动不了这个数；然后每个像素都除以那一点估出来的纸的亮度。剩下的就是墨迹，光线均匀，阴影和边角发暗都没有了。这跟提高对比度不是一回事：把一张拍下来的纸提高对比度，亮的地方变白，暗的地方变黑，暗处写的字也跟着看不见了。「自动色阶」把这类图片弄得更糟而不是更好，原因就在这里。

### 黑白模式为什么小那么多？

因为只有两种颜色的图像，数据量确实只是一千六百万色图像的一个零头，这里也就真按那样存：每像素一位，八个一组塞进一个字节，再精确压缩，而不是把一张黑白图片存成 JPEG。在同样的页面上，它比彩色模式小十八倍左右，于是二十页的合同从十五兆左右降到一兆以内。阈值用的是 Sauvola 的方法，每个像素是拿它自己邻域的均值和离散程度来判，而不是拿整页一个数字，这正是阴影里的字还看得清的原因。它没有中间调，所以带照片的页面应该换别的模式。

### 可以把好几页放进同一个 PDF 吗？

可以。每加一张照片就是下一页，顺序就是列表里的顺序，每一页各自保留自己的四个角，于是接连拍下来的一叠纸就成了一份文档。缩略图条上每一页的箭头可以把它往前或者往后挪。清理设置是所有页共用的，这是故意的：同一份文档里清理方式不同的页面，看着像两份文档。

### 它会识别文字，让 PDF 可以搜索吗？

不会。这里没有文字层，也没有字符识别，出来的是一页纸的图像放在一页上。真要做好就得用 OCR 引擎，那是几十兆的模型要下载，而一个在读你的工资单之前先去取模型的文档扫描工具，就是一个有理由为工资单往家里打电话的工具。你要是需要文字，黑白模式做出来的文件，恰恰是你自己机器上的 OCR 软件最好处理的那一种。

### 拍糊了，为什么？

几乎总是因为纸在照片里太小。预览下面那一栏会写纸填满了画面的多少，以及在那个尺寸的纸上大致相当于每英寸多少点。低到 150 DPI 上下，打印出来的扫描件就显得发虚，而文件里本来就没有的细节，任何工具都变不出来。别用变焦，直接走近；端稳；按下之前先让相机在纸上对上焦。另一个原因是手抖，那也救不回来。

### 免费吗？要注册吗？

免费，没有账号，不用登录，没有试用期，不限页数，也没有水印。照片多大也没有限制，因为根本没有服务器在为它掏钱，活是在你自己的机器上干的。本站靠广告养活，广告那边拿不到关于你文档的任何东西。

## 这条隐私承诺怎么核实

- **处理在这个浏览器里完成。** 本工具在浏览器里处理输入和结果，处理代码不把它们上传去处理。Content-Security-Policy 限制可用资源和连接目的地，但已允许的主机仍可接收请求。策略不检查载荷，不能单独证明什么都没有发出。请把具体操作的请求与源码核对，或断网完成该本地操作。
- **根本没有模型，所以既不用下载，也不用问谁。** 找出一张纸的四个角靠的是算术：图像的梯度，对其中直线的一次投票，再检查胜出那个四边形的每条边下面到底有什么。没有权重，没有推理运行时，第一次用时也不去取任何东西，更没有什么会在别人的文档上表现得不一样。看 `src/shared/document-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/shared/document-detect.js`；摆正在 `src/warp.js`；不匀的光是怎么被除掉的，看 `src/clean.js`。
