297 lines
9.3 KiB
Python
Executable File
297 lines
9.3 KiB
Python
Executable File
#!/usr/bin/env python3
|
||
"""截图工具 - 截取计算机桌面并保存。"""
|
||
|
||
import argparse
|
||
import os
|
||
import sys
|
||
import time
|
||
import platform
|
||
import subprocess
|
||
from datetime import datetime
|
||
|
||
# ==================== 配置常量 ====================
|
||
|
||
SCREENSHOT_DIR = os.path.expanduser("~/.aibox/screenshot")
|
||
SUPPORTED_SYSTEMS = ['Windows', 'Linux', 'Darwin']
|
||
|
||
|
||
# ==================== 辅助函数 ====================
|
||
|
||
def ensure_screenshot_dir():
|
||
"""确保截图目录存在"""
|
||
os.makedirs(SCREENSHOT_DIR, exist_ok=True)
|
||
return SCREENSHOT_DIR
|
||
|
||
|
||
def get_timestamp_filename(prefix="screenshot", extension="png"):
|
||
"""生成基于时间戳的文件名"""
|
||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||
return f"{prefix}_{timestamp}.{extension}"
|
||
|
||
|
||
def get_system():
|
||
"""获取当前操作系统"""
|
||
return platform.system()
|
||
|
||
|
||
# ==================== 各平台截图实现 ====================
|
||
|
||
def take_screenshot_windows(output_path, delay=0):
|
||
"""Windows平台截图"""
|
||
if delay > 0:
|
||
time.sleep(delay)
|
||
|
||
try:
|
||
ps_script = f'''
|
||
Add-Type -AssemblyName System.Windows.Forms
|
||
Add-Type -AssemblyName System.Drawing
|
||
|
||
$screen = [System.Windows.Forms.Screen]::PrimaryScreen
|
||
$bounds = $screen.Bounds
|
||
|
||
$bitmap = New-Object System.Drawing.Bitmap $bounds.Width, $bounds.Height
|
||
$graphics = [System.Drawing.Graphics]::FromImage($bitmap)
|
||
$graphics.CopyFromScreen($bounds.X, $bounds.Y, 0, 0, $bounds.Size)
|
||
|
||
$bitmap.Save("{output_path}", [System.Drawing.Imaging.ImageFormat]::Png)
|
||
$graphics.Dispose()
|
||
$bitmap.Dispose()
|
||
|
||
Write-Output "截图已保存: {output_path}"
|
||
'''
|
||
|
||
result = subprocess.run(
|
||
["powershell", "-Command", ps_script],
|
||
capture_output=True,
|
||
text=True,
|
||
timeout=30
|
||
)
|
||
|
||
if result.returncode == 0 and os.path.exists(output_path):
|
||
return True, f"截图成功: {output_path}"
|
||
else:
|
||
error_msg = result.stderr if result.stderr else "未知错误"
|
||
return False, f"截图失败: {error_msg}"
|
||
|
||
except subprocess.TimeoutExpired:
|
||
return False, "截图超时"
|
||
except Exception as e:
|
||
return False, f"截图错误: {str(e)}"
|
||
|
||
|
||
def take_screenshot_linux(output_path, delay=0):
|
||
"""Linux平台截图"""
|
||
if delay > 0:
|
||
time.sleep(delay)
|
||
|
||
tools = []
|
||
|
||
if subprocess.run(["which", "scrot"], capture_output=True).returncode == 0:
|
||
tools.append(("scrot", ["scrot", "-z", output_path]))
|
||
|
||
if subprocess.run(["which", "gnome-screenshot"], capture_output=True).returncode == 0:
|
||
tools.append(("gnome-screenshot", ["gnome-screenshot", "-f", output_path]))
|
||
|
||
if subprocess.run(["which", "import"], capture_output=True).returncode == 0:
|
||
tools.append(("import", ["import", "-window", "root", output_path]))
|
||
|
||
if not tools:
|
||
return False, "未找到截图工具,请安装 scrot, gnome-screenshot 或 ImageMagick"
|
||
|
||
for tool_name, cmd in tools:
|
||
try:
|
||
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
||
if result.returncode == 0 and os.path.exists(output_path):
|
||
return True, f"截图成功 (使用 {tool_name}): {output_path}"
|
||
except:
|
||
continue
|
||
|
||
return False, "所有截图工具都失败了"
|
||
|
||
|
||
def take_screenshot_macos(output_path, delay=0):
|
||
"""macOS平台截图"""
|
||
if delay > 0:
|
||
time.sleep(delay)
|
||
|
||
try:
|
||
if subprocess.run(["which", "screencapture"], capture_output=True).returncode != 0:
|
||
return False, "未找到 screencapture 命令"
|
||
|
||
cmd = ["screencapture", "-x", output_path]
|
||
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
||
|
||
if result.returncode == 0 and os.path.exists(output_path):
|
||
return True, f"截图成功: {output_path}"
|
||
else:
|
||
error_msg = result.stderr if result.stderr else "未知错误"
|
||
return False, f"截图失败: {error_msg}"
|
||
|
||
except subprocess.TimeoutExpired:
|
||
return False, "截图超时"
|
||
except Exception as e:
|
||
return False, f"截图错误: {str(e)}"
|
||
|
||
|
||
# ==================== 截图函数 ====================
|
||
|
||
def take_screenshot(output_dir=None, filename=None, delay=0):
|
||
"""截取屏幕截图"""
|
||
system = get_system()
|
||
|
||
if system not in SUPPORTED_SYSTEMS:
|
||
return False, f"不支持的操作系统: {system},支持的系统: {', '.join(SUPPORTED_SYSTEMS)}", None
|
||
|
||
if output_dir:
|
||
save_dir = output_dir
|
||
else:
|
||
save_dir = ensure_screenshot_dir()
|
||
|
||
os.makedirs(save_dir, exist_ok=True)
|
||
|
||
if filename:
|
||
filepath = os.path.join(save_dir, filename)
|
||
else:
|
||
filepath = os.path.join(save_dir, get_timestamp_filename())
|
||
|
||
if system == 'Windows':
|
||
success, message = take_screenshot_windows(filepath, delay)
|
||
elif system == 'Linux':
|
||
success, message = take_screenshot_linux(filepath, delay)
|
||
elif system == 'Darwin':
|
||
success, message = take_screenshot_macos(filepath, delay)
|
||
else:
|
||
return False, f"不支持的操作系统: {system}", None
|
||
|
||
if success:
|
||
return True, message, filepath
|
||
else:
|
||
return False, message, None
|
||
|
||
|
||
def list_recent_screenshots(limit=10):
|
||
"""列出最近的截图文件"""
|
||
save_dir = ensure_screenshot_dir()
|
||
|
||
if not os.path.exists(save_dir):
|
||
return f"截图目录不存在: {save_dir}"
|
||
|
||
screenshots = []
|
||
for f in os.listdir(save_dir):
|
||
if f.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp', '.gif')):
|
||
filepath = os.path.join(save_dir, f)
|
||
mtime = os.path.getmtime(filepath)
|
||
size = os.path.getsize(filepath)
|
||
screenshots.append((mtime, f, size))
|
||
|
||
screenshots.sort(reverse=True)
|
||
|
||
if not screenshots:
|
||
return f"截图目录中没有截图文件: {save_dir}"
|
||
|
||
result = [f"📸 最近的截图 (共 {len(screenshots)} 个):"]
|
||
for i, (mtime, fname, size) in enumerate(screenshots[:limit], 1):
|
||
dt = datetime.fromtimestamp(mtime).strftime("%Y-%m-%d %H:%M:%S")
|
||
|
||
if size < 1024:
|
||
size_str = f"{size}B"
|
||
elif size < 1024 * 1024:
|
||
size_str = f"{size/1024:.1f}KB"
|
||
else:
|
||
size_str = f"{size/1024/1024:.1f}MB"
|
||
|
||
result.append(f" {i}. {fname} - {dt} ({size_str})")
|
||
|
||
if len(screenshots) > limit:
|
||
result.append(f" ... 还有 {len(screenshots) - limit} 个文件")
|
||
|
||
return "\n".join(result)
|
||
|
||
|
||
# ==================== 命令行接口 ====================
|
||
|
||
def main():
|
||
parser = argparse.ArgumentParser(
|
||
description="截图工具 - 截取计算机桌面并保存。",
|
||
epilog="""
|
||
使用示例:
|
||
# 立即截图(自动生成文件名)
|
||
screenshot
|
||
|
||
# 3秒后截图
|
||
screenshot --delay 3
|
||
|
||
# 截图并指定文件名
|
||
screenshot --filename "my_screenshot.png"
|
||
|
||
# 截图并保存到指定目录
|
||
screenshot --output-dir "~/Desktop"
|
||
|
||
# 列出最近的截图
|
||
screenshot --list --limit 5
|
||
|
||
# 5秒后截图并保存到桌面
|
||
screenshot --delay 5 --output-dir "~/Desktop"
|
||
|
||
截图保存位置:
|
||
~/.aibox/screenshot/
|
||
自动命名格式: screenshot_YYYYMMDD_HHMMSS.png
|
||
|
||
支持的截图工具:
|
||
Linux: scrot, gnome-screenshot, ImageMagick
|
||
macOS: screencapture (系统自带)
|
||
Windows: PowerShell .NET (系统自带)
|
||
"""
|
||
)
|
||
|
||
parser.add_argument("--output-dir", "-o", help="截图保存目录(默认: ~/.aibox/screenshot/)")
|
||
parser.add_argument("--filename", "-f", help="文件名(默认: 自动生成时间戳文件名)")
|
||
parser.add_argument("--delay", "-d", type=int, default=0, help="延迟秒数(默认: 0)")
|
||
parser.add_argument("--list", "-l", action="store_true", help="列出最近的截图文件")
|
||
parser.add_argument("--limit", "-n", type=int, default=10, help="列出截图时的数量限制(默认: 10)")
|
||
|
||
args = parser.parse_args()
|
||
|
||
# 列出截图
|
||
if args.list:
|
||
print(list_recent_screenshots(args.limit))
|
||
return
|
||
|
||
# 执行截图
|
||
try:
|
||
success, message, filepath = take_screenshot(
|
||
output_dir=args.output_dir,
|
||
filename=args.filename,
|
||
delay=args.delay
|
||
)
|
||
|
||
if success:
|
||
print(f"✅ {message}")
|
||
|
||
if filepath and os.path.exists(filepath):
|
||
file_size = os.path.getsize(filepath)
|
||
if file_size < 1024:
|
||
size_str = f"{file_size}B"
|
||
elif file_size < 1024 * 1024:
|
||
size_str = f"{file_size/1024:.1f}KB"
|
||
else:
|
||
size_str = f"{file_size/1024/1024:.1f}MB"
|
||
print(f"📦 文件大小: {size_str}")
|
||
|
||
# 显示目录中的截图总数
|
||
save_dir = args.output_dir if args.output_dir else SCREENSHOT_DIR
|
||
save_dir = os.path.expanduser(save_dir)
|
||
if os.path.exists(save_dir):
|
||
screenshots = [f for f in os.listdir(save_dir) if f.lower().endswith(('.png', '.jpg', '.jpeg'))]
|
||
print(f"📁 该目录共有 {len(screenshots)} 张截图")
|
||
else:
|
||
print(f"❌ {message}")
|
||
sys.exit(1)
|
||
|
||
except Exception as e:
|
||
print(f"❌ 执行错误: {str(e)}")
|
||
sys.exit(1)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main() |