提取水印时 bytes.fromhex() 报错 ValueError:Hex 字符串长度为奇数 (由图片裁剪/平移导致)

Author: 14790897Created Jan 14, 2026Updated Apr 7, 2026

问题描述 (Description) 在使用 extract_text_wmbwm.extract裁剪 (Cropped)平移 后的图片中提取水印时,程序会崩溃并抛出 ValueError

经过分析,这是因为图片数据的部分丢失导致提取出的二进制数据不完整。当这些二进制数据被转换为十六进制字符串时,可能会出现奇数长度的情况(例如 'a' 而不是 '0a')。Python 的 bytes.fromhex() 函数要求输入字符串长度必须为偶数,因此导致报错。

虽然裁剪后的图片提取失败是正常的,但程序应该进行容错处理(例如补零或返回提取失败),而不是直接崩溃。

复现步骤 (To Reproduce)

  1. 对一张图片嵌入水印。
  2. 对图片进行裁剪或微小平移(例如平移 2 个像素)。
  3. 运行提取水印的代码。

报错信息 (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'

修改建议如下:

python
# 原代码
# 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