Неверно извлекается бит одного из каналов RGB пикселя. Стеганография, LSB
Появилась проблема с извлечением последнего бита выбранного канала пикселя. Есть программа по стеганографии с алгоритмом LSB, которая работает. Смысл алгоритма в том, что символ разбивается на части побитово и записывается в последние биты байта картинки, то есть в rgb 1 пикселя, второго, и т.д. Делается это последовательно в каждый цветовой канал. Я переделал под кодировку в конкретный RGB. То есть, выбирается RGB-спектр и только в него, пропуская другие, записывается бит символа. И вроде бы как с упаковкой текста в изображение проблем нет, но с его извлечением появились проблемы. Извлекаемый бит всегда стал равен 0. И собираемый символ кодируется в NULL согласно таблице ASCII.
Вот код на Python для декодирования:
def decode_image(encoded_img, output_txt, symbols_to_read):
img_mask = 0b11111110
img_mask = ~img_mask
print(bin(img_mask))
img_len = os.stat(encoded_img).st_size
selected_rgb = choose_rgb()
if symbols_to_read >= img_len / 24 - BMP_HEADER_SIZE:
print("Too much symbols to read")
return False
text = open(output_txt, 'w', encoding='utf-8')
encoded_bmp = open(encoded_img, 'rb')
encoded_bmp.seek(BMP_HEADER_SIZE + selected_rgb)
read = 0
while read < symbols_to_read:
symbol = 0
for bits_read in range(0, 8):
img_byte = int.from_bytes(encoded_bmp.read(1), sys.byteorder) &\
img_mask
symbol <<= 1
symbol |= img_byte
encoded_bmp.seek(2)
if chr(symbol) == '\n' and len(os.linesep) == 2:
read += 1
read += 1
print("Symbol #{0} is {1:c}".format(read, symbol))
text.write(chr(symbol))
text.close()
encoded_bmp.close()
return True
def choose_rgb():
chosen_rgb = int(input("Choose a color spectrum to encode:\n1 - Red;"
" 2 - Blue; 3 - Green:\n"))
return chosen_rgb - 1
to_read = int(input("How many characters are in the ciphertext?\n"))
image_file = "encoded.bmp"
decode_image(image_file, "result.txt", to_read)
Для того, чтобы пропустить 2 спектра без закодированной информации, было добавлено значение [0;2] к заголовку bmp для выбора спектра encoded_bmp.seek(BMP_HEADER_SIZE + selected_rgb)
и далее в цикле извлечения бита пропускается 2 байта методом .seek() encoded_bmp.seek(2).
Заметил, что проблема возникает как раз в этом месте, при переносе указателя файла на 2 байта. Если убрать эту строку, то всё работает и переменная img_byte принимает действительные значения последнего бита, отличные от 0.
Подскажите, в чём ошибка? Вроде бы как должно быть всё верно, но в этом месте кода что-то не работает.
for bits_read in range(0, 8):
img_byte = int.from_bytes(encoded_bmp.read(1), sys.byteorder) &\
img_mask
symbol <<= 1
symbol |= img_byte
encoded_bmp.seek(2)
И, похоже, проблема возникает при перемещении указателя по байтам изображения. Не понимаю, почему так происходит.
Напомню, при выполнении кода из-за того, что img_byte всегда принимает значение "0", генерируются символы NULL и записываются в файл "result.txt" в количестве указанном изначально переменной to_read. Но если извлекать бит у каждого байта, то всё работает корректно, декодированный текст из картинки идентичен закодированному ранее.