You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

86 lines
3.4 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

from PIL import Image
def makeImageEven(image):
"""
将图像像素值变为偶数值最低有效位为0
"""
# 获取图像所有像素值的列表:[(r,g,b,t),(r,g,b,t)...]
pixels = list(image.getdata())
# 将所有像素值变为偶数(通过移位)
evenPixels = [(r >> 1 << 1, g >> 1 << 1, b >> 1 << 1, t >> 1 << 1) for [r, g, b, t] in pixels]
# 创建一个与原图像大小相同的副本
evenImage = Image.new(image.mode, image.size)
# 将偶数像素值放入副本中
evenImage.putdata(evenPixels)
return evenImage
def constLenBin(int):
"""
返回固定长度的二进制字符串替代内置函数bin()
"""
# 使用二进制表示整数不足8位在左侧补0
binary = "0" * (8 - (len(bin(int)) - 2)) + bin(int).replace('0b', '')
return binary
def encodeDataInImage(image, data):
"""
将字符串编码到图片中
"""
# 获取最低有效位为0的图片副本
evenImage = makeImageEven(image)
# 将需要隐藏的字符串转换成二进制字符串
binary = ''.join(map(constLenBin, bytearray(data, 'utf-8')))
if len(binary) > len(image.getdata()) * 4:
# 若无法编码全部数据,抛出异常
raise Exception("Error: Can't encode more than" + len(evenImage.getdata()) * 4 + " bits in this image. ")
# 将二进制信息编码进像素值中
encodedPixels = [(r + int(binary[index * 4 + 0]), g + int(binary[index * 4 + 1]), b + int(binary[index * 4 + 2]),
t + int(binary[index * 4 + 3])) if index * 4 < len(binary) else (r, g, b, t) for
index, (r, g, b, t) in enumerate(list(evenImage.getdata()))]
# 创建新图片以存放编码后的像素
encodedImage = Image.new(evenImage.mode, evenImage.size)
# 添加编码后的数据
encodedImage.putdata(encodedPixels)
return encodedImage
def binaryToString(binary):
"""
从二进制字符串转为 UTF-8 字符串
"""
index = 0
string = []
rec = lambda x, i: x[2:8] + (rec(x[8:], i - 1) if i > 1 else '') if x else ''
fun = lambda x, i: x[i + 1:8] + rec(x[8:], i - 1)
while index + 1 < len(binary):
chartype = binary[index:].index('0') # 存放字符所占字节数一个字节的字符会存为0
length = chartype * 8 if chartype else 8
string.append(chr(int(fun(binary[index:index + length], chartype), 2)))
index += length
return ''.join(string)
def decodeImage(image):
"""
解码隐藏数据
"""
pixels = list(image.getdata()) # 获取像素列表
# 提取图片中所有最低有效位中的数据
binary = ''.join([str(int(r >> 1 << 1 != r)) + str(int(g >> 1 << 1 != g)) + str(int(b >> 1 << 1 != b)) + str(
int(t >> 1 << 1 != t)) for (r, g, b, t) in pixels])
# 找到数据截止处的索引
locationDoubleNull = binary.find('0000000000000000')
endIndex = locationDoubleNull + (
8 - (locationDoubleNull % 8)) if locationDoubleNull % 8 != 0 else locationDoubleNull
data = binaryToString(binary[0:endIndex])
return data
# 调用函数对图片进行数据编码并保存
#encodeDataInImage(Image.open("d:/9.png"), 'https://www.hzkjai.com 吉林绘智科技有限公司').save('d:/9.png')
# 解码图片中隐藏的数据并打印
#print(decodeImage(Image.open("d:/9.png")))