Python Pillow调用putpixel修改图片像素仅首个像素生效问题
Pillow putpixel仅首个像素修改生效问题修复
问题根因
你的代码存在4个逻辑错误共同导致该现象:
- 二进制串生成时未补全8位前导零,导致二进制总长度远小于预期,提前触发终止逻辑
- 处理到文本最后一位时直接return,未将当前已修改的像素写入图片
- 像素遍历顺序为列优先,和
getdata()返回的行优先顺序不一致,导致打印结果和预期对不上 - 若原图为索引色PNG,直接修改像素值不会生效(该场景概率较高)
修复步骤
- 补全二进制串的8位填充
将原代码的二进制转换逻辑:
text = ''.join(format(x,'b') for x in bytes(text,"ascii"))
修改为:
# 每个ASCII字符固定转换为8位二进制,不足补前导零 text = ''.join(format(x, '08b') for x in bytes(text, "ascii"))
修正终止逻辑,避免提前返回
将k循环内的提前return逻辑移到像素写入操作之后,处理完所有文本位后再返回,避免未保存当前像素的修改就退出。调整像素遍历顺序为行优先
将原有的外层x内层y的循环,调整为外层y内层x,和getdata()的顺序保持一致,避免打印结果和预期顺序错位。统一图片像素格式
打开图片后先转为RGBA模式,避免索引色模式下修改像素不生效。
修复后完整代码
from PIL import Image def encode(text,image): pixels = image.load() # 补全8位二进制 text = ''.join(format(x,'08b') for x in bytes(text,"ascii")) print(text) iteration = 0 # 调整为行优先遍历,和getdata顺序一致 for j in range(image.size[1]): for i in range(image.size[0]): tmp = list(pixels[i,j]) for k in range(len(tmp)): if iteration >= len(text): break elif text[iteration]=="0": if tmp[k]%2!=0: if tmp[k]==255: tmp[k]-=1 else: tmp[k]+=1 elif text[iteration]=="1": if tmp[k]%2==0: tmp[k]+=1 iteration +=1 # 直接修改load出来的像素对象即可,不需要额外调用putpixel pixels[i,j] = tuple(tmp) print(f"pixel : {pixels[i,j]}") # 所有位处理完后返回,避免提前退出 if iteration >= len(text): return image return image if __name__ == "__main__": img = Image.open("C:/Users/Toavina/Pictures/Crypto/icon.PNG") # 转为RGBA模式,避免索引色原图导致修改失效 img = img.convert("RGBA") img = encode("test_data",img) # 打印修改后的像素 for pixel in img.getdata(): print(pixel)
内容的提问来源于stack exchange,提问作者Toavina Tokiniaina
相关产品推荐
相关产品推荐

