逻辑非常简单,需要numpy
pillow
库,需要位运算基础,直接上代码:
from PIL import Image
import numpy as np
def pack(img: np.ndarray[np.uint8], text: str, encoding: str = 'utf-8') -> np.ndarray[np.uint8]:
img_shape = img.shape # 存储原始图片大小
# 将图片转为[r,g,b,r,g,b,...,r,g,b]形式
img = img.reshape(img_shape[0]*img_shape[1]*img_shape[2])
text = list(bytearray(text, encoding)) # 文本转字节串列表
bytes_long = len(text) # 文本大小
# 隐写文本大小
img[-8] = (img[-8] & 0b1111_1100) | ((bytes_long >> 14) & 0b0000_0011)
img[-7] = (img[-7] & 0b1111_1100) | ((bytes_long >> 12) & 0b0000_0011)
img[-6] = (img[-6] & 0b1111_1100) | ((bytes_long >> 10) & 0b0000_0011)
img[-5] = (img[-5] & 0b1111_1100) | ((bytes_long >> 8) & 0b0000_0011)
img[-4] = (img[-4] & 0b1111_1100) | ((bytes_long >> 6) & 0b0000_0011)
img[-3] = (img[-3] & 0b1111_1100) | ((bytes_long >> 4) & 0b0000_0011)
img[-2] = (img[-2] & 0b1111_1100) | ((bytes_long >> 2) & 0b0000_0011)
img[-1] = (img[-1] & 0b1111_1100) | ((bytes_long ) & 0b0000_0011)
# 隐写文本内容
for i in range(bytes_long):
byte = text[i] # 按字节隐写
img[i * 4 ] = (img[i * 4 ] & 0b1111_1100) | ((byte >> 6) & 0b0000_0011)
img[i * 4 + 1] = (img[i * 4 + 1] & 0b1111_1100) | ((byte >> 4) & 0b0000_0011)
img[i * 4 + 2] = (img[i * 4 + 2] & 0b1111_1100) | ((byte >> 2) & 0b0000_0011)
img[i * 4 + 3] = (img[i * 4 + 3] & 0b1111_1100) | ((byte ) & 0b0000_0011)
img = img.reshape(img_shape) # 复原图片形状
return img
def unpack(img: np.ndarray[np.uint8], encoding: str = 'utf-8') -> str:
# 将图片转为[r,g,b,r,g,b,...,r,g,b]形式
img = img.reshape(img.shape[0]*img.shape[1]*img.shape[2])
# 解码文本大小
bytes_long = (((img[-8] << 14) & 0b1100_0000_0000_0000) |
((img[-7] << 12) & 0b0000_0000_0000_0000) |
((img[-6] << 10) & 0b0000_1100_0000_0000) |
((img[-5] << 8 ) & 0b0000_0011_0000_0000) |
((img[-4] << 6 ) & 0b0000_0000_1100_0000) |
((img[-3] << 4 ) & 0b0000_0000_0011_0000) |
((img[-2] << 2 ) & 0b0000_0000_0000_1100) |
((img[-1] ) & 0b0000_0000_0000_0011))
# 按字节复原文本内容
text = b''
for i in range(bytes_long):
byte = img[i * 4:i * 4 + 4]
byte = (((byte[0] << 6) & 0b1100_0000) | ((byte[1] << 4) & 0b0011_0000) |
((byte[2] << 2) & 0b0000_1100) | (byte[3] & 0b0000_0011))
text += int(byte).to_bytes()
text = str(text, encoding=encoding) # 以特定编码转为字符串
return text
if __name__ == '__main__':
# 隐写
img = Image.open(r"E:\Users\Expector\Desktop\lty.png")
text = open(r"E:\Users\Expector\Desktop\book.txt", 'r', encoding='utf-8')
img = Image.fromarray(pack(np.array(img), text.read()))
img.save(r"E:\Users\Expector\Desktop\lty.c.png")
# 解密
img = Image.open(r"E:\Users\Expector\Desktop\lty.c.png")
text = open(r"E:\Users\Expector\Desktop\book.c.txt", 'w', encoding='utf-8')
text.write(unpack(np.array(img)))
附图: