import tkinter as tk
from tkinter import filedialog
import numpy as np
from PIL import Image
import os
# 全局变量,用于存储选择的图片路径
image_path = ""
def select_image():
"""打开文件对话框,让用户选择图片,并更新全局变量 image_path"""
global image_path
image_path = filedialog.askopenfilename(filetypes=[("Image files", "*.png;*.jpg;*.jpeg;*.bmp;*.gif")])
if image_path:
image_label.config(text=f"已选择图片: {os.path.basename(image_path)}")
def lsb_embed(pic_src, secrets):
"""将秘密信息嵌入到图片中"""
original_picture = Image.open(pic_src)
original_format = original_picture.format
pic_data = np.array(original_picture)
im_data = np.array(original_picture.copy()).ravel().tolist()
def cover_lsb(bin_index, data):
res = []
for i in range(8):
data_i_bin = bin(data[i])[2:].zfill(8)
if bin_index[i] == '0':
data_i_bin = data_i_bin[0:7] + '0'
elif bin_index[i] == '1':
data_i_bin = data_i_bin[0:7] + '1'
res.append(int(data_i_bin, 2))
return res
pic_idx = 0
res_data = []
for char in secrets:
index = ord(char)
bin_index = bin(index)[2:].zfill(8)
res = cover_lsb(bin_index, im_data[pic_idx * 8: (pic_idx + 1) * 8])
pic_idx += 1
res_data += res
res_data += im_data[pic_idx * 8:]
new_im_data = np.array(res_data).astype(np.uint8).reshape((pic_data.shape))
res_im = Image.fromarray(new_im_data)
res_im = res_im.convert(original_picture.mode)
pic_folder_path = './pic'
if not os.path.exists(pic_folder_path):
os.makedirs(pic_folder_path)
res_im.save(f'./pic/res_encode.{original_format.lower()}')
print(f"在 pic 中已生成 res_encode.{original_format.lower()}")
def lsb_extract(pic_src):
"""从图片中提取秘密信息"""
picture = Image.open(pic_src)
pic_datas = np.array(picture).ravel().tolist()
def lsb_decode(data):
str_bin = ''
for i in range(len(data)):
data_i_bin = bin(data[i])[2:][-1]
str_bin += data_i_bin
return chr(int(str_bin, 2))
str_data = ''
pic_idx = 0
while True:
data = pic_datas[pic_idx * 8: (pic_idx + 1) * 8]
char = lsb_decode(data)
if char == '\x00':
# 增加一个判断,如果下一个字符也为 '\x00',则停止提取
if pic_idx * 8 + 8 < len(pic_datas) and lsb_decode(pic_datas[pic_idx * 8 + 8: (pic_idx + 1) * 8 + 8]) == '\x00':
break
# 判断是否为可打印字符,如果不是则停止提取
if not char.isprintable():
break
str_data += char
pic_idx += 1
return str_data
def embed_message():
"""处理隐藏信息按钮的点击事件"""
secrets = input_text.get("1.0", tk.END).strip()
if not secrets:
result_label.config(text="请输入要隐藏的信息!", fg="red")
return
if not image_path:
result_label.config(text="请选择图片!", fg="red")
return
lsb_embed(image_path, secrets)
result_label.config(text="隐写成功!", fg="green")
def extract_message():
"""处理提取信息按钮的点击事件"""
if not image_path:
result_label.config(text="请选择图片!", fg="red")
return
extracted_data = lsb_extract(image_path)
extracted_text.config(text=extracted_data)
result_label.config(text=f"提取成功!提取的信息如上")
# 创建 Tkinter 窗口
root = tk.Tk()
root.title("QのLSB 隐写和提取工具!")
root.title_label = tk.Label(root, text=root.title(), fg="green")
root.title_label.pack()
# 创建并放置选择图片标签和按钮
image_label = tk.Label(root, text="请选择图片以继续...")
image_label.pack(pady=10)
select_image_button = tk.Button(root, text="选择图片", command=select_image)
select_image_button.pack(pady=5)
# 创建信息输入和输出框架
info_frame = tk.Frame(root)
info_frame.pack(pady=10)
# 创建输入部分
input_label = tk.Label(info_frame, text="输入要隐藏的信息:")
input_label.pack(pady=5, anchor='w')
input_text = tk.Text(info_frame, height=5, width=40, bg='white')
input_text.pack(pady=5)
# 创建提取部分
extracted_label = tk.Label(info_frame, text="提取的信息:")
extracted_label.pack(pady=5, anchor='w')
extracted_text = tk.Label(info_frame, text="", wraplength=300, bg='white')
extracted_text.config(height=4, width=40)
extracted_text.pack(pady=5)
# 创建按钮框架
button_frame = tk.Frame(root)
button_frame.pack(pady=10)
# 创建并放置隐藏信息和提取信息的按钮
embed_button = tk.Button(button_frame, text="隐藏信息", command=embed_message)
embed_button.pack(side=tk.LEFT, padx=20)
extract_button = tk.Button(button_frame, text="提取信息", command=extract_message)
extract_button.pack(side=tk.RIGHT, padx=20)
# 创建并放置结果标签
result_label = tk.Label(root, text="", wraplength=300)
result_label.pack(pady=10)
# 进入 Tkinter 主事件循环
root.mainloop()
为什么提取的时候出现乱码
