from numba import jit
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
import struct
import pandas as pd
import math

with open("C:\\Users\\zoyas\\OneDrive\\Рабочий стол\\владения\\учЁбка\\стеганография\\котлр3.bmp", "rb") as bmp:
    print('Type:', bmp.read(2).decode())
    print('Size: %s' % struct.unpack('I', bmp.read(4)))
    print('Reserved 1: %s' % struct.unpack('H', bmp.read(2)))
    print('Reserved 2: %s' % struct.unpack('H', bmp.read(2)))
    print('bfOffBits: %s' % struct.unpack('I', bmp.read(4)))
    
    print('DIB Header Size: %s' % struct.unpack('I', bmp.read(4)))
    
    width = struct.unpack('I', bmp.read(4))[0]
    height = struct.unpack('I', bmp.read(4))[0]

    print('width =', width)
    print('height =', height)

    """print('Width: %s' % struct.unpack('I', bmp.read(4)))
    print('Height: %s' % struct.unpack('I', bmp.read(4)))"""
    print('Colour Planes: %s' % struct.unpack('H', bmp.read(2)))
    print('Bits per Pixel: %s' % struct.unpack('H', bmp.read(2)))
    print('Compression Method: %s' % struct.unpack('I', bmp.read(4)))
    print('Raw Image Size: %s' % struct.unpack('I', bmp.read(4)))
    print('Horizontal Resolution: %s' % struct.unpack('I', bmp.read(4)))
    print('Vertical Resolution: %s' % struct.unpack('I', bmp.read(4)))
    print('Number of Colours: %s' % struct.unpack('I', bmp.read(4)))
    print('Important Colours: %s' % struct.unpack('I', bmp.read(4)))


img = Image.open("C:\\Users\\zoyas\\OneDrive\\Рабочий стол\\владения\\учЁбка\\стеганография\\котлр3.bmp")

data = np.array(img)
display(img)

from scipy.fftpack import dct, idct

def dct_(block):
    return dct(dct(block.T, norm='ortho').T, norm='ortho')

def idct_(block):
    return idct(idct(block.T, norm='ortho').T, norm='ortho')

def DCT(x): # Прямое ДКП
    N = 8
    y = np.zeros((N, N))
    for k in range(N):
        if k == 0:
            C_k = 1/N
        else:
            C_k = 2/N
        for l in range(N):
            if l == 0:
                C_l = 1/N
            else:
                C_l = 2/N

            for i in range(N):
                for j in range(N):
                    y[l,k] += x[j,i]*math.cos(math.pi*k*(2*i+1)/(2*N))*math.cos(math.pi*l*(2*j+1)/(2*N))
            y[l,k] *= math.sqrt(C_l*C_k)
    return y

def DCT_invert(y):  #Обратное ДКП
    N = 8
    x = np.zeros((N, N))
    for i in range(N):
        for j in range(N):
            for k in range(N):
                if k == 0:
                    C_k = 1 / N
                else:
                    C_k = 2 / N
                for l in range(N):
                    if l == 0:
                        C_l = 1 / N
                    else:
                        C_l = 2 / N
                    x[j,i] += (math.sqrt(C_l*C_k) * y[l,k]*math.cos(math.pi*k*(2*i+1)/(2*N))*math.cos(math.pi*l*(2*j+1)/(2*N)))
            x[j,i] = round(x[j,i])
    return x
def dct_idct_img(input_file, output_file):
    image = Image.open(input_file)
    image_data = np.array(image)
    h, w, channels = image_data.shape[0], image_data.shape[1], image_data.shape[2]

    dcp_im_data = np.zeros_like(image_data)

    for i in range(0, h, 8):
        for j in range(0, w, 8):
            for c in range(0, channels):
                block = image_data[i:i + 8, j:j + 8, c]

                #dct_block = dct_(block)
                dct_block = DCT(block)

                
                #print(dct_block)
                #idcp_block = idct_(dct_block)
                idcp_block = DCT_invert(dct_block)

                dcp_im_data[i:i + 8, j:j + 8, c] = idcp_block

    dcp_idcp_immage = Image.fromarray(np.uint8(dcp_im_data))
    display(dcp_idcp_immage)
    dcp_idcp_immage.save(output_file)

dct_idct_img("C:\\Users\\zoyas\\OneDrive\\Рабочий стол\\владения\\учЁбка\\стеганография\\котлр3.bmp", "C:\\Users\\zoyas\\OneDrive\\Рабочий стол\\владения\\учЁбка\\стеганография\\котлр3_1.bmp")
def calculate_psnr(original_image_file, stego_image_file):
    original_image = Image.open(original_image_file)
    stego_image = Image.open(stego_image_file)

    original_data = np.array(original_image)
    stego_data = np.array(stego_image)

    mse = np.mean((original_data - stego_data) ** 2)
    if mse == 0:
        return float('inf')

    max_pixel = 255.0
    psnr = 10 * math.log10(max_pixel ** 2 / mse)
    return psnr

