Optimizations in the LSB module.

This commit is contained in:
cedricbonhomme 2010-10-03 18:45:03 +02:00
parent d0c1c62564
commit dd4bce8a4a
2 changed files with 43 additions and 41 deletions

58
LSB.py
View file

@ -12,45 +12,31 @@ from PIL import Image
def hide(img, message): def hide(img, message):
""" """
Hide a message (string) in an image with the Hide a message (string) in an image with the
LSB (Less Significant Bit) technic. LSB (Least Significant Bit) technique.
""" """
encoded = img.copy() encoded = img.copy()
width, height = img.size width, height = img.size
index = 0 index = 0
message = message + '~~~' message = message + '~~ '
message_bits = tools.a2bits(message) message_bits = tools.a2bits(message)
npixels = width * height
if len(message_bits) > npixels * 3:
return """To long message (%s > %s).""" % (len(message_bits), npixels * 3)
for row in range(height): for row in range(height):
for col in range(width): for col in range(width):
if index + 3 <= len(message_bits) : if index + 3 <= len(message_bits) :
# Get the colour component.
(r, g, b) = img.getpixel((col, row)) (r, g, b) = img.getpixel((col, row))
# Convert int to bits
r_bits = tools.bs(r)
g_bits = tools.bs(g)
b_bits = tools.bs(b)
# Replace (in a list) the least significant bit # Change the Least Significant Bit of each colour component.
# by the bit of the message to hide r = tools.setlsb(r, message_bits[index])
list_r_bits = list(r_bits) g = tools.setlsb(g, message_bits[index+1])
list_g_bits = list(g_bits) b = tools.setlsb(b, message_bits[index+2])
list_b_bits = list(b_bits)
list_r_bits[-1] = message_bits[index]
list_g_bits[-1] = message_bits[index + 1]
list_b_bits[-1] = message_bits[index + 2]
# Convert lists to a strings
r_bits = "".join(list_r_bits)
g_bits = "".join(list_g_bits)
b_bits = "".join(list_b_bits)
# Convert strings of bits to int
r = int(r_bits, 2)
g = int(g_bits, 2)
b = int(b_bits, 2)
# Save the new pixel # Save the new pixel
encoded.putpixel((col, row), (r, g , b)) encoded.putpixel((col, row), (r, g , b))
@ -61,8 +47,8 @@ def hide(img, message):
def reveal(img): def reveal(img):
""" """
Find a message in an image (with the Find a message in an image
LSB technic). (with the LSB technique).
""" """
width, height = img.size width, height = img.size
bits = "" bits = ""
@ -73,12 +59,12 @@ def reveal(img):
bits += tools.bs(r)[-1] + tools.bs(g)[-1] + tools.bs(b)[-1] bits += tools.bs(r)[-1] + tools.bs(g)[-1] + tools.bs(b)[-1]
if len(bits) >= 8: if int(bits[-8:], 2) == 126:
if chr(int(bits[-8:], 2)) == '~': # chr(126) = '~ '
list_of_string_bits = ["".join(list(bits[i*8:(i*8)+8])) for i in range(0, len(bits)/8)] list_of_string_bits = ["".join(list(bits[i:(i+8)])) for i in range(0, len(bits)-8, 8)]
list_of_character = [chr(int(elem, 2)) for elem in list_of_string_bits] list_of_character = [chr(int(elem, 2)) for elem in list_of_string_bits]
return "".join(list_of_character)[:-1] return "".join(list_of_character)
return "" return ""
@ -86,7 +72,7 @@ if __name__ == '__main__':
# Point of entry in execution mode # Point of entry in execution mode
original_image_file = "./pictures/Lenna.png" original_image_file = "./pictures/Lenna.png"
encoded_image_file = "Lenna_enc.png" encoded_image_file = "Lenna_enc.png"
secret_message = "Avec la technique LSB (Least Significant Bit) l'oeil humain (un normal ;-)) ne voit plus la difference!" secret_message = "Avec la technique LSB (Least Significant Bit) l'oeil humain (un normal ;-)) ne voit plus la difference"
img1 = Image.open(original_image_file) img1 = Image.open(original_image_file)
img_encoded = hide(img1, secret_message) img_encoded = hide(img1, secret_message)

View file

@ -3,10 +3,9 @@
def a2bits(chars): def a2bits(chars):
""" """
Convert a string to its bits representation as a string of 0's and 1's. Converts a string to its bits representation as a string of 0's and 1's.
>>> a2bits("Hello World!") >>> a2bits("Hello World!")
'010010000110010101101100011011000110111100100000010101110110111101110010011011000110010000100001' '010010000110010101101100011011000110111100100000010101110110111101110010011011000110010000100001'
@ -17,7 +16,7 @@ def a2bits_list(chars):
""" """
Convert a string to its bits representation as a list of 0's and 1's. Convert a string to its bits representation as a list of 0's and 1's.
>>> a2bits_list("Hello Word!") >>> a2bits_list("Hello World!")
['01001000', ['01001000',
'01100101', '01100101',
'01101100', '01101100',
@ -37,6 +36,23 @@ def a2bits_list(chars):
def bs(s): def bs(s):
""" """
Convert an int to its bits representation as a string of 0's and 1's. Converts an int to its bits representation as a string of 0's and 1's.
""" """
return str(s) if s<=1 else bs(s>>1) + str(s&1) return str(s) if s<=1 else bs(s>>1) + str(s&1)
def setlsb(component, bit):
"""
Set Least Significant Bit of a colour component.
"""
return component & ~1 | int(bit)
def n_at_a_time(items, n, fillvalue):
"""
Returns an iterator which groups n items at a time.
Any final partial tuple will be padded with the fillvalue
>>> list(n_at_a_time([1, 2, 3, 4, 5], 2, 'X'))
[(1, 2), (3, 4), (5, 'X')]
"""
it = iter(items)
return its.izip_longest(*[it] * n, fillvalue=fillvalue)