兩個人想說悄悄話?那就試一下圖片隱寫術吧!
什麼是隱寫術
通過隱寫術,我們可以把一些重要信息隱藏再電子文件中。
如,我們將一段話隱寫在了圖片中,外人看起來就是一張普通的文件。通過解碼後,我們就能查看到隱藏的文字。
隱寫術原理
載體文件相對隱祕文件的大小(指數據含量)越大,隱藏後者就越加容易。
因爲這個原因,數字圖像在因特網和其他傳媒上被廣泛用於隱藏消息。這種方法使用的廣泛程度無從查考。例如:一個24位的位圖中的每個像素的三個顏色分量(紅綠藍)各使用8個比特來表示。如果我們只考慮藍色的話,就是說有2種不同的數值來表示深淺不同的藍色。而像11111111和11111110這兩個值所表示的藍色,人眼幾乎無法區分。因此,這個最低有效位就可以用來存儲顏色之外的信息,而且在某種程度上幾乎是檢測不到的。如果對紅色和綠色進行同樣的操作,就可以在差不多三個像素中存儲一個字節的信息。(百度百科)
用python3實現圖片隱寫術
安裝模塊pillow
若安裝失敗可以嘗試科學上網
pip3 install pillow
代碼
# coding:utf-8
# Python3 圖片隱寫術
from PIL import Image
"""
function:取得一個PIL圖像並且更改所有值爲偶數(使最低有效位爲0)
"""
def makeImageEven(image):
pixels = list(image.getdata()) # 得到一個[(r,g,b,t)]列表
# 更改所有值爲偶數(魔法般的移位)
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
"""
function:內置函數bin()的替代,返回固定長度的二進制字符串
"""
def constLenBin(int):
# 去掉 bin()返回的二進制字符串中的'0b',並在左邊補足'0'直到字符串長度爲8
binary = "0" * (8 - (len(bin(int)) - 2)) + bin(int).replace('0b', '')
return binary
"""
funtion:將字符串編碼到圖片中
"""
def encodeDataInImage(image, data):
evenImage = makeImageEven(image) # 獲得最低有效位爲0的圖片副本
binary = ''.join(map(constLenBin, bytearray(data, 'utf-8'))) # 將要隱藏字符串轉成2進制
# 如果不能編碼全部數據則拋出異常
if len(binary) > len(image.getdata()) * 4:
raise Exception('在此圖像中不能編碼超過' + len(evenImage.getdata()) * 4 + '位')
# 將 binary 中的二進制字符串信息編碼進像素裏
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
"""
function:從二進制字符串轉爲 UTF-8 字符串
"""
def binaryToString(binary):
index = 0
string = []
rec = lambda x, i: x[2:8] + (rec(x[8:], i - 1) if i > 1 else '') if x else ''
# rec = lambda x, i: x and (x[2:8] + (i > 1 and rec(x[8:], i-1) or '')) or ''
fun = lambda x, i: x[i + 1:8] + rec(x[8:], i - 1)
while index + 1 < len(binary):
chartype = binary[index:].index('0')
length = chartype * 8 if chartype else 8
string.append(chr(int(fun(binary[index:index + length], chartype), 2)))
index += length
return ''.join(string)
"""
function:解碼隱藏數據
"""
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("test.png"), '我腿短呀').save('test1.png')
print(decodeImage(Image.open("test1.png")))
參考文章:https://blog.csdn.net/m0_37713821/article/details/90575417