print("pasnr btw befor and after DCP ", calculate_psnr("C:\\Users\\zoyas\\OneDrive\\Рабочий стол\\владения\\учЁбка\\стеганография\\котлр3.bmp", "C:\\Users\\zoyas\\OneDrive\\Рабочий стол\\владения\\учЁбка\\стеганография\\котлр3_1.bmp"))


def bits_to_text_7bit(bit_array):
    """
    Преобразование массива 7-битовых битов обратно в текстовое сообщение.
    """
    byte_list = []
    for i in range(0, len(bit_array), 7):
        byte = 0
        for j in range(7):
            byte = (byte << 1) | bit_array[i + j]
        byte_list.append(byte)
    
    # Преобразование байтов в строку с использованием кодировки ASCII
    byte_array = bytearray(byte_list)
    text = byte_array.decode('ascii')
    return text

def int_to_bits(n, bit_size=32):
    """
    Преобразование целого числа в массив битов фиксированной длины (по умолчанию 32 бита).
    """
    if n < 0:
        n = (1 << bit_size) + n  # Для отрицательных чисел используем представление в дополнительном коде
    
    bits = []
    for i in range(bit_size):
        bits.append((n >> (bit_size - 1 - i)) & 1)  # Получаем каждый бит и добавляем в массив

    return bits

def bits_to_int(bits):
    """
    Преобразование массива битов в целое число.
    """
    bit_size = len(bits)
    n = 0
    for bit in bits:
        n = (n << 1) | bit
    
    # Проверка на отрицательное число в дополнительном коде (two's complement)
    if bits[0] == 1:  # Если старший бит равен 1, то число отрицательное
        n -= (1 << bit_size)
    
    return n
import codecs

check = []
def insert_mes(input_file, output_file, message, M_0, check):

    print("mes length: ", len(message))
    header_bits = int_to_bits(len(message))
    print ("header bits: ", header_bits)
    binary_mes = codecs.encode(message, 'ascii')

    # Преобразование массива байтов в массив битов
    mes_bits = []
    for byte in binary_mes:
        for i in range(7):
            bit = (byte >> (6 - i)) & 1
            mes_bits.append(bit)

    # Вывод массива битов
    print("bit mes: ", mes_bits)
    print("mes bits: ", len(mes_bits))
    print("mes: ", bits_to_text_7bit(mes_bits))

    check = [*header_bits, *mes_bits]

    image = Image.open(input_file)
    image_data = np.array(image)
    h, w, channels = image_data.shape[0], image_data.shape[1], image_data.shape[2]

    watermarked_image_data = np.zeros_like(image_data)

    #t = M_0

    er1=0
    er2=0
    er3=0
    er4=0

    bit_index = 0
    k1 = 2
    k2 = 3

    t = 0.01
    
    for i in range(0, h, 8):
        for j in range(0, w, 8):
            for c in range(0, channels):
                block = image_data[i:i + 8, j:j + 8, c]

                dct_block = dct_(block)
                #dct_block = DCT(block)
                #print(dct_block)

                #dct_block = write()

                if (bit_index < len(header_bits)):
                    #dct_block = write(dct_block, header_bits[bit_index],M_0)
                    if (header_bits[bit_index] == 1):
                        if (abs(dct_block[k1, k2]) - abs(dct_block[k2, k1]) <= M_0):
                            
                            while(abs(dct_block[k1, k2]) - abs(dct_block[k2, k1]) <= M_0):

                                if (dct_block[k1, k2] >= 0):
                                    dct_block[k1, k2] += t
                                else:
                                    dct_block[k1, k2] -= t

                                if (dct_block[k2, k1] > 0):
                                    if (dct_block[k2, k1] - t > 0):
                                        dct_block[k2, k1] -= t
                                elif (dct_block[k2, k1] < 0):
                                    if (dct_block[k2, k1] + t < 0):
                                        dct_block[k2, k1] += t

                            if(abs(dct_block[k1, k2]) <= abs(dct_block[k2, k1])):
                                er1+=1
                    else:
                        if (abs(dct_block[k1, k2]) - abs(dct_block[k2, k1]) >= -M_0):
                            
                            while(abs(dct_block[k1, k2]) - abs(dct_block[k2, k1]) >= -M_0):

                                if (dct_block[k1, k2] > 0):
                                    if (dct_block[k1, k2] - t > 0):
                                        dct_block[k1, k2] -= t
                                elif (dct_block[k1, k2] < 0):
                                    if (dct_block[k1, k2] + t < 0):
                                        dct_block[k1, k2] += t

                                if (dct_block[k2, k1] >= 0):
                                    dct_block[k2, k1] += t
                                else:
                                    dct_block[k2, k1] -= t

                            if(abs(dct_block[k1, k2]) >= abs(dct_block[k2, k1])):
                                er2+=1

                            
                elif (bit_index - len(header_bits) < len(mes_bits)):
                    #dct_block = write(dct_block, mes_bits[bit_index - len(header_bits)],M_0)

                    if (mes_bits[bit_index - len(header_bits)] == 1):
                        if (abs(dct_block[k1, k2]) - abs(dct_block[k2, k1]) <= M_0):
                            
                            while(abs(dct_block[k1, k2]) - abs(dct_block[k2, k1]) <= M_0):

                                if (dct_block[k1, k2] >= 0):
                                    dct_block[k1, k2] += t
                                else:
                                    dct_block[k1, k2] -= t

                                if (dct_block[k2, k1] > 0):
                                    if (dct_block[k2, k1] - t > 0):
                                        dct_block[k2, k1] -= t
                                elif (dct_block[k2, k1] < 0):
                                    if (dct_block[k2, k1] + t < 0):
                                        dct_block[k2, k1] += t

                            if(abs(dct_block[k1, k2]) <= abs(dct_block[k2, k1])):
                                er3+=1
                                
                    else:
                        if (abs(dct_block[k1, k2]) - abs(dct_block[k2, k1]) >= -M_0):

                            while(abs(dct_block[k1, k2]) - abs(dct_block[k2, k1]) >= -M_0):

                                if (dct_block[k1, k2] > 0):
                                    if (dct_block[k1, k2] - t > 0):
                                        dct_block[k1, k2] -= t
                                elif (dct_block[k1, k2] < 0):
                                    if (dct_block[k1, k2] + t < 0):
                                        dct_block[k1, k2] += t

                                if (dct_block[k2, k1] >= 0):
                                    dct_block[k2, k1] += t
                                else:
                                    dct_block[k2, k1] -= t

                            if(abs(dct_block[k1, k2]) >= abs(dct_block[k2, k1])):
                                er4+=1

                
                watermarked_block = idct_(dct_block)
                #watermarked_block = DCT_invert(dct_block)

                watermarked_image_data[i:i + 8, j:j + 8, c] = watermarked_block
            bit_index += 1

    watermarked_image = Image.fromarray(np.uint8(watermarked_image_data))
    #watermarked_image = Image.fromarray(np.clip(watermarked_image_data, 0, 255).astype(np.uint8))
    display(watermarked_image)
    
    watermarked_image.save(output_file)
    print(er1,er2,er3,er4)
    return check


