混淆与解混淆共用同一套坐标和同一个步长。理解“曲线”“位移”“双射”三个词, 就足以解释你在这个工具里看到的所有现象。
一句话版本
把图片的像素按一条固定曲线排成一队,再把整队数据往前平移约 0.618 倍总长的距离。 平移是循环的,每个位置都有唯一来源,所以反向平移同样距离就能恢复。
没有密码,没有随机种子,也没有隐藏参数。所有规则都可以写成几行公式,这也是它“可逆但不可保密”的原因。
像素是一张按行列排好的表
浏览器通过 Canvas 读取图片时,得到的是一段连续的内存:每四个字节描述一个像素, 依次是红、绿、蓝和透明度。图片的宽度决定了一行有多少个像素, 于是这段一维数据可以被重新折成一张二维的表。
人眼之所以能看到画面,是因为这些数值按照原来的行列关系排列。 只要把表格里任意两个格子的内容互换,画面就会开始失真;互换得越多、越远,越难辨认。 混淆做的事情,就是大规模、确定性地互换位置,而不修改任何一个颜色值。
为什么不直接随机打乱
随机打乱听起来更安全,但会带来两个工程问题。第一,真正随机的排列需要保存一张映射表, 800 万像素就是 800 万个索引,内存开销很大;第二,解混淆必须知道同一张随机表, 而这张表没有天然的分发方式,除非额外引入密钥或种子。
空间填充曲线提供了另一种思路:它只依赖宽高,不需要额外保存任何表。 给定宽高,每个人都能算出完全相同的遍历顺序;给定顺序,每个人也都能算出反向映射。 这正好满足“可逆、无需密钥、可复现”的目标。
顺便说一句,曲线还有一个副作用:它让相邻的格子在顺序上也尽量相邻。 这样搬运之后的画面会呈现细碎的噪点,而不是大块的色带,视觉遮挡效果更均匀。
Gilbert 曲线怎么走
常见的希尔伯特曲线定义在 2 的幂次方形网格上。本站使用的是它的推广版本, 可以处理任意宽高的矩形,因此 1200 × 800、1080 × 1920 这类图片不需要补边或裁切。
递归过程可以这样理解:把当前矩形沿长边切成两块或三块,分别递归;
需要反向遍历的块,把方向取反。切到只剩一行或一列时,直接顺序填满。
由于每次切分都完整覆盖原矩形,最终得到的坐标序列长度恰好等于
W × H,每个格子出现且只出现一次。
这不是“近似覆盖”,而是严格的划分。它保证了后面所有步骤都建立在一个完整的双射上, 不会有像素被漏掉,也不会有像素被写两次。
0.618 倍的步长
如果只按曲线顺序把数据往前挪一位,相邻像素仍然挨在一起,画面几乎不会变。 步长必须足够大,才能把原本相邻的像素甩到队列的另一端。本站使用的步长是:
shift = round((√5 − 1) / 2 × W × H)
(√5 − 1) / 2 约等于 0.618,也就是黄金分割比例的倒数。
它乘以像素总数,再四舍五入到整数,得到一个与总长度同一量级的位移。
对任意尺寸的图片,这个比例都能让搬运后的像素落在队列中段附近,
而不是只在局部小范围里打转。
为什么不用 0.5?因为 0.5 倍总长会让前后两半整体交换,容易形成肉眼可辨的对称结构; 也不容易产生“挪了几次就回到原位”的短周期。黄金分割比例是一个无理数的近似, 在离散化之后仍然能让位移与总长度保持较为“错开”的关系,实际效果更均匀。
一次搬运的完整流程
把上面的内容合起来,一次混淆可以用下面几行伪代码描述:
N = W × H
shift = round(0.618 × N)
curve = gilbertPath(W, H) // 长度 N 的坐标序列
for i in 0 .. N-1:
from = curve[i]
to = curve[(i + shift) % N]
out[to] = in[from]
解混淆把赋值方向反过来,其余完全相同:
for i in 0 .. N-1:
from = curve[i]
to = curve[(i + shift) % N]
out[from] = in[to]
注意 out 和 in 是两块独立的像素缓冲区。原地交换会互相覆盖,
因此实现时总是先读源数据,再写目标数据。最终结果写回同一张画布,导出为图片。
可逆性从哪来
可逆性由两步复合保证:
- 曲线是一个双射。每个网格坐标对应唯一的序号,每个序号也对应唯一的坐标。
- 平移是一个置换。在长度为 N 的环上,
i → (i + shift) mod N是一一对应的,反向就是i → (i − shift) mod N。
两个双射复合仍然是双射,所以每个输出位置都能找到唯一来源,反向执行就能完整恢复。 这也解释了为什么少一个像素都不行:宽高变化会改变 N、曲线形状和步长, 整个映射关系随之改变,旧图片的坐标就对不上了。
动手画一遍
下面的图把 12 × 8 的网格和它的 Gilbert 曲线画了出来。拖动滑杆改变序号 i, 深色格表示曲线上的第 i 个点,橙色格表示它被搬到的第 i + shift 个点。 切换网格尺寸,可以看到步长随总像素数变化。
它能做什么,不能做什么
从数学上看,这是一个没有密钥的置换。任何人都可以构造出同样的曲线和步长, 因此任何人都能还原。它真正提供的是观看门槛:缩略图不再直接暴露内容, 随手转发的人需要多走一步才能看到画面。
如果需要“没有授权就打不开”,请使用带密钥的加密;如果需要“这段信息根本不该出现”, 请直接裁剪或彻底打码。混淆可以和其他手段组合,但不能替代它们。 更完整的讨论见隐私与安全边界与方案对比。