KIRO写的需求文档:给CnQRCode增加二维码解码功能
引言
CnQRCode 单元(Source/Crypto/CnQRCode.pas)目前已实现二维码生成功能(TCnQREncoder 类)。本需求文档描述在同一单元内新增二维码识别(解码)功能的完整需求,分三个阶段实现:
• 阶段一:从 TCnQRData(二维 0/1 矩阵)直接解码出文本内容,这是核心解码逻辑。 • 阶段二:从 TBitmap 图像出发,经过二值化、寻像图案定位、对齐图案定位、透视变换、网格采样,最终得到 TCnQRData 矩阵。 • 阶段三:将阶段一和阶段二串联,提供从 TBitmap 直接解码出文本的完整接口。
解码逻辑参考 zxing 开源库的 BitMatrixParser、DataBlock、ReedSolomonDecoder、DecodedBitStreamParser、FinderPatternFinder、AlignmentPatternFinder、Detector 等类,并适配 Delphi 5 语法规范。
术语表
• TCnQRData:二维字节数组 array of array of Byte,索引为[X, Y],左上角为[0, 0],值 1 表示黑色模块,值 0 表示白色模块。• TCnQRDecoder:本功能新增的二维码解码器类,负责从 TCnQRData 矩阵或 TBitmap 图像解码出文本。 • TCnQRBinarizer:本功能新增的图像二值化处理器,将灰度图像转换为黑白二值矩阵。 • TCnQRDetector:本功能新增的二维码检测器,负责从二值矩阵中定位寻像图案、对齐图案,并执行透视变换采样。 • TCnQRFinderPattern:寻像图案(Finder Pattern)的中心坐标及估算模块尺寸的记录结构。 • TCnQRAlignmentPattern:对齐图案(Alignment Pattern)的中心坐标及估算模块尺寸的记录结构。 • TCnQRPerspectiveTransform:透视变换矩阵,用于将图像坐标映射到规范化的模块网格坐标。 • TCnQRFormatInfo:格式信息结构,包含纠错级别(TCnErrorRecoveryLevel)和掩码类型(0..7)。 • TCnQRDecodeMode:解码模式枚举,对应 QR 码规范中的 Numeric、AlphaNumeric、Byte、Kanji、Hanzi、ECI 等编码模式。 • TCnErrorRecoveryLevel:纠错级别枚举,已有定义:erlL(7%)、erlM(15%)、erlQ(25%)、erlH(30%)。 • TCnQRCodeVersion:二维码版本,范围 1..40,已有定义。 • GF(2^8):二进制扩展域,用于 Reed-Solomon 纠错运算,生成多项式为 x^8+x^4+x^3+x^2+1(0x11D)。 • 寻像图案(Finder Pattern):位于二维码三个角(左上、右上、左下)的 7x7 黑白同心方块图案,用于定位和方向识别。 • 对齐图案(Alignment Pattern):版本 2 及以上的二维码中用于校正图像畸变的 5x5 小方块图案。 • 时序图案(Timing Pattern):连接寻像图案的交替黑白条纹,用于确定模块网格坐标。 • 格式信息(Format Information):15 位数据,包含纠错级别(2 位)和掩码类型(3 位),附带 10 位 BCH 纠错码,存储于矩阵两处位置。 • 版本信息(Version Information):18 位数据,包含版本号(6 位)和 12 位 BCH 纠错码,版本 7 及以上存储于矩阵两处位置。 • 掩码(Data Mask):对数据区域按 8 种规则之一进行异或操作,以改善模块分布均匀性。 • 码字(Codeword):8 位数据单元,是 Reed-Solomon 纠错的基本处理单位。 • 数据块(Data Block):按版本和纠错级别划分的码字子集,每块独立进行 Reed-Solomon 纠错。 • Z 字形路径(Zigzag Path):从矩阵右下角开始,按列对(每次两列)从右向左、交替从下到上/从上到下读取数据位的路径。 • ECI(Extended Channel Interpretation):扩展通道解释,用于指定非默认字符集编码。 • Hanzi 模式:汉字编码模式,使用 GB2312 编码,每个汉字用 13 位表示。 • Kanji 模式:日文汉字编码模式,使用 Shift-JIS 编码,每个字符用 13 位表示。 • 1:1:3:1:1 比例:寻像图案在水平或垂直方向上黑-白-黑-白-黑五段的像素数比例,用于识别寻像图案。 • 透视变换(Perspective Transform):将四边形区域映射到正方形网格的投影变换,用于校正图像倾斜和透视畸变。 • 二值化(Binarization):将灰度图像转换为黑白二值图像的过程,本功能采用自适应阈值方法。 • TBytes:Delphi 动态字节数组类型,等价于 array of Byte。• TUInt64:CnPack 已定义的无符号 64 位整数类型。
需求
需求 1:格式信息读取与解析
用户故事: 作为开发者,我希望解码器能从 TCnQRData 矩阵中读取并解析格式信息,以便确定纠错级别和掩码类型,为后续解码步骤提供基础参数。
验收标准
1. WHEN 给定一个尺寸不小于 21x21 的 TCnQRData 矩阵,THE TCnQRDecoder SHALL 按 MSB 优先顺序从矩阵左上角区域(列 8 行 0..5、行 8 列 0..5,跳过时序图案位置,再加 (8,7)、(8,8)、(7,8))读取第一份 15 位格式信息位序列,位 14 为最高位。 2. WHEN 给定一个有效的 TCnQRData 矩阵,THE TCnQRDecoder SHALL 从矩阵右上角(行 8,列 Size-1..Size-8)和左下角(列 8,行 Size-7..Size-1,含暗模块位置)读取第二份 15 位格式信息位序列。 3. WHEN 读取到两份格式信息位序列,THE TCnQRDecoder SHALL 对每份位序列与掩码值 0x5412 进行异或运算后,在 32 个标准格式信息码字表中分别查找汉明距离最小的匹配项;IF 两份各自的最小汉明距离不同,THEN THE TCnQRDecoder SHALL 采用汉明距离更小的那份的解析结果。 4. WHEN 两份格式信息均无法在汉明距离不超过 3 的范围内匹配任何标准码字,THE TCnQRDecoder SHALL 返回格式错误(Format Error)。 5. WHEN 格式信息解析成功,THE TCnQRDecoder SHALL 从解析结果中提取纠错级别(bits 4..3)和掩码类型(bits 2..0),并存入 TCnQRFormatInfo 结构。 6. WHEN 格式信息中的纠错级别位为 01,THE TCnQRDecoder SHALL 将纠错级别识别为 erlL;为 00 时识别为 erlM;为 11 时识别为 erlQ;为 10 时识别为 erlH。
需求 2:版本信息读取与解析
用户故事: 作为开发者,我希望解码器能从 TCnQRData 矩阵中读取并解析版本信息,以便确定二维码版本号,从而获取正确的码字数量和数据块结构。
验收标准
1. WHEN 矩阵尺寸对应版本 1..6(即 Size = 21..41),THE TCnQRDecoder SHALL 直接由公式 Version = (Size - 17) / 4 推算版本号,无需读取版本信息区域。 2. WHEN 矩阵尺寸对应版本 7..40(即 Size >= 45),THE TCnQRDecoder SHALL 从矩阵右上角版本信息区域(列 Size-11..Size-9,行 0..5)读取 18 位版本信息位序列。 3. WHEN 矩阵尺寸对应版本 7..40,THE TCnQRDecoder SHALL 同时从矩阵左下角版本信息区域(列 0..5,行 Size-11..Size-9)读取第二份 18 位版本信息位序列。 4. WHEN 读取到版本信息位序列,THE TCnQRDecoder SHALL 在 34 个标准版本信息码字表(版本 7..40)中查找汉明距离最小的匹配项。 5. WHEN 版本信息无法在汉明距离不超过 3 的范围内匹配任何标准码字,THE TCnQRDecoder SHALL 返回格式错误(Format Error)。 6. WHEN 版本信息解析成功,THE TCnQRDecoder SHALL 验证解析出的版本号对应的矩阵尺寸(Version * 4 + 17)与实际矩阵尺寸一致;IF 不一致,THEN THE TCnQRDecoder SHALL 返回格式错误。
需求 3:去掩码处理
用户故事: 作为开发者,我希望解码器能对 TCnQRData 矩阵的数据区域执行去掩码操作,以便还原原始数据位,使后续码字读取得到正确的数据。
验收标准
1. WHEN 格式信息解析成功并获得掩码类型(0..7),THE TCnQRDecoder SHALL 对矩阵中所有非功能区域(非寻像图案、非时序图案、非对齐图案、非格式信息、非版本信息区域)的每个模块执行去掩码操作。 2. WHEN 掩码类型为 0,THE TCnQRDecoder SHALL 对满足 (Row + Col) mod 2 = 0 的模块执行位翻转(0 变 1,1 变 0)。 3. WHEN 掩码类型为 1,THE TCnQRDecoder SHALL 对满足 Row mod 2 = 0 的模块执行位翻转。 4. WHEN 掩码类型为 2,THE TCnQRDecoder SHALL 对满足 Col mod 3 = 0 的模块执行位翻转。 5. WHEN 掩码类型为 3,THE TCnQRDecoder SHALL 对满足 (Row + Col) mod 3 = 0 的模块执行位翻转。 6. WHEN 掩码类型为 4,THE TCnQRDecoder SHALL 对满足 (Row div 2 + Col div 3) mod 2 = 0 的模块执行位翻转。 7. WHEN 掩码类型为 5,THE TCnQRDecoder SHALL 对满足 (Row * Col) mod 6 = 0 的模块执行位翻转。 8. WHEN 掩码类型为 6,THE TCnQRDecoder SHALL 对满足 (Row * Col) mod 6 < 3 的模块执行位翻转。 9. WHEN 掩码类型为 7,THE TCnQRDecoder SHALL 对满足 (Row + Col + (Row * Col) mod 3) mod 2 = 0 的模块执行位翻转。 10. THE TCnQRDecoder SHALL 使用已有的 IsFunctionArea 函数逻辑判断每个模块是否属于功能区域,功能区域的模块不参与去掩码操作。
需求 4:码字提取(Z 字形路径读取)
用户故事: 作为开发者,我希望解码器能按照 QR 码规范的 Z 字形路径从去掩码后的矩阵中读取码字字节序列,以便为 Reed-Solomon 纠错提供输入数据。
验收标准
1. WHEN 去掩码完成后,THE TCnQRDecoder SHALL 从矩阵右下角开始,按列对(每次处理相邻两列,右列为高位、左列为低位)从右向左遍历,第一个列对从下到上读取,此后每个列对交替切换方向。 2. WHEN 遍历到列索引为 6 的列对时,THE TCnQRDecoder SHALL 跳过列 6(时序图案列),将该列对视为列 7 和列 5 的组合继续处理。 3. WHEN 读取到属于功能区域的模块时,THE TCnQRDecoder SHALL 跳过该模块,继续读取下一个非功能区域模块。 4. WHEN 连续读取到 8 个有效数据位时,THE TCnQRDecoder SHALL 将这 8 位组合为一个码字字节(MSB 优先),并追加到码字序列中。 5. WHEN 码字序列的字节数等于当前版本对应的总码字数(CN_TOTAL_CODEWORDS 表中的值),THE TCnQRDecoder SHALL 停止读取并返回码字序列。 6. WHEN 版本对应存在余数位(Remainder Bits)时,THE TCnQRDecoder SHALL 在读完所有码字后跳过这些余数位,不将其计入码字序列。 7. IF 读取完所有非功能区域模块后码字数量与预期不符,THEN THE TCnQRDecoder SHALL 返回格式错误。
需求 5:数据块划分
用户故事: 作为开发者,我希望解码器能按照版本和纠错级别将码字序列正确划分为数据块,以便对每个数据块独立执行 Reed-Solomon 纠错。
验收标准
1. WHEN 获得码字序列后,THE TCnQRDecoder SHALL 根据版本号和纠错级别,从 CN_NUM_ERROR_CORRECTION_BLOCKS 和 CN_ECC_CODEWORDS_PER_BLOCK 常量表中查询数据块数量和每块纠错码字数。 2. THE TCnQRDecoder SHALL 按照 QR 码规范的交织顺序将码字序列分配到各数据块:先按顺序分配每块的数据码字,再分配每块的纠错码字。 3. WHEN 版本和纠错级别对应两种不同大小的数据块时(如版本 5 erlM 有 2 个 43 字节块和 2 个 44 字节块),THE TCnQRDecoder SHALL 正确处理两种块大小的交织分配。 4. WHEN 数据块划分完成后,THE TCnQRDecoder SHALL 确保所有数据块的总码字数之和等于该版本和纠错级别的总码字数。 5. IF 码字序列长度与预期总码字数不符,THEN THE TCnQRDecoder SHALL 返回格式错误。
需求 6:Reed-Solomon 纠错解码
用户故事: 作为开发者,我希望解码器能对每个数据块执行 GF(2^8) Reed-Solomon 纠错,以便在二维码存在轻微损坏或噪声时仍能正确恢复数据。
验收标准
1. WHEN 对一个数据块执行 Reed-Solomon 纠错时,THE TCnQRDecoder SHALL 使用 GF(2^8) 域(生成多项式 0x11D,原根 2)对数据块中的数据码字和纠错码字联合进行纠错运算,计算伴随式多项式、错误位置多项式(Berlekamp-Massey 或 Euclidean 算法)和错误值多项式(Forney 算法)。 2. WHEN 执行 GF(2^8) 域运算时,THE TCnQRDecoder SHALL 使用已有的 CN_LOG_TABLE 和 CN_EXP_TABLE 常量表完成乘法(log 相加后查 exp 表)和除法(log 相减后查 exp 表)运算,零元素特殊处理。 3. WHEN 数据块中的错误数量不超过 floor(纠错码字数 / 2) 时,THE TCnQRDecoder SHALL 成功纠正所有错误并返回纠正后的数据码字。 4. WHEN 某个数据块中的错误数量超过 floor(纠错码字数 / 2) 时,THE TCnQRDecoder SHALL 立即停止对该块的纠错并返回校验和错误(Checksum Error),不继续处理后续数据块。 5. WHEN 所有数据块纠错完成后,THE TCnQRDecoder SHALL 按块顺序拼接各块的数据码字,形成完整的数据字节流。 6. THE TCnQRDecoder SHALL 仅将数据码字(非纠错码字)部分传递给后续的比特流解析步骤。
需求 7:比特流解析与编码模式还原
用户故事: 作为开发者,我希望解码器能从纠错后的数据字节流中解析各编码模式段并还原原始文本,以便最终输出可读的字符串内容。
验收标准
1. WHEN 开始解析数据字节流时,THE TCnQRDecoder SHALL 循环读取 4 位模式指示符,根据其值确定当前段的编码模式。 2. WHEN 模式指示符为 0000(终止符)或剩余位数不足 4 位时,THE TCnQRDecoder SHALL 停止解析并返回已累积的文本结果。 3. WHEN 模式为 Numeric(0001),THE TCnQRDecoder SHALL 读取字符计数位(版本 1..9 为 10 位,版本 10..26 为 12 位,版本 27..40 为 14 位),然后每次读取 10 位解码 3 个数字、7 位解码 2 个数字、4 位解码 1 个数字,直到处理完所有字符。 4. WHEN 模式为 AlphaNumeric(0010),THE TCnQRDecoder SHALL 读取字符计数位(版本 1..9 为 9 位,版本 10..26 为 11 位,版本 27..40 为 13 位),然后每次读取 11 位解码 2 个字符(第一字符 = 值 / 45,第二字符 = 值 mod 45),剩余 1 个字符读取 6 位,使用 45 字符字母表(0-9、A-Z、空格、$、%、*、+、-、.、/、:)还原。 5. WHEN 模式为 Byte(0100),THE TCnQRDecoder SHALL 读取字符计数位(版本 1..9 为 8 位,版本 10..40 为 16 位),然后每次读取 8 位作为一个字节,按 ISO-8859-1 或 UTF-8 编码(根据 ECI 指定或自动检测)还原字符串。 6. WHEN 模式为 Kanji(1000),THE TCnQRDecoder SHALL 读取字符计数位(版本 1..9 为 8 位,版本 10..26 为 10 位,版本 27..40 为 12 位),然后每次读取 13 位,按 Shift-JIS 编码还原日文汉字。 7. WHEN 模式为 Hanzi(1101),THE TCnQRDecoder SHALL 读取 4 位子集指示符,再读取字符计数位(版本 1..9 为 8 位,版本 10..26 为 10 位,版本 27..40 为 12 位),然后每次读取 13 位,按 GB2312 编码还原汉字。 8. WHEN 模式为 ECI(0111),THE TCnQRDecoder SHALL 读取 ECI 指定值(1 字节、2 字节或 3 字节格式),并将后续 Byte 模式段按指定字符集解码。 9. WHEN 模式为 Structured Append(0011),THE TCnQRDecoder SHALL 读取 8 位符号序列号和 8 位奇偶校验数据,并继续解析后续段。 10. IF 解析过程中剩余位数不足以完成当前模式的读取,THEN THE TCnQRDecoder SHALL 返回格式错误。
需求 8:镜像矩阵重试机制
用户故事: 作为开发者,我希望解码器在正常解码失败时能自动尝试镜像矩阵后重新解码,以便处理被镜像拍摄或打印的二维码图像。
验收标准
1. WHEN 对 TCnQRData 矩阵进行正常解码(格式信息读取、版本信息读取、码字提取、RS 纠错、比特流解析)失败时,THE TCnQRDecoder SHALL 自动尝试镜像解码流程。 2. WHEN 执行镜像解码时,THE TCnQRDecoder SHALL 先将矩阵沿主对角线翻转(即将 QRData[X, Y] 与 QRData[Y, X] 互换),生成镜像矩阵。 3. WHEN 镜像矩阵生成后,THE TCnQRDecoder SHALL 对镜像矩阵重新执行完整的解码流程(格式信息读取、版本信息读取、去掩码、码字提取、RS 纠错、比特流解析)。 4. WHEN 镜像解码成功时,THE TCnQRDecoder SHALL 在解码结果中标记该结果来自镜像矩阵(通过 IsMirrored 属性或输出参数)。 5. WHEN 正常解码和镜像解码均失败时,THE TCnQRDecoder SHALL 返回原始正常解码时产生的错误(格式错误或校验和错误)。 6. THE TCnQRDecoder SHALL 在镜像重试时重置格式信息和版本信息的缓存,确保重新从镜像矩阵读取这些信息。
需求 9:图像二值化(自适应阈值)
用户故事: 作为开发者,我希望解码器能将 TBitmap 灰度图像转换为黑白二值矩阵,以便后续的寻像图案定位算法能在二值化后的矩阵上工作。
验收标准
1. WHEN 给定一幅 TBitmap 图像,THE TCnQRBinarizer SHALL 首先将图像转换为灰度图(若图像为彩色,则按 Gray = R * 0.299 + G * 0.587 + B * 0.114 计算灰度值)。 2. THE TCnQRBinarizer SHALL 将图像划分为若干 8x8 像素的子块,对每个子块统计灰度直方图,计算局部自适应阈值。 3. WHEN 计算子块阈值时,THE TCnQRBinarizer SHALL 取该子块灰度直方图中最暗 5% 像素和最亮 5% 像素的平均值作为局部阈值;IF 子块内灰度范围过小(最大值与最小值之差小于 24),THEN THE TCnQRBinarizer SHALL 使用全局阈值(128)代替局部阈值。 4. WHEN 对每个像素进行二值化时,THE TCnQRBinarizer SHALL 将灰度值小于对应子块阈值的像素标记为黑色(值 1),其余像素标记为白色(值 0)。 5. THE TCnQRBinarizer SHALL 输出与输入图像等尺寸的 TCnQRData 矩阵,其中每个元素为 0 或 1。 6. WHEN 输入图像宽度或高度小于 21 像素时,THE TCnQRBinarizer SHALL 返回图像尺寸不足错误。
需求 10:寻像图案定位
用户故事: 作为开发者,我希望检测器能在二值矩阵中准确定位三个寻像图案的中心坐标,以便后续计算透视变换参数。
验收标准
1. WHEN 对二值矩阵执行寻像图案扫描时,THE TCnQRDetector SHALL 逐行扫描,统计每行中连续黑-白-黑-白-黑五段的像素计数,检测满足 1:1:3:1:1 比例的候选位置(判定条件:每段计数与 totalCount/7 的偏差不超过 totalCount/14,中间段偏差不超过 3*totalCount/14)。 2. WHEN 水平扫描发现候选位置时,THE TCnQRDetector SHALL 在该候选位置的估算列坐标(centerFromEnd = end - stateCount[4] - stateCount[3] - stateCount[2]/2)处执行垂直交叉验证,检查垂直方向是否也满足 1:1:3:1:1 比例,并以垂直方向的 centerFromEnd 公式精确行坐标。 3. WHEN 垂直交叉验证通过时,THE TCnQRDetector SHALL 以精确行坐标重新执行水平扫描,用 centerFromEnd 公式进一步精确列坐标;IF 水平二次验证的总像素数与原始水平扫描总像素数偏差超过 20%,THEN THE TCnQRDetector SHALL 放弃该候选点。 4. WHEN 水平和垂直验证均通过时,THE TCnQRDetector SHALL 执行对角线验证(从精确中心向左上和右下方向扫描),检查对角方向是否满足 1:1:3:1:1 比例(允许 75% 以内偏差,即每段偏差不超过 totalCount/1.333/7)。 5. WHEN 四重验证(水平、垂直、水平二次、对角线)均通过时,THE TCnQRDetector SHALL 将该位置记录为寻像图案候选中心,并估算模块尺寸(总像素数 / 7)。 6. WHEN 新候选中心与已有候选中心的距离小于已有候选中心估算模块尺寸的 10 倍时,THE TCnQRDetector SHALL 将两者合并(取加权平均坐标和模块尺寸),并增加该候选点的确认计数;否则新增一个独立候选点。 7. WHEN 扫描完成后,THE TCnQRDetector SHALL 从所有候选中心中选出三个最佳寻像图案,要求:三个图案的估算模块尺寸相差不超过 40%,且三点构成接近等腰直角三角形(最小化 |c^2 - 2b^2| + |c^2 - 2a^2|,其中 a ≤ b ≤ c 为三边长度平方)。 8. WHEN 无法找到满足条件的三个寻像图案时,THE TCnQRDetector SHALL 返回未找到图案错误(Not Found Error)。 9. WHEN 三个最佳寻像图案确定后,THE TCnQRDetector SHALL 按以下规则排序:计算三点两两距离,最长边对面的点为左上角;在剩余两点中,叉积为正的点为右上角,另一点为左下角。
需求 11:对齐图案定位
用户故事: 作为开发者,我希望检测器能在版本 2 及以上的二维码中定位对齐图案,以便提高透视变换的精度,从而正确处理倾斜或畸变的图像。
验收标准
1. WHEN 根据三个寻像图案估算的版本号大于 1 时,THE TCnQRDetector SHALL 尝试在估算的对齐图案位置附近搜索对齐图案。 2. THE TCnQRDetector SHALL 根据三个寻像图案中心坐标估算"右下角"位置(bottomRightX = topRight.X - topLeft.X + bottomLeft.X,bottomRightY = topRight.Y - topLeft.Y + bottomLeft.Y),并在距该位置 3 个模块处估算对齐图案中心。 3. THE TCnQRDetector SHALL 在估算中心周围以模块尺寸的 4 倍为初始搜索半径,扫描满足 1:1:1 比例(黑-白-黑)的候选对齐图案位置。 4. WHEN 初始搜索半径内未找到对齐图案时,THE TCnQRDetector SHALL 将搜索半径加倍(最多扩大到 16 倍模块尺寸)后重试。 5. WHEN 找到满足 1:1:1 比例的候选位置时,THE TCnQRDetector SHALL 执行垂直和水平交叉验证,确认该位置为对齐图案中心。 6. WHEN 所有搜索半径均未找到对齐图案时,THE TCnQRDetector SHALL 继续执行后续步骤(不将对齐图案纳入透视变换),而不返回错误。
需求 12:透视变换与网格采样
用户故事: 作为开发者,我希望检测器能根据寻像图案和对齐图案的坐标计算透视变换矩阵,并通过网格采样将图像中的二维码区域映射为规范化的 TCnQRData 矩阵。
验收标准
1. WHEN 获得三个寻像图案中心坐标后,THE TCnQRDetector SHALL 分别计算左上到右上、左上到左下的像素距离,取两者平均值除以模块尺寸后加 7,四舍五入得到初始维度,再将其调整为满足 (Dimension - 1) mod 4 = 0 的最近合法值(即 Dimension mod 4 = 1)。 2. WHEN 找到对齐图案时,THE TCnQRDetector SHALL 使用以下四点映射构造透视变换矩阵:源点(左上寻像图案、右上寻像图案、对齐图案、左下寻像图案)→ 目标点((3.5, 3.5)、(Dim-3.5, 3.5)、(Dim-6.5, Dim-6.5)、(3.5, Dim-3.5)),其中 Dim = Dimension。 3. WHEN 未找到对齐图案时,THE TCnQRDetector SHALL 推算右下角坐标(bottomRightX = topRight.X - topLeft.X + bottomLeft.X,bottomRightY = topRight.Y - topLeft.Y + bottomLeft.Y),使用四点映射:源点(左上、右上、右下推算点、左下)→ 目标点((3.5, 3.5)、(Dim-3.5, 3.5)、(Dim-3.5, Dim-3.5)、(3.5, Dim-3.5))。 4. THE TCnQRDetector SHALL 使用 George Wolberg 透视变换算法(四边形到四边形映射,通过四边形到正方形再到四边形的复合变换)计算 3x3 透视变换矩阵,矩阵系数以单精度浮点数存储。 5. WHEN 透视变换矩阵计算完成后,THE TCnQRDetector SHALL 对规范化网格中每个模块中心坐标(col + 0.5,row + 0.5)执行逆变换,得到对应的二值化图像像素坐标,并采样该坐标处的二值(0 或 1)。 6. THE TCnQRDetector SHALL 将采样结果填入 TCnQRData 矩阵,输出尺寸为 Dimension x Dimension 的矩阵,其中 QRData[col, row] 对应网格列 col、行 row 的采样值。 7. IF 透视变换后采样坐标超出图像边界,THEN THE TCnQRDetector SHALL 将该模块视为白色(值 0)。
需求 13:端到端从 TBitmap 解码
用户故事: 作为应用开发者,我希望能通过一个简单的接口直接将 TBitmap 图像解码为文本字符串,以便在应用程序中快速集成二维码扫描功能。
验收标准
1. THE TCnQRDecoder SHALL 提供一个函数(如 CnQRDecodeFromBitmap),接受 TBitmap 参数,返回解码后的文本字符串和布尔型成功标志。 2. WHEN 调用端到端解码函数时,THE TCnQRDecoder SHALL 依次执行:图像二值化(需求 9)、寻像图案定位(需求 10)、对齐图案定位(需求 11)、透视变换与网格采样(需求 12)、矩阵解码(需求 1..8)。 3. WHEN 任一阶段失败时,THE TCnQRDecoder SHALL 停止后续处理,将成功标志设为 False,并通过输出参数或异常返回具体错误信息。 4. WHEN 所有阶段均成功时,THE TCnQRDecoder SHALL 将成功标志设为 True,并返回解码后的文本字符串。 5. THE TCnQRDecoder SHALL 同时提供一个函数(如 CnQRDecodeFromMatrix),直接接受 TCnQRData 参数执行阶段一解码,供已有矩阵数据的场景使用。 6. WHEN 输入的 TBitmap 为 nil 或尺寸为 0 时,THE TCnQRDecoder SHALL 返回参数错误,不执行任何解码操作。
需求 14:错误处理
用户故事: 作为开发者,我希望解码器在遇到各类错误时能返回明确的错误类型和描述,以便调用方能区分不同的失败原因并采取相应处理措施。
验收标准
1. WHEN 格式信息或版本信息无法解析时,THE TCnQRDecoder SHALL 返回格式错误(Format Error),并在错误信息中说明是格式信息还是版本信息解析失败。 2. WHEN Reed-Solomon 纠错失败(错误数量超过纠错能力)时,THE TCnQRDecoder SHALL 返回校验和错误(Checksum Error),并在错误信息中指明是哪个数据块纠错失败。 3. WHEN 在图像中无法找到三个有效的寻像图案时,THE TCnQRDetector SHALL 返回未找到图案错误(Not Found Error)。 4. WHEN 比特流解析过程中遇到未知的模式指示符时,THE TCnQRDecoder SHALL 返回格式错误。 5. WHEN 比特流解析过程中字符计数超出剩余可用位数时,THE TCnQRDecoder SHALL 返回格式错误。 6. THE TCnQRDecoder SHALL 使用已有的 ECnQRCodeException 异常类(或其子类)报告所有解码错误,异常消息应包含足够的上下文信息。 7. WHILE 执行镜像重试时,THE TCnQRDecoder SHALL 保留原始错误信息,仅在镜像重试也失败后才抛出原始错误。
正确性属性(用于属性测试)
以下属性描述了解码功能应满足的不变量和往返性质,可用于属性测试(Property-Based Testing)。
属性 1:编码-解码往返性(Round-Trip Property)
描述: 对于任意合法的输入文本,先用 TCnQREncoder 编码生成 TCnQRData 矩阵,再用 TCnQRDecoder 解码,应得到与原始输入相同的文本。
形式化表达:
FOR ALL text: String WHERE CnQREncode(text) succeeds,
CnQRDecodeFromMatrix(CnQREncode(text).QRData) = text适用范围:
• Numeric 模式:纯数字字符串(0-9),长度 1..7089 • AlphaNumeric 模式:大写字母、数字及特殊字符(0-9、A-Z、空格、$、%、*、+、-、.、/、:),长度 1..4296 • Byte 模式:任意 ASCII 字符串,长度 1..2953 • 各纠错级别(erlL、erlM、erlQ、erlH) • 版本 1..40
测试建议: 使用属性测试框架生成随机文本,验证往返一致性。
属性 2:去掩码幂等性(Idempotence Property)
描述: 对同一矩阵连续执行两次相同掩码类型的去掩码操作,结果应与原始矩阵相同(因为去掩码等价于异或,两次异或等于恒等变换)。
形式化表达:
FOR ALL matrix: TCnQRData, maskType: 0..7,
ApplyUnmask(ApplyUnmask(matrix, maskType), maskType) = matrix测试建议: 对随机矩阵和随机掩码类型验证此属性。
属性 3:格式信息解码稳定性(Error Correction Property)
描述: 对于任意合法的格式信息值,在其 15 位编码中翻转不超过 3 位后,解码结果应与原始格式信息相同。
形式化表达:
FOR ALL formatInfo: TCnQRFormatInfo, errorBits: Integer WHERE errorBits <= 3,
DecodeFormatInfo(FlipBits(EncodeFormatInfo(formatInfo), errorBits)) = formatInfo测试建议: 对所有 32 种合法格式信息值,枚举所有 1 位、2 位、3 位翻转组合,验证解码正确性。
属性 4:版本信息解码稳定性(Error Correction Property)
描述: 对于任意合法的版本信息值(版本 7..40),在其 18 位编码中翻转不超过 3 位后,解码结果应与原始版本号相同。
形式化表达:
FOR ALL version: 7..40, errorBits: Integer WHERE errorBits <= 3,
DecodeVersionInfo(FlipBits(EncodeVersionInfo(version), errorBits)) = version测试建议: 对版本 7..40 的所有合法版本信息值,枚举 1..3 位翻转,验证解码正确性。
属性 5:Reed-Solomon 纠错能力(Error Correction Property)
描述: 对于任意合法的数据块,在其码字中引入不超过 floor(纠错码字数 / 2) 个错误后,Reed-Solomon 解码应能恢复原始数据码字。
形式化表达:
FOR ALL dataBlock: TBytes, ecCodewords: Integer, errors: Integer
WHERE errors <= ecCodewords / 2,
RSDecodeWithErrors(RSEncode(dataBlock, ecCodewords), errors) = dataBlock测试建议: 对随机数据块,在随机位置引入随机数量(不超过纠错能力)的错误,验证纠错后数据与原始数据一致。
属性 6:透视变换可逆性(Round-Trip Property)
描述: 对于任意四点透视变换,将源坐标变换到目标坐标后,再用逆变换变换回来,应得到与原始坐标近似相等的值(浮点误差在 0.001 以内)。
形式化表达:
FOR ALL point: (Float, Float), transform: TCnQRPerspectiveTransform,
|InverseTransform(Transform(point, transform), transform) - point| < 0.001测试建议: 对随机四点集合构造透视变换,验证正变换和逆变换的往返精度。
属性 7:寻像图案比例不变性(Metamorphic Property)
描述: 对于任意满足 1:1:3:1:1 比例的五段像素计数,将所有计数等比例缩放后,foundPatternCross 函数的判断结果应保持不变。
形式化表达:
FOR ALL stateCount: array[0..4] of Integer WHERE foundPatternCross(stateCount) = True,
FOR ALL scale: Integer WHERE scale >= 1,
foundPatternCross(ScaleStateCount(stateCount, scale)) = True测试建议: 生成满足 1:1:3:1:1 比例的随机计数,验证等比缩放后仍能被识别。
属性 8:二值化输出范围不变量(Invariant Property)
描述: 对于任意输入图像,二值化输出矩阵中每个元素的值必须为 0 或 1。
形式化表达:
FOR ALL bitmap: TBitmap WHERE bitmap.Width >= 21 AND bitmap.Height >= 21,
FOR ALL x: 0..bitmap.Width-1, y: 0..bitmap.Height-1,
Binarize(bitmap)[x, y] IN {0, 1}测试建议: 对随机生成的图像(包括全黑、全白、随机噪声、渐变等)验证此不变量。
夜雨聆风