message = "Hello, it's me. I was wondering if after all this yers you'd like"

in_p = "C:\\Users\\zoyas\\OneDrive\\Рабочий стол\\владения\\учЁбка\\стеганография\\котлр3.bmp"
out_p = "C:\\Users\\zoyas\\OneDrive\\Рабочий стол\\владения\\учЁбка\\стеганография\\котлр3_1.bmp"

check = insert_mes(in_p, out_p, message, 5, check)
def get_mes(container, M_0, check):

    k1 = 2
    k2 = 3

    image = Image.open(container)
    image_data = np.array(image)
    h, w, channels = image_data.shape[0], image_data.shape[1], image_data.shape[2]

    watermarked_image_data = np.zeros_like(image_data)

    header_bits = [0] * 32
    mes_bits = []
    #mes_bits = [0] * len(check)
    mis_count = 0

    bit_index = 0
    for i in range(0, h, 8):
        for j in range(0, w, 8):
            voice_0 = 0
            voice_1 = 0
            for c in range(0, channels):
                block = image_data[i:i + 8, j:j + 8, c]

                dct_block = dct_(block)
                #dct_block = DCT(block)

                if (abs(dct_block[k1, k2]) < abs(dct_block[k2, k1])):
                    voice_0 += 1
                else:
                    voice_1 += 1
                

            if (bit_index < 32):
                if (voice_0 > voice_1):
                    header_bits[bit_index] = 0
                else:
                    header_bits[bit_index] = 1

                if (bit_index == 31):
                    print("mes length: ", bits_to_int(header_bits))

                    mes_bits = [0] * (bits_to_int(header_bits) * 7)
                    #print("mes length: ", bits_to_int(header_bits))

            elif (bit_index - len(header_bits) < len(mes_bits)):
            
                if (voice_0 > voice_1):
                    mes_bits[bit_index - len(header_bits)] = 0
                else:
                    mes_bits[bit_index - len(header_bits)] = 1
            bit_index += 1

    print("mes length: ", bits_to_int(header_bits))
    print(len(mes_bits))
    print("mes: ", bits_to_text_7bit(mes_bits))
    print(mes_bits)
    return mes_bits

