photoframe


Namephotoframe JSON
Version 0.1.4 PyPI version JSON
download
home_pageNone
SummaryA CLI tool for adding watermarks to photos with lossless output and Chinese font support
upload_time2025-07-27 03:33:58
maintainerNone
docs_urlNone
authorNone
requires_python>=3.12
licenseMIT
keywords cli exif image photo watermark
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Watermarker

一个基于 Python 的 CLI 工具,用于为照片添加水印并输出无损照片。支持多种模板和自动方向检测。

## 特性

- 🖼️ **多格式支持**: 支持 JPEG, PNG, TIFF, HEIC 等常见图片格式
- 🏷️ **多种模板**: 日期水印、宝宝年龄、相机参数等
- 🔄 **自动方向**: 自动检测横竖拍并调整水印位置
- 📊 **EXIF 提取**: 智能提取拍摄日期、相机信息等元数据
- 💯 **无损输出**: 保持原始图片质量和元数据
- ⚙️ **高度可定制**: 支持位置、透明度、字体大小等自定义

## 安装

本地开发使用:
```bash
git clone <repository-url>
cd watermarker
uv sync
uv run watermarker --help
```

## 使用方法

### 基础用法

```bash
# 添加日期水印
uv run watermarker add photo.jpg

# 指定输出文件
uv run watermarker add photo.jpg --output photo_with_date.jpg

# 预览模式(不保存文件)
uv run watermarker add photo.jpg --dry-run
```

### 模板选项

#### 1. 日期模板(默认)
```bash
# 基础日期水印
uv run watermarker add photo.jpg --template date

# 自定义位置和透明度
uv run watermarker add photo.jpg --template date --position bottom-left --opacity 0.6
```

#### 2. 宝宝年龄模板
```bash
# 显示宝宝年龄(需要出生日期)
uv run watermarker add photos/1.jpg --template baby --baby-birth-date 2024-01-15

# 结果示例: "2024.05.15 · 4个月3天"
```

#### 3. 相机参数模板
```bash
# 显示相机参数(类似徕卡风格)
uv run watermarker add photo.jpg --template camera

# 结果示例: "LEICA Q2 · 28mm f/1.4 ISO100 1/60s"
```

### 高级选项

```bash
# 自定义文本
uv run watermarker add photo.jpg --custom-text "我的照片"

# 调整字体大小和颜色
uv run watermarker add photo.jpg --font-size 1.5 --color white

# 设置固定边距(像素)
uv run watermarker add photo.jpg --margin 60

# 详细输出
uv run watermarker add photo.jpg --verbose
```

### 查看图片信息

```bash
# 显示图片的 EXIF 信息
uv run watermarker info photo.jpg
```

## 参数说明

| 参数 | 描述 | 默认值 |
|------|------|--------|
| `--template, -t` | 模板类型 (date/baby/camera) | date |
| `--output, -o` | 输出文件路径 | 自动生成 |
| `--position` | 水印位置 (bottom-right/bottom-left/bottom-center) | bottom-right |
| `--opacity` | 透明度 (0.0-1.0) | 0.8 |
| `--font-size` | 字体大小倍数 | 1.0 |
| `--color` | 文本颜色 | white |
| `--margin` | 固定边距像素 (10-200) | 40 |
| `--baby-birth-date` | 宝宝出生日期 (YYYY-MM-DD) | - |
| `--custom-text` | 自定义水印文本 | - |
| `--dry-run` | 预览模式,不保存文件 | false |
| `--verbose, -v` | 显示详细信息 | false |

## 支持的图片格式

- JPEG (.jpg, .jpeg)
- PNG (.png)
- TIFF (.tiff, .tif)
- BMP (.bmp)
- WebP (.webp)

## 项目结构

```
watermarker/
├── src/watermarker/
│   ├── cli.py              # CLI 接口
│   ├── core/
│   │   ├── processor.py    # 图像处理
│   │   ├── exif_reader.py  # EXIF 读取
│   │   └── utils.py        # 工具函数
│   └── templates/
│       ├── base.py         # 基础模板
│       ├── date.py         # 日期模板
│       ├── baby.py         # 宝宝年龄模板
│       └── camera.py       # 相机参数模板
├── tests/                  # 测试文件
├── DESIGN.md              # 技术设计文档
└── README.md
```

## 示例输出

### 日期模板
- 简单日期: `2024.05.15`

### 宝宝年龄模板
- 月龄显示: `2024.05.15 · 4个月3天`
- 岁数显示: `2024.05.15 · 2岁3个月`

### 相机参数模板
- 徕卡风格: `LEICA Q2 · 28mm f/1.4 ISO100 1/60s`
- 紧凑风格: `Canon EOS R5 | 85mm | f/2.8, 1/200s, ISO400`

