需求背景
用hugo写博客的时候,存放图片是最麻烦的事情,有时候要从截图里面存图片,有时候要保存网上的图片。
基于上面的需求,我用python实现了个简单的GUI程序, 能实现:
- 选择hugo目录,并记忆选择的路径到配置文件,第二次打开无需选择hugo博客目录
- 将图片保存到static目录的images文件夹,按年月日的方式存放,自动创建目录
- 文件命名采用图片hash来命名
- 自动生成Markdown的图片调用相对路径
程序截图
程序运行效果
点击保存剪贴板图片 后的效果
实现代码
import tkinter as tk
from tkinter import filedialog
from PIL import ImageGrab
import os
import datetime
import hashlib
import configparser
# 创建配置文件
config = configparser.ConfigParser()
config_file = os.path.expanduser("~/.clipboard_image_config.ini")
# 如果配置文件存在,读取保存目录路径
if os.path.exists(config_file):
config.read(config_file)
output_dir = config.get("Settings", "output_dir")
else:
output_dir = os.path.expanduser("~/static")
# 计算图像内容的哈希值
def calculate_image_hash(image):
return hashlib.sha256(image.tobytes()).hexdigest()
# 处理按钮点击事件:保存剪贴板图片
def save_image_from_clipboard():
# 使用Pillow库获取剪贴板中的图片数据
clipboard_image = ImageGrab.grabclipboard()
if clipboard_image is not None:
# 计算图像内容的哈希值
image_hash = calculate_image_hash(clipboard_image)
# 生成文件名
current_time = datetime.datetime.now()
year = str(current_time.year)
month = str(current_time.month).zfill(2)
day = str(current_time.day).zfill(2)
file_name = f"images/{year}/{month}/{day}/{image_hash}.png"
# 构建完整的文件路径
file_path = os.path.join(output_dir, file_name)
# 修复路径中的双斜杠问题
file_path = file_path.replace(os.path.sep, "/").replace("//", "/")
try:
# 检查目录是否存在,如果不存在则创建目录
os.makedirs(os.path.dirname(file_path), exist_ok=True)
# 保存图像文件
clipboard_image.save(file_path, "PNG")
# 插入Markdown图片代码到输入框
insert_markdown_image_code(file_path)
result_label.config(text=f"图像已保存到 {file_path}")
except Exception as e:
result_label.config(text=f"保存图像时出现错误: {str(e)}")
else:
result_label.config(text="剪贴板中没有图片数据")
# 处理按钮点击事件:选择保存目录
def select_output_directory():
global output_dir
selected_dir = filedialog.askdirectory()
if selected_dir:
output_dir = selected_dir
# 将选择的目录保存到配置文件
config["Settings"] = {"output_dir": output_dir}
with open(config_file, "w") as configfile:
config.write(configfile)
# 更新只读文本框的内容
directory_entry.delete(0, tk.END)
directory_entry.insert(0, output_dir)
# 处理按钮点击事件:复制Markdown图片代码
def copy_markdown_image_code():
selected_text = input_text.get("1.0", "end-1c") # 获取输入框中的文本
selected_text = selected_text.strip() # 去除首尾空白
selected_text = selected_text.replace(output_dir, "") # 转换为相对路径
selected_text = selected_text.replace(os.path.sep, "/") # 替换路径分隔符为/
selected_text = selected_text.replace("//", "/") # 替换双斜杠为单斜杠
result_label.config(text="Markdown图片代码已复制到剪贴板")
root.clipboard_clear()
root.clipboard_append(selected_text)
root.update()
# 插入Markdown图片代码到输入框
def insert_markdown_image_code(file_path):
relative_path = file_path.replace(output_dir, "").replace(os.path.sep, "/")
markdown_code = f"![Image]({relative_path})"
input_text.insert(tk.END, markdown_code)
# 创建主窗口
root = tk.Tk()
root.title("保存剪贴板图片")
# 创建只读输入框:用于显示所选目录路径
directory_entry = tk.Entry(root, state='readonly')
directory_entry.grid(row=3, column=0, columnspan=2, sticky="ew", padx=10, pady=10)
# 创建按钮:保存剪贴板图片
save_button = tk.Button(root, text="保存剪贴板图片", command=save_image_from_clipboard)
save_button.grid(row=0, column=0, columnspan=2, padx=10, pady=10)
# 创建按钮:选择保存目录
select_dir_button = tk.Button(root, text="选择保存目录", command=select_output_directory)
select_dir_button.grid(row=1, column=0, columnspan=2, padx=10, pady=10)
# 创建用于显示结果的标签
result_label = tk.Label(root, text="", wraplength=300)
result_label.grid(row=2, column=0, columnspan=2, padx=10, pady=10)
# 初次更新只读输入框的内容
directory_entry.insert(0, output_dir)
# 创建输入框:用于插入Markdown图片代码
input_text = tk.Text(root)
input_text.grid(row=4, column=0, columnspan=2, sticky="nsew", padx=10, pady=10)
# 创建按钮:复制Markdown图片代码
copy_code_button = tk.Button(root, text="复制代码", command=copy_markdown_image_code)
copy_code_button.grid(row=5, column=0, columnspan=2, padx=10, pady=10)
# 设置网格布局的列和行权重,使得窗口变大时,小部件会自动调整大小
root.columnconfigure(0, weight=1)
# 启动主事件循环
root.mainloop()