steno_dct / app /utils.py
Xinqi04
new
b96cf99
Raw
History Blame Contribute Delete
3.21 kB
from PIL import Image
import numpy as np
from scipy.fftpack import dct, idct
import io
QUANTIZATION_FACTOR = 10
def convert_and_resize_image(image):
gray_image = image.convert("L")
w, h = gray_image.size
w_crop = w - (w % 8)
h_crop = h - (h % 8)
if w_crop == 0 or h_crop == 0:
return None
return gray_image.crop((0, 0, w_crop, h_crop))
def message_to_binary(message):
message += "_END_"
return ''.join(format(ord(c), '08b') for c in message)
def binary_to_message(binary_message):
delimiter = ''.join(format(ord(c), '08b') for c in "_END_")
if delimiter not in binary_message:
return None
try:
end_index = binary_message.index(delimiter)
clean_binary = binary_message[:end_index]
if len(clean_binary) % 8 != 0:
return None
return ''.join(chr(int(clean_binary[i:i+8], 2)) for i in range(0, len(clean_binary), 8))
except:
return None
def apply_dct(image_array):
h, w = image_array.shape
dct_blocks = np.zeros_like(image_array, dtype=float)
for i in range(0, h, 8):
for j in range(0, w, 8):
block = image_array[i:i+8, j:j+8].astype(float)
dct_blocks[i:i+8, j:j+8] = dct(dct(block.T, norm='ortho').T, norm='ortho')
return dct_blocks
def apply_idct(dct_blocks):
h, w = dct_blocks.shape
image_blocks = np.zeros_like(dct_blocks, dtype=float)
for i in range(0, h, 8):
for j in range(0, w, 8):
block = dct_blocks[i:i+8, j:j+8]
image_blocks[i:i+8, j:j+8] = idct(idct(block.T, norm='ortho').T, norm='ortho')
return np.clip(image_blocks, 0, 255).astype(np.uint8)
def embed_message(image, secret_message):
gray_cropped = convert_and_resize_image(image)
if gray_cropped is None:
return None
img_array = np.array(gray_cropped)
h, w = img_array.shape
binary_message = message_to_binary(secret_message)
msg_len = len(binary_message)
dct_coeffs = apply_dct(img_array)
bit_index = 0
for i in range(0, h, 8):
for j in range(0, w, 8):
if bit_index >= msg_len:
break
u, v = 4, 1
coeff = dct_coeffs[i + u, j + v]
bit = int(binary_message[bit_index])
quantized_coeff = int(round(coeff / QUANTIZATION_FACTOR))
if quantized_coeff % 2 != bit:
quantized_coeff -= 1
dct_coeffs[i + u, j + v] = quantized_coeff * QUANTIZATION_FACTOR
bit_index += 1
if bit_index >= msg_len:
break
stego_array = apply_idct(dct_coeffs)
return Image.fromarray(stego_array)
def extract_message(image):
gray_cropped = convert_and_resize_image(image)
if gray_cropped is None:
return None
img_array = np.array(gray_cropped)
h, w = img_array.shape
dct_coeffs = apply_dct(img_array)
binary_message = ""
for i in range(0, h, 8):
for j in range(0, w, 8):
u, v = 4, 1
coeff = dct_coeffs[i + u, j + v]
quantized_coeff = int(round(coeff / QUANTIZATION_FACTOR))
binary_message += str(quantized_coeff % 2)
return binary_to_message(binary_message)