需求背景

用hugo写博客的时候,存放图片是最麻烦的事情,有时候要从截图里面存图片,有时候要保存网上的图片。

基于上面的需求,我用python实现了个简单的GUI程序, 能实现:

  • 选择hugo目录,并记忆选择的路径到配置文件,第二次打开无需选择hugo博客目录
  • 将图片保存到static目录的images文件夹,按年月日的方式存放,自动创建目录
  • 文件命名采用图片hash来命名
  • 自动生成Markdown的图片调用相对路径

程序截图

程序运行效果

Hugo博客辅助程序

点击保存剪贴板图片 后的效果 Hugo博客辅助程序

实现代码

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130


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()