#message = "Hello, it's me"

in_p = "C:\\Users\\zoyas\\OneDrive\\Рабочий стол\\владения\\учЁбка\\стеганография\\котлр3.bmp"
out_p = "C:\\Users\\zoyas\\OneDrive\\Рабочий стол\\владения\\учЁбка\\стеганография\\котлр3_1.bmp"

final = get_mes(out_p, 0, check)
def get_mes_after(container, M_0, check):

    image = Image.open(container)
    image_data = np.array(image)
    h, w, channels = image_data.shape[0], image_data.shape[1], image_data.shape[2]

    watermarked_image_data = np.zeros_like(image_data)

    k1 = 2
    k2 = 3

    header_bits = [0] * 455
    mes_bits = []
    #mes_bits = [0] * len(check)
    mis_count = 0

    bit_index = 0
    for i in range(0, h, 8):
        for j in range(0, w, 8):
            voice_0 = 0
            voice_1 = 0
            for c in range(0, channels):
                #print(i,j,c, bit_index)
                block = image_data[i:i + 8, j:j + 8, c]

                dct_block = dct_(block)
                #dct_block = DCT(block)

                if (abs(dct_block[k1, k2]) < abs(dct_block[k2, k1])):
                    voice_0 += 1
                else:
                    voice_1 += 1

            if (bit_index >= 32 and bit_index < 455 + 32):
                if (voice_0 > voice_1):
                    header_bits[bit_index - 32] = 0
                else:
                    header_bits[bit_index - 32] = 1

            bit_index += 1

    #print("mistakes ", mis_count)
    #print("per cent mistakes ", mis_count / len(check))
    #got_mes = bits_to_text_7bit(mes_bits)
    print(header_bits)
    print("mes: ", bits_to_text_7bit(header_bits))
    return header_bits

#message = "Hello, it's me"

in_p = "C:\\Users\\zoyas\\OneDrive\\Рабочий стол\\владения\\учЁбка\\стеганография\\котлр3.bmp"
out_p = "C:\\Users\\zoyas\\OneDrive\\Рабочий стол\\владения\\учЁбка\\стеганография\\котлр3_1.bmp"

final_header = get_mes_after(out_p, 0, check)
def compress_image(input_file, compressed_file, quality=50):
    image = Image.open(input_file)
    image.save(compressed_file, "JPEG", quality=quality)
    #print(f"sjato in {compressed_file} witj quaolity {quality}")

def decompress_image(jpeg_file, output_file):
    image = Image.open(jpeg_file)
    image = image.convert("RGB")  # Преобразуем обратно в формат с 3 каналами (RGB)
    image.save(output_file, "BMP")
    #print(f"Immde alive in {jpeg_file} and saved as {output_file}")

comp_path = "C:\\Users\\zoyas\\OneDrive\\Рабочий стол\\владения\\учЁбка\\стеганография\\котлр3_2.jpeg"
again_bmp_path = "C:\\Users\\zoyas\\OneDrive\\Рабочий стол\\владения\\учЁбка\\стеганография\\котлр3_3.bmp"

compress_image(out_p,comp_path)
dk = Image.open(comp_path)
display(dk)

decompress_image(comp_path, again_bmp_path)
img_ag_bmp = Image.open(again_bmp_path)
display(img_ag_bmp)


message = "Hello, it's me. I was wondering if after all this yers you'd like"
binary_mes = codecs.encode(message, 'ascii')

# Преобразование массива байтов в массив битов
mes_bits = []
for byte in binary_mes:
    for i in range(7):
        bit = (byte >> (6 - i)) & 1
        mes_bits.append(bit)
        
smth = get_mes_after(again_bmp_path, 0, check)
#print(smth)
print(mes_bits)

count = 0
for i in range(0, len(smth)):
    if (smth[i] != mes_bits[i]):
        count += 1
print("procent of mistakes: ",(count /len(smth)) * 100)
print("mistakes: ", count)


в этом коде такая ошибка:
[{
	"resource": "/C:/Users/serez/Desktop/steg3333/steggg3.py",
	"owner": "python",
	"code": {
		"value": "reportUndefinedVariable",
		"target": {
			"$mid": 1,
			"path": "/microsoft/pyright/blob/main/docs/configuration.md",
			"scheme": "https",
			"authority": "github.com",
			"fragment": "reportUndefinedVariable"
		}
	},
	"severity": 4,
	"message": "\"display\" is not defined",
	"source": "Pylance",
	"startLineNumber": 39,
	"startColumn": 1,
	"endLineNumber": 39,
	"endColumn": 8
}]