提取水印时 bytes.fromhex() 报错 ValueError:Hex 字符串长度为奇数 (由图片裁剪/平移导致)
Author: 14790897Created Jan 14, 2026Updated Apr 7, 2026
问题描述 (Description)
在使用 extract_text_wm 或 bwm.extract 从裁剪 (Cropped) 或 平移 后的图片中提取水印时,程序会崩溃并抛出 ValueError。
经过分析,这是因为图片数据的部分丢失导致提取出的二进制数据不完整。当这些二进制数据被转换为十六进制字符串时,可能会出现奇数长度的情况(例如 'a' 而不是 '0a')。Python 的 bytes.fromhex() 函数要求输入字符串长度必须为偶数,因此导致报错。
虽然裁剪后的图片提取失败是正常的,但程序应该进行容错处理(例如补零或返回提取失败),而不是直接崩溃。
复现步骤 (To Reproduce)
- 对一张图片嵌入水印。
- 对图片进行裁剪或微小平移(例如平移 2 个像素)。
- 运行提取水印的代码。
报错信息 (Traceback)
File "blind_watermark.py", line 106, in extract
wm = bytes.fromhex(hex(int(byte, base=2))[2:]).decode('utf-8', errors='replace')
ValueError: non-hexadecimal number found in fromhex() arg at position ...
修复建议 (Suggested Fix)
建议在 blind_watermark.py 中修改 extract 函数,在转换前检查 Hex 字符串的长度。如果是奇数,则在前面补 '0'。
修改建议如下:
# 原代码
# wm = bytes.fromhex(hex(int(byte, base=2))[2:]).decode('utf-8', errors='replace')
# 建议修改为 (Fix suggestion)
hex_str = hex(int(byte, base=2))[2:]
if len(hex_str) % 2 != 0:
hex_str = '0' + hex_str
wm = bytes.fromhex(hex_str).decode('utf-8', errors='replace')
Source: guofei9987/blind_watermark