Неверно извлекается бит одного из каналов 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. Но если извлекать бит у каждого байта, то всё работает корректно, декодированный текст из картинки идентичен закодированному ранее.


Ответы (0 шт):