Как это работает
PNG хранит информацию о каждом пикселе через четыре канала: R (красный), G (зелёный), B (синий) и альфа (прозрачность). Каждый канал — это целое число от 0 до 255.
Уловка в том, чтобы использовать LSB (Least Significant Bit — младший бит) каждого канала. Если ты изменишь только последний бит, цвет изменится на величину, которую человеческий глаз не заметит. Идеально для стеганографии.
Сколько данных влезет?
Каждый пиксель имеет три цветовых канала (R, G, B), поэтому вмещает 3 бита информации:
- Текст «Hello world» в UTF-8 займёт примерно 30 пикселей (картинка 6×6)
- 100 тысяч слов потребуют изображение 1000×1000
- До 5 мегабайт данных поместятся на 5000×5000
При этом вес файла изменится минимально — архивация PNG скроет твои манипуляции.
Кодируем сообщение
Процесс простой: переводишь сообщение в бинарный формат, затем для каждого пикселя подменяешь младшие биты его каналов на биты из твоих данных.
function writeData(imageBinary, dataBinary) {
for (let i = 0, dataBitIndex = 0; i < imageBinary.length; i += 4) {
for (let j = 0; j < 3; j++, dataBitIndex++) {
if (dataBitIndex >= dataBinary.length * 8) {
return imageBinary;
}
// Получаем текущий бит данных
let bit = (dataBinary[Math.floor(dataBitIndex / 8)] >> (7 - (dataBitIndex % 8))) & 1;
// Подменяем младший бит канала
imageBinary[i + j] = (imageBinary[i + j] & 0xFE) | bit;
}
}
return imageBinary;
}
Перед самими данными запиши их длину (4 байта) — потребуется для декодирования.
Читаем сообщение обратно
Декодирование работает в обратном направлении: проходишь по всем пикселям, собираешь младшие биты каналов, собираешь их обратно в байты.
function readMessage(dataBinary) {
let bytes = [];
for (let i = 0, dataBitIndex = 0, currentByte = 0; i < pixels.length; i += 4) {
for (let j = 0; j < 3; j++) {
let bit = pixels[i + j] & 1;
currentByte = (currentByte << 1) | bit;
dataBitIndex++;
if (dataBitIndex % 8 === 0) {
bytes.push(currentByte);
currentByte = 0;
}
}
}
return Buffer.from(bytes);
}
Почитай первые 4 байта, узнаешь длину сообщения, срежешь лишнее — готово.
Что дальше?
Базовая версия уже полезна, но можно развить идею:
- Шифрование: добавь AES перед кодированием, и даже если кто-то найдёт данные, не сможет их прочитать
- Другие файлы: не только текст — можно прятать любые бинарные файлы
- Эллиптические кривые: выбирай пиксели не по порядку, а по криптографической функции — сложнее обнаружить
- Шум: добавь случайные изменения к «пустым» пикселям, чтобы затруднить стегоанализ
Всё зависит от твоих целей: просто спрятать пароли в фотографию кота или сделать серьёзную систему скрытой передачи данных.

