2 Star 0 Fork 0

oreomaker/bmp-lsb

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
console.py 11.37 KB
一键复制 编辑 原始数据 按行查看 历史
from os import remove
from tkinter import Tk, Label, Menu, filedialog, SUNKEN, Frame, Text, Entry, Button, END, messagebox
from PIL import Image, ImageTk, ImageFile, UnidentifiedImageError
from encode import encode_bmp, save_encode_img
from decode import extract
ImageFile.LOAD_TRUNCATED_IMAGES = True
class PlaceholderEntry(Entry):
def __init__(self, master=None, placeholder="Enter text here...", **kwargs):
super().__init__(master, **kwargs)
self.placeholder = placeholder
self.insert("0", self.placeholder)
self.bind("<FocusIn>", self._clear_placeholder)
self.bind("<FocusOut>", self._restore_placeholder)
def _clear_placeholder(self, event):
if self.get() == self.placeholder:
self.delete("0", "end")
def _restore_placeholder(self, event):
if not self.get():
self.insert("0", self.placeholder)
class bmp_transfer:
def __init__(self):
self.original_file_path= "" # 原图的路径/待解码的图的路径
self.embedded_file_path = "" # 嵌入图的路径
self.embedded_info="" # 嵌入的信息
self.embedded_img_header="" # 嵌入图片信息,包括header
self.embedded_img_header_others = "" # 嵌入图的其他信息
self.embedded_img_data="" # 嵌入图片信息,包括data
self.extract_info="" # 提取的图片信息
self.max_embed_length_bits=0 # 可嵌入信息的最大长度(bit)
self.max_embed_length_bytes=0 # 可嵌入信息的最大长度(byte)
# 创建一个Tkinter窗口
self.root = Tk()
self.root.geometry("1300x800") # 设置窗口大小
# 按钮组件
self.button_frame = Frame(self.root, width=400, height=300)
self.button_frame.pack_propagate(0)
self.button_frame.grid(row=0, column=0)
self.button_frame.grid_columnconfigure(0, weight=1)
self.button_frame.grid_columnconfigure(1, weight=1)
self.button_frame.grid_rowconfigure(0, weight=1)
self.button_frame.grid_rowconfigure(1, weight=1)
self.read_img_button = Button(self.button_frame, text="读取图片", command=self.open_img)
self.read_img_button.grid(row=0, column=0)
self.embed_button = Button(self.button_frame, text="嵌入", command=self.embed_info)
self.embed_button.grid(row=0, column=1)
self.save_img_button = Button(self.button_frame, text="存储图片", command=self.save_embed_img)
self.save_img_button.grid(row=1, column=0)
self.extract_button = Button(self.button_frame, text="提取", command=self.extract_embed_info)
self.extract_button.grid(row=1, column=1)
# 图片展示组件
self.original_frame=Frame(self.root, width=400, height=300)
self.encoded_frame=Frame(self.root, width=400, height=300)
self.original_frame.pack_propagate(0)
self.encoded_frame.pack_propagate(0)
self.original_label = Label(self.original_frame, text='原图', borderwidth=2, relief=SUNKEN)
self.encoded_label = Label(self.encoded_frame, text='嵌入信息后的图', borderwidth=2, relief=SUNKEN)
self.original_label.pack(fill='both', expand=True)
self.encoded_label.pack(fill='both', expand=True)
self.original_frame.grid(row=1, column=0)
self.encoded_frame.grid(row=1, column=2)
#对话框展示组件
self.text_frame = Frame(self.root, width=400, height=300)
self.text_frame.pack_propagate(0)
self.text_frame.grid(row=1, column=1)
self.upper_text = Text(self.text_frame, height=15, font=("Arial", 20))
self.lower_text = PlaceholderEntry(self.text_frame, placeholder="输入要嵌入的信息/显示提取出的信息", font=("Arial", 20))
self.upper_text.pack(fill='both', expand=True)
self.lower_text.pack(fill='both', expand=True)
self.upper_text.place(x=0, y=0, width=400, height=150)
self.lower_text.place(x=0, y=150, width=400, height=150)
self.upper_text.insert('1.0', '这是要显示计算出来的可嵌入信息的最大长度')
self.upper_text.configure(state='disabled')
# 创建菜单栏
menubar = Menu(self.root)
# 创建菜单选项
file_menu = Menu(menubar, tearoff=0)
file_menu.add_command(label="读取图片", command=self.open_img) # 将open_img函数绑定到菜单项
file_menu.add_command(label="存储图片", command=self.save_embed_img)
file_menu.add_separator()
file_menu.add_command(label="嵌入", command=self.embed_info)
file_menu.add_command(label="提取", command=self.extract_embed_info)
file_menu.add_separator()
file_menu.add_command(label="退出", command=self.root.quit)
menubar.add_cascade(label="菜单", menu=file_menu) # 将菜单选项添加到menubar
self.root.config(menu=menubar) # 添加菜单栏
# 交互函数
def open_img(self):
self.original_file_path = filedialog.askopenfilename() # 打开文件选择对话框
if self.original_file_path: # 确保文件路径不为空
try:
img = Image.open(self.original_file_path)
except UnidentifiedImageError:
messagebox.showwarning('警告', "选择的文件不是图片")
self.original_file_path=""
return
if img.format =='BMP' and img.mode == 'RGB':
width, height = img.size
self.max_embed_length_bits = width * height * 3 # 总共可以嵌入的bit数,每个像素可以嵌入3bits
self.max_embed_length_bytes = self.max_embed_length_bits // 8 # 总共可以嵌入的字节数
elif img.format =='BMP' and img.mode == 'L':
width, height = img.size
self.max_embed_length_bits = width * height # 总共可以嵌入的bit数,每个像素可以嵌入3bits
self.max_embed_length_bytes = self.max_embed_length_bits // 8 # 总共可以嵌入的字节数
else:
messagebox.showerror('错误', "嵌入图像必须是BMP图片的256灰度图或者24位真彩图,当前图片格式为:{}, {}".format(img.format, img.mode))
# print("嵌入图像必须是BMP图片的256灰度图或者24位真彩图,当前图片格式为:{}, {}".format(img.format, img.mode))
return
if img.size[0]>512 or img.size[1]>512:
messagebox.showerror('错误', "嵌入图像大小不超过512*512,当前图片大小为:{}*{}".format(img.size[0], img.size[1]))
# print("嵌入图像大小不超过512*512,当前图片大小为:{}*{}".format(img.size[0], img.size[1]))
return
if img.size[0]%4 !=0 :
messagebox.showerror('错误', "嵌入图像的宽度必须是4的倍数,当前图片宽度为:{}".format(img.size[0]))
# print("嵌入图像的宽度必须是4的倍数,当前图片宽度为:{}".format(img.size[0]))
return
self.upper_text.configure(state='normal')
self.upper_text.delete('1.0', 'end')
self.upper_text.insert('1.0', '当前图像可嵌入信息最大字节数为:{}'.format(self.max_embed_length_bytes))
self.upper_text.configure(state='disabled')
max_size=(400, 300)
#将大图按比例缩小
if img.size[0]>400 or img.size[1]>300:
img.thumbnail(max_size, Image.LANCZOS)
#将小图按比例放大
else:
max_size = (400, 300)
aspect_ratio = img.size[0] / img.size[1]
new_width = min(max_size[0], max_size[1] * aspect_ratio)
new_height = min(max_size[1], max_size[0] / aspect_ratio)
img = img.resize((int(new_width), int(new_height)), Image.LANCZOS)
img_tk = ImageTk.PhotoImage(img)
self.original_label.config(image=img_tk)
self.original_label.image = img_tk # 保持对图像的引用
def embed_info(self):
if self.original_file_path:
self.embedded_info=self.lower_text.get()
if len(self.embedded_info.encode('utf-8'))>self.max_embed_length_bytes:
messagebox.showerror('错误', '信息过长,无法嵌入')
# print('信息过长,无法嵌入')
else:
# print('嵌入信息中')
#调用encode.py中的嵌入函数将信息嵌入,结果先显示在嵌入信息后的图片中
(self.embedded_img_header, self.embedded_img_header_others, self.embedded_img_data)=encode_bmp(self.original_file_path, self.embedded_info)
self.embedded_file_path=self.original_file_path[:-4]+"_embeded"+self.original_file_path[-4:]
save_encode_img(self.embedded_file_path, self.embedded_img_data, self.embedded_img_header, self.embedded_img_header_others)
# 将这个新的bmp文件读取进来,转换成PhotoImage
img = Image.open(self.embedded_file_path)
max_size = (400, 300)
# 将大图按比例缩小
if img.size[0] > 400 or img.size[1] > 300:
img.thumbnail(max_size, Image.LANCZOS)
# 将小图按比例放大
else:
max_size = (400, 300)
aspect_ratio = img.size[0] / img.size[1]
new_width = min(max_size[0], max_size[1] * aspect_ratio)
new_height = min(max_size[1], max_size[0] / aspect_ratio)
img = img.resize((int(new_width), int(new_height)), Image.LANCZOS)
img_tk = ImageTk.PhotoImage(img)
self.encoded_label.config(image=img_tk)
self.encoded_label.image = img_tk # 保持对图像的引用
#删除临时bmp文件
try:
remove(self.embedded_file_path)
messagebox.showinfo('提示', "嵌入成功")
print("移除成功")
except FileNotFoundError:
messagebox.showwarning('警告', "文件 {} 不存在.".format(self.embedded_file_path))
return
# print("文件 {} 不存在.".format(self.embedded_file_path))
else:
messagebox.showerror('错误', "必须选择图片才能嵌入哦~")
# print("必须选择图片才能嵌入哦~")
def save_embed_img(self):
if self.embedded_file_path:
save_encode_img(self.embedded_file_path, self.embedded_img_data, self.embedded_img_header, self.embedded_img_header_others)
messagebox.showinfo('提示',"保存成功,文件位置为:{}".format(self.embedded_file_path))
else:
messagebox.showerror('错误', "还没嵌入图像呢~")
def extract_embed_info(self):
if self.original_file_path:
self.extract_info=extract(self.original_file_path)
self.lower_text.delete(0, END)
self.lower_text.insert(0, self.extract_info)
messagebox.showinfo('提示', "提取成功~,信息已经显示到上面的框框中了~")
else:
messagebox.showerror('错误', "必须选择图片才能提取哦~")
def run(self):
# 启动窗口
self.root.mainloop()
def main():
app = bmp_transfer()
app.run()
if __name__ == "__main__":
main()
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/oreomaker/bmp-lsb.git
git@gitee.com:oreomaker/bmp-lsb.git
oreomaker
bmp-lsb
bmp-lsb
main

搜索帮助