修复路径引号处理,完善帮助菜单样式
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
1
|
||||||
@@ -1,20 +1,28 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from watermark import watermark_image, increment_count, load_font
|
from watermark import watermark_image, increment_count
|
||||||
from config import OUTPUT_DIR, SUPPORTED_INPUT_EXTENSIONS, WORK_DIR
|
from config import OUTPUT_DIR, SUPPORTED_INPUT_EXTENSIONS, SUPPORTED_OUTPUT_EXTENSIONS, WORK_DIR
|
||||||
|
|
||||||
|
|
||||||
def print_help():
|
def print_help():
|
||||||
help_text = """
|
help_text = """
|
||||||
用法:
|
========================================
|
||||||
"图片路径" "水印内容" 加水印,保持原格式输出
|
imgwatermark - 图像水印工具 v1.0
|
||||||
"图片路径>输出格式" "水印内容" 加水印并转换格式(格式可选:jpg/png/bmp/gif/tiff/webp)
|
支持: .jpg .png .bmp .gif .tiff .webp
|
||||||
/exit 退出程序
|
输出: jpg / png / bmp / gif / tiff / webp
|
||||||
/get 查询已处理图片总数
|
========================================
|
||||||
|
|
||||||
示例:
|
命令:
|
||||||
photo.jpg "版权所有"
|
<图片路径> \"水印内容\" 加水印,保持原格式输出
|
||||||
photo.jpg>PNG "2026"
|
<图片路径>>.png \"内容\" 加水印并转换格式(格式可选:jpg/png/bmp/gif/tiff/webp)
|
||||||
|
/exit 或 exit 退出程序
|
||||||
|
/get 或 get 显示已处理图片统计
|
||||||
|
/help 或 help 显示本帮助信息
|
||||||
|
|
||||||
|
示例:
|
||||||
|
D:\\img\\photo.jpg \"版权所有\"
|
||||||
|
D:\\img\\photo.jpg>.png \"2026\"
|
||||||
|
/get
|
||||||
"""
|
"""
|
||||||
print(help_text.strip())
|
print(help_text.strip())
|
||||||
|
|
||||||
@@ -27,23 +35,26 @@ def print_stats():
|
|||||||
count = int(f.read().strip())
|
count = int(f.read().strip())
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
print(f"当前已处理图片数量: {count}")
|
print(f"已处理图片总数: {count} 张")
|
||||||
|
|
||||||
|
|
||||||
def process_single(image_arg, text):
|
def process_single(image_arg, text):
|
||||||
|
"""处理单张图片:可选格式转换,添加水印,计数+1。"""
|
||||||
|
# 去掉首尾引号(兼容命令行传入带引号的路径)
|
||||||
|
image_arg = image_arg.strip().strip('"').strip("'")
|
||||||
|
text = text.strip().strip('"').strip("'")
|
||||||
|
|
||||||
if ">" not in image_arg:
|
if ">" not in image_arg:
|
||||||
# 无格式转换,保持原格式
|
|
||||||
output_ext = None
|
output_ext = None
|
||||||
else:
|
else:
|
||||||
parts = image_arg.rsplit(">", 1)
|
parts = image_arg.rsplit(">", 1)
|
||||||
image_arg, out_ext = parts
|
image_arg, out_ext = parts[0].strip(), parts[1].strip().lstrip(".")
|
||||||
out_ext = out_ext.strip().lstrip(".")
|
|
||||||
if out_ext.lower() not in SUPPORTED_INPUT_EXTENSIONS:
|
if out_ext.lower() not in SUPPORTED_INPUT_EXTENSIONS:
|
||||||
print(f"不支持的输出格式: .{out_ext},支持的格式: {', '.join(sorted(SUPPORTED_INPUT_EXTENSIONS))}")
|
print(f"不支持的输出格式: .{out_ext},支持的格式: {', '.join(sorted(SUPPORTED_OUTPUT_EXTENSIONS))}")
|
||||||
return
|
return
|
||||||
output_ext = f".{out_ext.lower()}"
|
output_ext = f".{out_ext.lower()}"
|
||||||
|
|
||||||
input_path = image_arg.strip()
|
input_path = image_arg
|
||||||
if not os.path.isfile(input_path):
|
if not os.path.isfile(input_path):
|
||||||
print(f"找不到输入图片: {input_path}")
|
print(f"找不到输入图片: {input_path}")
|
||||||
return
|
return
|
||||||
@@ -65,10 +76,10 @@ def main():
|
|||||||
process_single(sys.argv[1], sys.argv[2])
|
process_single(sys.argv[1], sys.argv[2])
|
||||||
return
|
return
|
||||||
|
|
||||||
print("========================================")
|
print("=" * 40)
|
||||||
print(" 图像水印工具 v1.0")
|
print(" imgwatermark - 图像水印工具 v1.0")
|
||||||
print(" 输入 /help 查看帮助")
|
print(" 输入 /help 查看帮助")
|
||||||
print("========================================")
|
print("=" * 40)
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
cmd = input("\n> ").strip()
|
cmd = input("\n> ").strip()
|
||||||
@@ -79,28 +90,29 @@ def main():
|
|||||||
if not cmd:
|
if not cmd:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if cmd == "/exit" or cmd == "exit":
|
# 处理命令前缀(支持带/或不带/)
|
||||||
|
if cmd in ("/exit", "exit"):
|
||||||
print("再见!")
|
print("再见!")
|
||||||
break
|
break
|
||||||
elif cmd == "/get":
|
elif cmd in ("/get", "get"):
|
||||||
print_stats()
|
print_stats()
|
||||||
elif cmd == "/help":
|
elif cmd in ("/help", "help"):
|
||||||
print_help()
|
print_help()
|
||||||
elif ">" in cmd:
|
elif ">" in cmd:
|
||||||
# 格式转换模式: "图片>格式 水印内容"
|
# 格式转换模式: "图片路径>.png 水印内容" 或 "图片路径>PNG 水印内容"
|
||||||
parts = cmd.split(">", 1)
|
parts = cmd.split(">", 1)
|
||||||
image_part = parts[0].strip()
|
image_part = parts[0].strip()
|
||||||
rest = parts[1].strip()
|
rest = parts[1].strip()
|
||||||
if not rest:
|
if not rest:
|
||||||
print("缺少水印内容,请重试。输入 /help 查看帮助。")
|
print("缺少水印内容,请重试。输入 /help 查看帮助。")
|
||||||
continue
|
continue
|
||||||
# 找出 ">格式 " 后面的水印文本(用 ">格式 " 分割后取第二部分)
|
# rest 中第一个空格前是格式,后面是水印文本
|
||||||
if " " in rest:
|
tokens = rest.split(None, 1)
|
||||||
final_format, text = rest.split(" ", 1)
|
if len(tokens) < 2:
|
||||||
full_arg = f"{image_part}>{final_format}"
|
|
||||||
else:
|
|
||||||
print("格式参数后缺少水印内容,请重试。输入 /help 查看帮助。")
|
print("格式参数后缺少水印内容,请重试。输入 /help 查看帮助。")
|
||||||
continue
|
continue
|
||||||
|
final_format, text = tokens
|
||||||
|
full_arg = f"{image_part}>{final_format}"
|
||||||
process_single(full_arg, text)
|
process_single(full_arg, text)
|
||||||
else:
|
else:
|
||||||
# 普通模式: "图片路径 水印内容"
|
# 普通模式: "图片路径 水印内容"
|
||||||
|
|||||||
+20
-9
@@ -1,9 +1,9 @@
|
|||||||
import os
|
import os
|
||||||
from PIL import Image, ImageDraw, ImageFont
|
from PIL import Image, ImageDraw, ImageFont
|
||||||
from config import OUTPUT_DIR, SUPPORTED_INPUT_EXTENSIONS, SUPPORTED_OUTPUT_EXTENSIONS
|
from config import OUTPUT_DIR, SUPPORTED_INPUT_EXTENSIONS, SUPPORTED_OUTPUT_EXTENSIONS, STATS_FILE
|
||||||
|
|
||||||
|
|
||||||
def load_font(size=40):
|
def load_font(size=48):
|
||||||
"""根据系统加载合适的字体文件。"""
|
"""根据系统加载合适的字体文件。"""
|
||||||
candidates = [
|
candidates = [
|
||||||
r"C:\Windows\Fonts\msyh.ttc",
|
r"C:\Windows\Fonts\msyh.ttc",
|
||||||
@@ -17,6 +17,14 @@ def load_font(size=40):
|
|||||||
return ImageFont.load_default()
|
return ImageFont.load_default()
|
||||||
|
|
||||||
|
|
||||||
|
def _strip_quotes(s):
|
||||||
|
"""去掉首尾的引号(\"、')"""
|
||||||
|
s = s.strip()
|
||||||
|
if len(s) >= 2 and s[0] == s[-1] and s[0] in ('"', "'"):
|
||||||
|
return s[1:-1]
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
def watermark_image(input_path, text, output_path=None, output_ext=None):
|
def watermark_image(input_path, text, output_path=None, output_ext=None):
|
||||||
"""
|
"""
|
||||||
给图片添加水印并保存。
|
给图片添加水印并保存。
|
||||||
@@ -31,7 +39,7 @@ def watermark_image(input_path, text, output_path=None, output_ext=None):
|
|||||||
"""
|
"""
|
||||||
img = Image.open(input_path).convert("RGBA")
|
img = Image.open(input_path).convert("RGBA")
|
||||||
|
|
||||||
# 水印图层
|
# 水印图层(右下角)
|
||||||
overlay = Image.new("RGBA", img.size, (0, 0, 0, 0))
|
overlay = Image.new("RGBA", img.size, (0, 0, 0, 0))
|
||||||
draw = ImageDraw.Draw(overlay)
|
draw = ImageDraw.Draw(overlay)
|
||||||
|
|
||||||
@@ -42,28 +50,31 @@ def watermark_image(input_path, text, output_path=None, output_ext=None):
|
|||||||
x = img.width - tw - 20
|
x = img.width - tw - 20
|
||||||
y = img.height - th - 20
|
y = img.height - th - 20
|
||||||
|
|
||||||
# 半透明背景
|
# 半透明圆角背景
|
||||||
draw.rounded_rectangle(
|
draw.rounded_rectangle(
|
||||||
[x - 8, y - 4, x + tw + 8, y + th + 4],
|
[x - 8, y - 4, x + tw + 8, y + th + 4],
|
||||||
radius=6,
|
radius=6,
|
||||||
fill=(0, 0, 0, 140),
|
fill=(0, 0, 0, 140),
|
||||||
)
|
)
|
||||||
# 文字
|
# 白色文字
|
||||||
draw.text((x, y), text, fill=(255, 255, 255, 255), font=font)
|
draw.text((x, y), text, fill=(255, 255, 255, 255), font=font)
|
||||||
|
|
||||||
# 合成
|
# 合成并转 RGB
|
||||||
result = Image.alpha_composite(img, overlay)
|
result = Image.alpha_composite(img, overlay)
|
||||||
result = result.convert("RGB")
|
result = result.convert("RGB")
|
||||||
|
|
||||||
# 确定输出路径与格式
|
# 确定输出格式
|
||||||
if output_ext is None:
|
if output_ext is None:
|
||||||
_, ext = os.path.splitext(input_path)
|
_, ext = os.path.splitext(input_path)
|
||||||
output_ext = ext.lower()
|
output_ext = ext.lower()
|
||||||
else:
|
else:
|
||||||
output_ext = output_ext.lower()
|
output_ext = output_ext.lower()
|
||||||
if output_ext not in SUPPORTED_OUTPUT_EXTENSIONS:
|
if output_ext not in SUPPORTED_OUTPUT_EXTENSIONS:
|
||||||
raise ValueError(f"不支持的输出格式: {output_ext},支持的格式: {SUPPORTED_OUTPUT_EXTENSIONS}")
|
raise ValueError(
|
||||||
|
f"不支持的输出格式: {output_ext},支持的格式: {', '.join(sorted(SUPPORTED_OUTPUT_EXTENSIONS))}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# 确定输出路径
|
||||||
if output_path is None:
|
if output_path is None:
|
||||||
base_name = os.path.basename(input_path)
|
base_name = os.path.basename(input_path)
|
||||||
name_no_ext = os.path.splitext(base_name)[0]
|
name_no_ext = os.path.splitext(base_name)[0]
|
||||||
@@ -85,7 +96,7 @@ def watermark_image(input_path, text, output_path=None, output_ext=None):
|
|||||||
|
|
||||||
|
|
||||||
def increment_count():
|
def increment_count():
|
||||||
"""已处理图片计数 +1。"""
|
"""已处理图片计数 +1,返回新总数。"""
|
||||||
count = 0
|
count = 0
|
||||||
if os.path.exists(STATS_FILE):
|
if os.path.exists(STATS_FILE):
|
||||||
with open(STATS_FILE, "r", encoding="utf-8") as f:
|
with open(STATS_FILE, "r", encoding="utf-8") as f:
|
||||||
|
|||||||
Reference in New Issue
Block a user