32 lines
1.3 KiB
Python
32 lines
1.3 KiB
Python
|
|
from __future__ import annotations
|
||
|
|
from dataclasses import dataclass
|
||
|
|
import numpy as np
|
||
|
|
|
||
|
|
|
||
|
|
@dataclass(frozen=True)
|
||
|
|
class LsbRow8:
|
||
|
|
"""Встраивание/извлечение 8 бит в первый ряд блока 8×8 через LSB."""
|
||
|
|
|
||
|
|
@staticmethod
|
||
|
|
def embed(block: np.ndarray, bits: np.ndarray) -> np.ndarray:
|
||
|
|
"""Вернуть копию блока с вшитыми 8 битами."""
|
||
|
|
if block.shape != (8, 8):
|
||
|
|
raise ValueError("Нужен блок 8x8.")
|
||
|
|
b = np.asarray(block, dtype=np.uint8).copy()
|
||
|
|
v = np.asarray(bits, dtype=np.uint8).reshape(-1)
|
||
|
|
if v.size != 8 or not np.isin(v, [0, 1]).all():
|
||
|
|
raise ValueError("Нужно 8 бит 0/1.")
|
||
|
|
# Меняем только младшие биты первых 8 пикселей верхней строки
|
||
|
|
row = b[0, :8]
|
||
|
|
row = (row & 0xFE) | v
|
||
|
|
b[0, :8] = row
|
||
|
|
return b
|
||
|
|
|
||
|
|
@staticmethod
|
||
|
|
def extract(block: np.ndarray) -> np.ndarray:
|
||
|
|
"""Извлечь 8 бит из LSB первого ряда блока."""
|
||
|
|
if block.shape != (8, 8):
|
||
|
|
raise ValueError("Нужен блок 8x8.")
|
||
|
|
b = np.asarray(block, dtype=np.uint8)
|
||
|
|
return (b[0, :8] & 1).astype(np.uint8)
|