Python圖片隱寫術

兩個人想說悄悄話?那就試一下圖片隱寫術吧!

什麼是隱寫術

通過隱寫術,我們可以把一些重要信息隱藏再電子文件中。
如,我們將一段話隱寫在了圖片中,外人看起來就是一張普通的文件。通過解碼後,我們就能查看到隱藏的文字。

隱寫術原理

載體文件相對隱祕文件的大小(指數據含量)越大,隱藏後者就越加容易。

因爲這個原因,數字圖像在因特網和其他傳媒上被廣泛用於隱藏消息。這種方法使用的廣泛程度無從查考。例如:一個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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章