## 开发

### 运行测试
```bash
uv run pytest
```

### 代码格式化
```bash
uv run black src/
uv run isort src/
```

## 许可证

MIT License

## 贡献

欢迎提交 Issue 和 Pull Request!

## 更新日志

### v0.1.0
- 初始版本
- 支持日期、宝宝年龄、相机参数三种模板
- 支持多种图片格式
- 无损输出功能
            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "photoframe",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.12",
    "maintainer_email": null,
    "keywords": "cli, exif, image, photo, watermark",
    "author": null,
    "author_email": "aleksichen <your-email@example.com>",
    "download_url": "https://files.pythonhosted.org/packages/a7/e7/4f007d3d89d71c75583e219ae47f604d29f37c1ae02496458490c8ad6727/photoframe-0.1.4.tar.gz",
    "platform": null,
    "description": "# Watermarker\n\n\u4e00\u4e2a\u57fa\u4e8e Python \u7684 CLI \u5de5\u5177\uff0c\u7528\u4e8e\u4e3a\u7167\u7247\u6dfb\u52a0\u6c34\u5370\u5e76\u8f93\u51fa\u65e0\u635f\u7167\u7247\u3002\u652f\u6301\u591a\u79cd\u6a21\u677f\u548c\u81ea\u52a8\u65b9\u5411\u68c0\u6d4b\u3002\n\n## \u7279\u6027\n\n- \ud83d\uddbc\ufe0f **\u591a\u683c\u5f0f\u652f\u6301**: \u652f\u6301 JPEG, PNG, TIFF, HEIC \u7b49\u5e38\u89c1\u56fe\u7247\u683c\u5f0f\n- \ud83c\udff7\ufe0f **\u591a\u79cd\u6a21\u677f**: \u65e5\u671f\u6c34\u5370\u3001\u5b9d\u5b9d\u5e74\u9f84\u3001\u76f8\u673a\u53c2\u6570\u7b49\n- \ud83d\udd04 **\u81ea\u52a8\u65b9\u5411**: \u81ea\u52a8\u68c0\u6d4b\u6a2a\u7ad6\u62cd\u5e76\u8c03\u6574\u6c34\u5370\u4f4d\u7f6e\n- \ud83d\udcca **EXIF \u63d0\u53d6**: \u667a\u80fd\u63d0\u53d6\u62cd\u6444\u65e5\u671f\u3001\u76f8\u673a\u4fe1\u606f\u7b49\u5143\u6570\u636e\n- \ud83d\udcaf **\u65e0\u635f\u8f93\u51fa**: \u4fdd\u6301\u539f\u59cb\u56fe\u7247\u8d28\u91cf\u548c\u5143\u6570\u636e\n- \u2699\ufe0f **\u9ad8\u5ea6\u53ef\u5b9a\u5236**: \u652f\u6301\u4f4d\u7f6e\u3001\u900f\u660e\u5ea6\u3001\u5b57\u4f53\u5927\u5c0f\u7b49\u81ea\u5b9a\u4e49\n\n## \u5b89\u88c5\n\n\u672c\u5730\u5f00\u53d1\u4f7f\u7528:\n```bash\ngit clone <repository-url>\ncd watermarker\nuv sync\nuv run watermarker --help\n```\n\n## \u4f7f\u7528\u65b9\u6cd5\n\n### \u57fa\u7840\u7528\u6cd5\n\n```bash\n# \u6dfb\u52a0\u65e5\u671f\u6c34\u5370\nuv run watermarker add photo.jpg\n\n# \u6307\u5b9a\u8f93\u51fa\u6587\u4ef6\nuv run watermarker add photo.jpg --output photo_with_date.jpg\n\n# \u9884\u89c8\u6a21\u5f0f\uff08\u4e0d\u4fdd\u5b58\u6587\u4ef6\uff09\nuv run watermarker add photo.jpg --dry-run\n```\n\n### \u6a21\u677f\u9009\u9879\n\n#### 1. \u65e5\u671f\u6a21\u677f\uff08\u9ed8\u8ba4\uff09\n```bash\n# \u57fa\u7840\u65e5\u671f\u6c34\u5370\nuv run watermarker add photo.jpg --template date\n\n# \u81ea\u5b9a\u4e49\u4f4d\u7f6e\u548c\u900f\u660e\u5ea6\nuv run watermarker add photo.jpg --template date --position bottom-left --opacity 0.6\n```\n\n#### 2. \u5b9d\u5b9d\u5e74\u9f84\u6a21\u677f\n```bash\n# \u663e\u793a\u5b9d\u5b9d\u5e74\u9f84\uff08\u9700\u8981\u51fa\u751f\u65e5\u671f\uff09\nuv run watermarker add photos/1.jpg --template baby --baby-birth-date 2024-01-15\n\n# \u7ed3\u679c\u793a\u4f8b: \"2024.05.15 \u00b7 4\u4e2a\u67083\u5929\"\n```\n\n#### 3. \u76f8\u673a\u53c2\u6570\u6a21\u677f\n```bash\n# \u663e\u793a\u76f8\u673a\u53c2\u6570\uff08\u7c7b\u4f3c\u5f95\u5361\u98ce\u683c\uff09\nuv run watermarker add photo.jpg --template camera\n\n# \u7ed3\u679c\u793a\u4f8b: \"LEICA Q2 \u00b7 28mm f/1.4 ISO100 1/60s\"\n```\n\n### \u9ad8\u7ea7\u9009\u9879\n\n```bash\n# \u81ea\u5b9a\u4e49\u6587\u672c\nuv run watermarker add photo.jpg --custom-text \"\u6211\u7684\u7167\u7247\"\n\n# \u8c03\u6574\u5b57\u4f53\u5927\u5c0f\u548c\u989c\u8272\nuv run watermarker add photo.jpg --font-size 1.5 --color white\n\n# \u8bbe\u7f6e\u56fa\u5b9a\u8fb9\u8ddd\uff08\u50cf\u7d20\uff09\nuv run watermarker add photo.jpg --margin 60\n\n# \u8be6\u7ec6\u8f93\u51fa\nuv run watermarker add photo.jpg --verbose\n```\n\n### \u67e5\u770b\u56fe\u7247\u4fe1\u606f\n\n```bash\n# \u663e\u793a\u56fe\u7247\u7684 EXIF \u4fe1\u606f\nuv run watermarker info photo.jpg\n```\n\n## \u53c2\u6570\u8bf4\u660e\n\n| \u53c2\u6570 | \u63cf\u8ff0 | \u9ed8\u8ba4\u503c |\n|------|------|--------|\n| `--template, -t` | \u6a21\u677f\u7c7b\u578b (date/baby/camera) | date |\n| `--output, -o` | \u8f93\u51fa\u6587\u4ef6\u8def\u5f84 | \u81ea\u52a8\u751f\u6210 |\n| `--position` | \u6c34\u5370\u4f4d\u7f6e (bottom-right/bottom-left/bottom-center) | bottom-right |\n| `--opacity` | \u900f\u660e\u5ea6 (0.0-1.0) | 0.8 |\n| `--font-size` | \u5b57\u4f53\u5927\u5c0f\u500d\u6570 | 1.0 |\n| `--color` | \u6587\u672c\u989c\u8272 | white |\n| `--margin` | \u56fa\u5b9a\u8fb9\u8ddd\u50cf\u7d20 (10-200) | 40 |\n| `--baby-birth-date` | \u5b9d\u5b9d\u51fa\u751f\u65e5\u671f (YYYY-MM-DD) | - |\n| `--custom-text` | \u81ea\u5b9a\u4e49\u6c34\u5370\u6587\u672c | - |\n| `--dry-run` | \u9884\u89c8\u6a21\u5f0f\uff0c\u4e0d\u4fdd\u5b58\u6587\u4ef6 | false |\n| `--verbose, -v` | \u663e\u793a\u8be6\u7ec6\u4fe1\u606f | false |\n\n## \u652f\u6301\u7684\u56fe\u7247\u683c\u5f0f\n\n- JPEG (.jpg, .jpeg)\n- PNG (.png)\n- TIFF (.tiff, .tif)\n- BMP (.bmp)\n- WebP (.webp)\n\n## \u9879\u76ee\u7ed3\u6784\n\n```\nwatermarker/\n\u251c\u2500\u2500 src/watermarker/\n\u2502   \u251c\u2500\u2500 cli.py              # CLI \u63a5\u53e3\n\u2502   \u251c\u2500\u2500 core/\n\u2502   \u2502   \u251c\u2500\u2500 processor.py    # \u56fe\u50cf\u5904\u7406\n\u2502   \u2502   \u251c\u2500\u2500 exif_reader.py  # EXIF \u8bfb\u53d6\n\u2502   \u2502   \u2514\u2500\u2500 utils.py        # \u5de5\u5177\u51fd\u6570\n\u2502   \u2514\u2500\u2500 templates/\n\u2502       \u251c\u2500\u2500 base.py         # \u57fa\u7840\u6a21\u677f\n\u2502       \u251c\u2500\u2500 date.py         # \u65e5\u671f\u6a21\u677f\n\u2502       \u251c\u2500\u2500 baby.py         # \u5b9d\u5b9d\u5e74\u9f84\u6a21\u677f\n\u2502       \u2514\u2500\u2500 camera.py       # \u76f8\u673a\u53c2\u6570\u6a21\u677f\n\u251c\u2500\u2500 tests/                  # \u6d4b\u8bd5\u6587\u4ef6\n\u251c\u2500\u2500 DESIGN.md              # \u6280\u672f\u8bbe\u8ba1\u6587\u6863\n\u2514\u2500\u2500 README.md\n```\n\n## \u793a\u4f8b\u8f93\u51fa\n\n### \u65e5\u671f\u6a21\u677f\n- \u7b80\u5355\u65e5\u671f: `2024.05.15`\n\n### \u5b9d\u5b9d\u5e74\u9f84\u6a21\u677f\n- \u6708\u9f84\u663e\u793a: `2024.05.15 \u00b7 4\u4e2a\u67083\u5929`\n- \u5c81\u6570\u663e\u793a: `2024.05.15 \u00b7 2\u5c813\u4e2a\u6708`\n\n### \u76f8\u673a\u53c2\u6570\u6a21\u677f\n- \u5f95\u5361\u98ce\u683c: `LEICA Q2 \u00b7 28mm f/1.4 ISO100 1/60s`\n- \u7d27\u51d1\u98ce\u683c: `Canon EOS R5 | 85mm | f/2.8, 1/200s, ISO400`\n\n## \u5f00\u53d1\n\n### \u8fd0\u884c\u6d4b\u8bd5\n```bash\nuv run pytest\n```\n\n### \u4ee3\u7801\u683c\u5f0f\u5316\n```bash\nuv run black src/\nuv run isort src/\n```\n\n## \u8bb8\u53ef\u8bc1\n\nMIT License\n\n## \u8d21\u732e\n\n\u6b22\u8fce\u63d0\u4ea4 Issue \u548c Pull Request\uff01\n\n## \u66f4\u65b0\u65e5\u5fd7\n\n### v0.1.0\n- \u521d\u59cb\u7248\u672c\n- \u652f\u6301\u65e5\u671f\u3001\u5b9d\u5b9d\u5e74\u9f84\u3001\u76f8\u673a\u53c2\u6570\u4e09\u79cd\u6a21\u677f\n- \u652f\u6301\u591a\u79cd\u56fe\u7247\u683c\u5f0f\n- \u65e0\u635f\u8f93\u51fa\u529f\u80fd",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "A CLI tool for adding watermarks to photos with lossless output and Chinese font support",
    "version": "0.1.4",
    "project_urls": {
        "Homepage": "https://github.com/aleksichen/watermarker",
        "Issues": "https://github.com/aleksichen/watermarker/issues",
        "Repository": "https://github.com/aleksichen/watermarker.git"
    },
    "split_keywords": [
        "cli",
        " exif",
        " image",
        " photo",
        " watermark"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "a70bf43cd73f62558fe49e0103b2fe093c44015f2b03f87824fb978e17e9ea8e",
                "md5": "0ca2dd29711583c32fb2fb8bc27fdf79",
                "sha256": "7506b7b8b48a5c39d4c4e784cf0d48e5d39739e23fe46033958ce87a6940b31f"
            },
            "downloads": -1,
            "filename": "photoframe-0.1.4-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "0ca2dd29711583c32fb2fb8bc27fdf79",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.12",
            "size": 23343,
            "upload_time": "2025-07-27T03:33:47",
            "upload_time_iso_8601": "2025-07-27T03:33:47.699667Z",
            "url": "https://files.pythonhosted.org/packages/a7/0b/f43cd73f62558fe49e0103b2fe093c44015f2b03f87824fb978e17e9ea8e/photoframe-0.1.4-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "a7e74f007d3d89d71c75583e219ae47f604d29f37c1ae02496458490c8ad6727",
                "md5": "a123ec9d82b44c27a1e3ab110de33ffc",
                "sha256": "6401164c75fd38b5b8d0856ab71c339a615e785bffbb0efc76ee4be3d8e308a2"
            },
            "downloads": -1,
            "filename": "photoframe-0.1.4.tar.gz",
            "has_sig": false,
            "md5_digest": "a123ec9d82b44c27a1e3ab110de33ffc",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.12",
            "size": 4408892,
            "upload_time": "2025-07-27T03:33:58",
            "upload_time_iso_8601": "2025-07-27T03:33:58.069322Z",
            "url": "https://files.pythonhosted.org/packages/a7/e7/4f007d3d89d71c75583e219ae47f604d29f37c1ae02496458490c8ad6727/photoframe-0.1.4.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-07-27 03:33:58",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "aleksichen",
    "github_project": "watermarker",
    "github_not_found": true,
    "lcname": "photoframe"
}
        
Elapsed time: 0.71628s