py steganography
Школьный проект.
Код из файлика для кодировки:
from PIL import Image
def encode_image(image_path, message, output_path):
img = Image.open(image_path)
img = img.convert('RGB')
binary_message = ''.join(format(ord(i), '08b') for i in message)
binary_message += '1111111111111110'
message_index = 0
pixels = img.load()
for i in range(img.width):
for j in range(img.height):
pixel = list(pixels[i, j])
for n in range(3):
if message_index < len(binary_message):
pixel[n] = pixel[n] & 0xFE | int(binary_message[message_index])
message_index += 1
pixels[i, j] = tuple(pixel)
if message_index >= len(binary_message):
break
else:
continue
break
img.save(output_path)
s = input('Введите сообщение, которое хотите скрыть в иозбражении (используйте латиницу или цифры) \n')
encode_image('input_image.png', s, 'encoded_image.png')
код файлик из для получения смски из изображения:
from PIL import Image
def decode_image(image_path):
img = Image.open(image_path)
img = img.convert('RGB')
pixels = img.load()
binary_message = ''
for i in range(img.width):
for j in range(img.height):
pixel = pixels[i, j]
for n in range(3):
binary_message += str(pixel[n] & 1)
if binary_message[-16:] == '1111111111111110':
break
else:
continue
break
message = ''
for i in range(0, len(binary_message) - 16, 8):
byte = binary_message[i:i + 8]
message += chr(int(byte, 2))
return message
hidden_message = decode_image('encoded_image.png')
print("Извлеченное сообщение:", hidden_message)
по итогу извлеченное сообщение я получаю, но с огромным количеством рандомных символов
(9ü ?UUoV¥R©[jz¤¿©¸ÜI$©%U Î?9½’8íŽÇlq$ìq8’N ð?à ?ü~ ÿ и тп) .
вероятно, дело либо в кодировках, либо с фоткой че-т происходит. может вы чего подскажите?
Ответы (2 шт):
Современные кодировки русского языка 2-байтовые. Одного байта вам не хватит чтобы закодировать код русского символа, получающийся через ord(i)
. Проверим это утверждение:
x = format(ord('а'), '08b')
print(x, len(x))
# 10000110000 11
Получилось 11 битов, а не 8, на которые вы рассчитывали при обратной расшифровке. Поэтому всё и "поехало" у вас.
Чиним это так. Переделываем однобайтовое кодирование в двухбайтовое. И стоп-слово тоже увеличиваем с 2-х байт, до 4-х.
# binary_message = ''.join(format(ord(i), '08b') for i in message)
# binary_message += '1111111111111110'
binary_message = ''.join(format(ord(i), '016b') for i in message)
binary_message += '11111111111111111111111111111110'
...
# if binary_message[-16:] == '1111111111111110':
if binary_message[-32:] == '11111111111111111111111111111110':
...
# for i in range(0, len(binary_message) - 16, 8):
# byte = binary_message[i:i + 8]
for i in range(0, len(binary_message) - 32, 16):
byte = binary_message[i:i + 16]
После этих изменений вроде бы нормально работает и с русскими буквами.
я бы не использовал ord
import bitarray
binary_message = bitarray.bitarray()
binary_message.frombytes(message.encode('utf-8'))
binary_message += '1111111111111110'
обратно
binary_message.tobytes()[:-2].decode('utf-8')