""" Модуль LSB (Least Significant Bit) стеганографии. Скрывает текст в изображении путем замены последних битов пикселей. Каждый пиксель RGB хранит 3 бита информации (по одному в каждом канале). """ import numpy as np from PIL import Image from .utils import text_to_bits, bits_to_text def encode_lsb(image_path: str, message: str, output_path: str) -> bool: """ Скрывает текстовое сообщение в изображении методом LSB. Алгоритм: 1. Преобразует текст в битовую строку 2. Добавляет стоп-маркер (8 нулевых битов) для обозначения конца 3. Проходит по всем пикселям изображения 4. В каждом канале (R,G,B) заменяет последний бит на бит сообщения Аргументы: image_path (str): Путь к исходному изображению message (str): Текст для сокрытия output_path (str): Путь для сохранения результата Возвращает: bool: True если успешно, False если сообщение слишком длинное """ # Загружаем изображение img = Image.open(image_path).convert('RGB') pixels = np.array(img, dtype=np.uint8) height, width, channels = pixels.shape # Преобразуем сообщение в биты и добавляем стоп-маркер bits = text_to_bits(message) + '00000000' # Проверяем, поместится ли сообщение max_bits = height * width * channels if len(bits) > max_bits: print(f"Ошибка: сообщение слишком большое.") print(f"Доступно битов: {max_bits}, требуется: {len(bits)}") return False # Прячем биты в изображение bit_index = 0 total_bits = len(bits) for i in range(height): for j in range(width): for c in range(channels): if bit_index >= total_bits: break pixel_value = pixels[i, j, c] bit = int(bits[bit_index]) # Обнуляем последний бит и устанавливаем нужный pixels[i, j, c] = (pixel_value & 0xFE) | bit bit_index += 1 if bit_index >= total_bits: break if bit_index >= total_bits: break # Сохраняем измененное изображение result_img = Image.fromarray(pixels, mode='RGB') result_img.save(output_path) print(f"Успешно! Спрятано {total_bits} бит ({total_bits // 8} байт)") return True def decode_lsb(image_path: str) -> str: """ Извлекает скрытое сообщение из изображения методом LSB. Алгоритм: 1. Проходит по всем пикселям изображения 2. Из каждого канала извлекает последний бит 3. Собирает биты в байты 4. Останавливается при обнаружении стоп-маркера (8 нулевых битов) Аргументы: image_path (str): Путь к изображению со скрытым сообщением Возвращает: str: Извлеченное сообщение """ # Загружаем изображение img = Image.open(image_path).convert('RGB') pixels = np.array(img, dtype=np.uint8) height, width, channels = pixels.shape # Извлекаем биты extracted_bits = [] stop_counter = 0 stop_marker_length = 8 for i in range(height): for j in range(width): for c in range(channels): # Извлекаем последний бит bit = pixels[i, j, c] & 1 extracted_bits.append(bit) # Проверяем стоп-маркер if bit == 0: stop_counter += 1 if stop_counter == stop_marker_length: # Убираем стоп-маркер из результата extracted_bits = extracted_bits[:-stop_marker_length] break else: stop_counter = 0 if stop_counter == stop_marker_length: break if stop_counter == stop_marker_length: break if len(extracted_bits) == 0: return "" # Преобразуем биты в строку и декодируем bits_string = ''.join(str(bit) for bit in extracted_bits) try: return bits_to_text(bits_string) except Exception as e: print(f"Ошибка при декодировании: {e}") return ""