py-img-processor 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of py-img-processor might be problematic. Click here for more details.

Files changed (30) hide show
  1. py_img_processor-1.0.0/LICENSE +21 -0
  2. py_img_processor-1.0.0/MANIFEST.in +10 -0
  3. py_img_processor-1.0.0/PKG-INFO +164 -0
  4. py_img_processor-1.0.0/README.md +138 -0
  5. py_img_processor-1.0.0/imgprocessor/__init__.py +68 -0
  6. py_img_processor-1.0.0/imgprocessor/enums.py +96 -0
  7. py_img_processor-1.0.0/imgprocessor/exceptions.py +26 -0
  8. py_img_processor-1.0.0/imgprocessor/main.py +106 -0
  9. py_img_processor-1.0.0/imgprocessor/parsers/__init__.py +89 -0
  10. py_img_processor-1.0.0/imgprocessor/parsers/alpha.py +32 -0
  11. py_img_processor-1.0.0/imgprocessor/parsers/base.py +353 -0
  12. py_img_processor-1.0.0/imgprocessor/parsers/blur.py +29 -0
  13. py_img_processor-1.0.0/imgprocessor/parsers/circle.py +53 -0
  14. py_img_processor-1.0.0/imgprocessor/parsers/crop.py +100 -0
  15. py_img_processor-1.0.0/imgprocessor/parsers/gray.py +24 -0
  16. py_img_processor-1.0.0/imgprocessor/parsers/merge.py +111 -0
  17. py_img_processor-1.0.0/imgprocessor/parsers/resize.py +122 -0
  18. py_img_processor-1.0.0/imgprocessor/parsers/rotate.py +31 -0
  19. py_img_processor-1.0.0/imgprocessor/parsers/watermark.py +218 -0
  20. py_img_processor-1.0.0/imgprocessor/processor.py +128 -0
  21. py_img_processor-1.0.0/imgprocessor/utils.py +54 -0
  22. py_img_processor-1.0.0/py_img_processor.egg-info/PKG-INFO +164 -0
  23. py_img_processor-1.0.0/py_img_processor.egg-info/SOURCES.txt +28 -0
  24. py_img_processor-1.0.0/py_img_processor.egg-info/dependency_links.txt +1 -0
  25. py_img_processor-1.0.0/py_img_processor.egg-info/entry_points.txt +2 -0
  26. py_img_processor-1.0.0/py_img_processor.egg-info/not-zip-safe +1 -0
  27. py_img_processor-1.0.0/py_img_processor.egg-info/requires.txt +2 -0
  28. py_img_processor-1.0.0/py_img_processor.egg-info/top_level.txt +1 -0
  29. py_img_processor-1.0.0/setup.cfg +4 -0
  30. py_img_processor-1.0.0/setup.py +58 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Skyler Hu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,10 @@
1
+ include README.md
2
+ include LICENSE
3
+
4
+ recursive-include imgprocessor/ *
5
+ recursive-include *.md Makefile *.jpg *.png *.gif
6
+
7
+ recursive-exclude * __pycache__
8
+ recursive-exclude * *.py[co]
9
+ recursive-exclude tests *
10
+ recursive-exclude docs *
@@ -0,0 +1,164 @@
1
+ Metadata-Version: 2.1
2
+ Name: py-img-processor
3
+ Version: 1.0.0
4
+ Summary: Image editor using Python and Pillow.
5
+ Home-page: https://github.com/SkylerHu/py-img-processor.git
6
+ Author: SkylerHu
7
+ Author-email: skylerhu@qq.com
8
+ License: MIT Licence
9
+ Keywords: image,img-processor,image-processor,imgprocessor,img-editor,image-editor
10
+ Platform: any
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3 :: Only
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: Implementation :: CPython
21
+ Requires-Python: >=3.9
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: py-enum>=1.1.1
25
+ Requires-Dist: Pillow>=8
26
+
27
+ # py-img-processor
28
+
29
+ [![PyPI - Version](https://img.shields.io/pypi/v/py-img-processor)](https://github.com/SkylerHu/py-img-processor)
30
+ [![GitHub Actions Workflow Status](https://github.com/SkylerHu/py-img-processor/actions/workflows/pre-commit.yml/badge.svg?branch=master)](https://github.com/SkylerHu/py-img-processor)
31
+ [![GitHub Actions Workflow Status](https://github.com/SkylerHu/py-img-processor/actions/workflows/test-py3.yml/badge.svg?branch=master)](https://github.com/SkylerHu/py-img-processor)
32
+ [![Coveralls](https://img.shields.io/coverallsCoverage/github/SkylerHu/py-img-processor?branch=master)](https://github.com/SkylerHu/py-img-processor)
33
+ [![PyPI - Wheel](https://img.shields.io/pypi/wheel/py-img-processor)](https://github.com/SkylerHu/py-img-processor)
34
+ [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/py-img-processor)](https://github.com/SkylerHu/py-img-processor)
35
+ [![PyPI - Implementation](https://img.shields.io/pypi/implementation/py-img-processor)](https://github.com/SkylerHu/py-img-processor)
36
+ [![GitHub License](https://img.shields.io/github/license/SkylerHu/py-img-processor)](https://github.com/SkylerHu/py-img-processor)
37
+
38
+
39
+ Image editor using Python and Pillow.
40
+
41
+ 依赖Pillow开发的Python库,用于图像编辑处理。
42
+
43
+
44
+ ## 1. 安装
45
+
46
+ pip install py-img-processor
47
+
48
+ 依赖:
49
+
50
+ - `Python >= 3.9`
51
+ - `Pillow >= 8.0.0`
52
+
53
+ 可查看版本变更记录 [ChangeLog](https://github.com/SkylerHu/py-img-processor/blob/master/docs/CHANGELOG-1.x.md)
54
+
55
+ ## 2. 使用(Usage)
56
+
57
+ 具体使用说明查看 [readthedocs](https://py-img-processor.readthedocs.io) 。
58
+
59
+ ## 2.1 运行配置
60
+ 可以通过指定环境变量`PY_SETTINGS_MODULE`加载配置文件:
61
+
62
+ export PY_SETTINGS_MODULE=${your_project.settings_file.py}
63
+
64
+ 支持的配置项有:
65
+
66
+ | 配置项 | 类型 | 说明 | 默认值 |
67
+ | - | - | - | - |
68
+ | DEBUG | bool | 是否debug开发模式 | False |
69
+ | PROCESSOR_MAX_FILE_SIZE | int | 处理原图的大小限制, 单位 MB | 20 |
70
+ | PROCESSOR_MAX_W_H | int | 处理图像,原图宽高像素限制 | 30000 |
71
+ | PROCESSOR_MAX_PIXEL | int | width x height总像素3亿,处理前后的值都被此配置限制 | 300000000 |
72
+ | PROCESSOR_DEFAULT_QUALITY | int | 图像处理后的默认质量 | 75 |
73
+ | PROCESSOR_TEXT_FONT | str | 默认字体文件,默认从系统中寻找;也可以直接传递字体文件路径 | Arial Unicode.ttf |
74
+
75
+ > `注意`:`PROCESSOR_TEXT_FONT` 字体的设置是文字水印必要参数,需保证系统已安装该字体。默认值 `Arial Unicode.ttf` 是MacOS系统存在的字体,建议设置字体文件路径。
76
+
77
+ ## 2.2 图像处理
78
+ ### 处理函数
79
+ `process_image_by_path(input_path, out_path, params)`
80
+
81
+ 参数说明:
82
+
83
+ - `input_path` str,输入图像文件路径
84
+ - `out_path` str, 输出图像保存路径
85
+ - `params` str or json,图像处理参数,参数说明详见 [Reference.md](https://github.com/SkylerHu/py-img-processor/blob/master/docs/Reference.md)
86
+
87
+
88
+ ### 图像处理参数为字符串
89
+
90
+ - 斜线 `/` 隔开,区分不同的操作;
91
+ - 逗号 `,` 隔开,区分操作中不同的参数;
92
+ - 下划线 `_` 隔开,`key_value` 的形式,区分参数的Key和Value;
93
+ - `value`是复杂参数时,需要进行`base64url_encode`,是否需要encode查看文档参数详细说明;
94
+
95
+ ```python
96
+ from imgprocessor.utils import base64url_encode
97
+ from imgprocessor.processor import process_image_by_path
98
+
99
+ process_image_by_path(
100
+ "tests/imgs/lenna-400x225.jpg",
101
+ "/tmp/output.png",
102
+ # 对图片缩放、裁剪、生成圆角、并转成png存储
103
+ "resize,s_1080/crop,w_700,h_700//watermark,text_{base64url_encode('Hello 世界')}/circle,r_10/format,png",
104
+ )
105
+ ```
106
+
107
+ ### 图像处理参数为JSON
108
+ - 只是形式不同,参数和字符串形式无本质区别;
109
+ - `format`、`quality`、`interlace`三个值在JSON第一层,直接按照`key: value`的形式设置;
110
+ - 其他参数都放在 `actions` 数组中;
111
+
112
+ ```python
113
+ process_image_by_path(
114
+ "tests/imgs/lenna-400x225.jpg",
115
+ "/tmp/output.png",
116
+ {
117
+ "actions": [
118
+ {"key": "resize", "s": 1080},
119
+ {"key": "crop", "w": 700, "h": 700},
120
+ # JSON形式参数, text无需encode
121
+ {"key": "watermark", "text": "Hello 世界"},
122
+ {"key": "circle", "r": 10},
123
+ ],
124
+ "format": "png",
125
+ },
126
+ )
127
+ ```
128
+ 该操作与上述字符串示例参数等效。
129
+
130
+ ## 命令行
131
+ 安装库后 有可执行命令 `img-processor` 可以使用,通过 `img-processor -h` 查看参数说明。
132
+
133
+ ```shell
134
+ usage: img-processor [-h] [-V] -P PATH [--action ACTION [ACTION ...]] -O OUTPUT [--overwrite]
135
+
136
+ 图像处理
137
+
138
+ optional arguments:
139
+ -h, --help show this help message and exit
140
+ -V, --version show program's version number and exit
141
+ -P PATH, --path PATH 输入图像的文件路径/目录,若是目录则批量处理目录下所有图像
142
+ --action ACTION [ACTION ...]
143
+ 操作参数,可对同一个文件多组操作
144
+ -O OUTPUT, --output OUTPUT
145
+ 输出图像路径,多个图像或多个操作时请设置已存在的目录
146
+ --overwrite 是否覆盖输出路径中已有文件
147
+ ```
148
+
149
+ 示例:
150
+ ```shell
151
+ # 对单个图像进行多个操作,actions有2个参数,会输出2个图像文件
152
+ img-processor -P tests/imgs/lenna-400x225.jpg -O /tmp/ --action resize,s_300 circle,r_100 --overwrite
153
+ ```
154
+
155
+ > 注意:action参数仅支持字符串表达形式。
156
+
157
+
158
+ ## 提取图像主色调
159
+ ```python
160
+ from imgprocessor.processor import extract_main_color
161
+
162
+ extract_main_color("tests/imgs/lenna-400x225.jpg")
163
+ # 输出: "905C4C"
164
+ ```
@@ -0,0 +1,138 @@
1
+ # py-img-processor
2
+
3
+ [![PyPI - Version](https://img.shields.io/pypi/v/py-img-processor)](https://github.com/SkylerHu/py-img-processor)
4
+ [![GitHub Actions Workflow Status](https://github.com/SkylerHu/py-img-processor/actions/workflows/pre-commit.yml/badge.svg?branch=master)](https://github.com/SkylerHu/py-img-processor)
5
+ [![GitHub Actions Workflow Status](https://github.com/SkylerHu/py-img-processor/actions/workflows/test-py3.yml/badge.svg?branch=master)](https://github.com/SkylerHu/py-img-processor)
6
+ [![Coveralls](https://img.shields.io/coverallsCoverage/github/SkylerHu/py-img-processor?branch=master)](https://github.com/SkylerHu/py-img-processor)
7
+ [![PyPI - Wheel](https://img.shields.io/pypi/wheel/py-img-processor)](https://github.com/SkylerHu/py-img-processor)
8
+ [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/py-img-processor)](https://github.com/SkylerHu/py-img-processor)
9
+ [![PyPI - Implementation](https://img.shields.io/pypi/implementation/py-img-processor)](https://github.com/SkylerHu/py-img-processor)
10
+ [![GitHub License](https://img.shields.io/github/license/SkylerHu/py-img-processor)](https://github.com/SkylerHu/py-img-processor)
11
+
12
+
13
+ Image editor using Python and Pillow.
14
+
15
+ 依赖Pillow开发的Python库,用于图像编辑处理。
16
+
17
+
18
+ ## 1. 安装
19
+
20
+ pip install py-img-processor
21
+
22
+ 依赖:
23
+
24
+ - `Python >= 3.9`
25
+ - `Pillow >= 8.0.0`
26
+
27
+ 可查看版本变更记录 [ChangeLog](./docs/CHANGELOG-1.x.md)
28
+
29
+ ## 2. 使用(Usage)
30
+
31
+ 具体使用说明查看 [readthedocs](https://py-img-processor.readthedocs.io) 。
32
+
33
+ ## 2.1 运行配置
34
+ 可以通过指定环境变量`PY_SETTINGS_MODULE`加载配置文件:
35
+
36
+ export PY_SETTINGS_MODULE=${your_project.settings_file.py}
37
+
38
+ 支持的配置项有:
39
+
40
+ | 配置项 | 类型 | 说明 | 默认值 |
41
+ | - | - | - | - |
42
+ | DEBUG | bool | 是否debug开发模式 | False |
43
+ | PROCESSOR_MAX_FILE_SIZE | int | 处理原图的大小限制, 单位 MB | 20 |
44
+ | PROCESSOR_MAX_W_H | int | 处理图像,原图宽高像素限制 | 30000 |
45
+ | PROCESSOR_MAX_PIXEL | int | width x height总像素3亿,处理前后的值都被此配置限制 | 300000000 |
46
+ | PROCESSOR_DEFAULT_QUALITY | int | 图像处理后的默认质量 | 75 |
47
+ | PROCESSOR_TEXT_FONT | str | 默认字体文件,默认从系统中寻找;也可以直接传递字体文件路径 | Arial Unicode.ttf |
48
+
49
+ > `注意`:`PROCESSOR_TEXT_FONT` 字体的设置是文字水印必要参数,需保证系统已安装该字体。默认值 `Arial Unicode.ttf` 是MacOS系统存在的字体,建议设置字体文件路径。
50
+
51
+ ## 2.2 图像处理
52
+ ### 处理函数
53
+ `process_image_by_path(input_path, out_path, params)`
54
+
55
+ 参数说明:
56
+
57
+ - `input_path` str,输入图像文件路径
58
+ - `out_path` str, 输出图像保存路径
59
+ - `params` str or json,图像处理参数,参数说明详见 [Reference.md](./docs/Reference.md)
60
+
61
+
62
+ ### 图像处理参数为字符串
63
+
64
+ - 斜线 `/` 隔开,区分不同的操作;
65
+ - 逗号 `,` 隔开,区分操作中不同的参数;
66
+ - 下划线 `_` 隔开,`key_value` 的形式,区分参数的Key和Value;
67
+ - `value`是复杂参数时,需要进行`base64url_encode`,是否需要encode查看文档参数详细说明;
68
+
69
+ ```python
70
+ from imgprocessor.utils import base64url_encode
71
+ from imgprocessor.processor import process_image_by_path
72
+
73
+ process_image_by_path(
74
+ "tests/imgs/lenna-400x225.jpg",
75
+ "/tmp/output.png",
76
+ # 对图片缩放、裁剪、生成圆角、并转成png存储
77
+ "resize,s_1080/crop,w_700,h_700//watermark,text_{base64url_encode('Hello 世界')}/circle,r_10/format,png",
78
+ )
79
+ ```
80
+
81
+ ### 图像处理参数为JSON
82
+ - 只是形式不同,参数和字符串形式无本质区别;
83
+ - `format`、`quality`、`interlace`三个值在JSON第一层,直接按照`key: value`的形式设置;
84
+ - 其他参数都放在 `actions` 数组中;
85
+
86
+ ```python
87
+ process_image_by_path(
88
+ "tests/imgs/lenna-400x225.jpg",
89
+ "/tmp/output.png",
90
+ {
91
+ "actions": [
92
+ {"key": "resize", "s": 1080},
93
+ {"key": "crop", "w": 700, "h": 700},
94
+ # JSON形式参数, text无需encode
95
+ {"key": "watermark", "text": "Hello 世界"},
96
+ {"key": "circle", "r": 10},
97
+ ],
98
+ "format": "png",
99
+ },
100
+ )
101
+ ```
102
+ 该操作与上述字符串示例参数等效。
103
+
104
+ ## 命令行
105
+ 安装库后 有可执行命令 `img-processor` 可以使用,通过 `img-processor -h` 查看参数说明。
106
+
107
+ ```shell
108
+ usage: img-processor [-h] [-V] -P PATH [--action ACTION [ACTION ...]] -O OUTPUT [--overwrite]
109
+
110
+ 图像处理
111
+
112
+ optional arguments:
113
+ -h, --help show this help message and exit
114
+ -V, --version show program's version number and exit
115
+ -P PATH, --path PATH 输入图像的文件路径/目录,若是目录则批量处理目录下所有图像
116
+ --action ACTION [ACTION ...]
117
+ 操作参数,可对同一个文件多组操作
118
+ -O OUTPUT, --output OUTPUT
119
+ 输出图像路径,多个图像或多个操作时请设置已存在的目录
120
+ --overwrite 是否覆盖输出路径中已有文件
121
+ ```
122
+
123
+ 示例:
124
+ ```shell
125
+ # 对单个图像进行多个操作,actions有2个参数,会输出2个图像文件
126
+ img-processor -P tests/imgs/lenna-400x225.jpg -O /tmp/ --action resize,s_300 circle,r_100 --overwrite
127
+ ```
128
+
129
+ > 注意:action参数仅支持字符串表达形式。
130
+
131
+
132
+ ## 提取图像主色调
133
+ ```python
134
+ from imgprocessor.processor import extract_main_color
135
+
136
+ extract_main_color("tests/imgs/lenna-400x225.jpg")
137
+ # 输出: "905C4C"
138
+ ```
@@ -0,0 +1,68 @@
1
+ import typing
2
+ import os
3
+ import traceback
4
+ import importlib
5
+
6
+
7
+ __all__ = ["settings", "VERSION"]
8
+ __version__ = "1.0.0"
9
+
10
+
11
+ VERSION = __version__
12
+
13
+ _BLACK_ATTRS = ["_settings", "__dict__"]
14
+
15
+
16
+ class SettingsProxy(object):
17
+
18
+ def __init__(self) -> None:
19
+ _settings = None
20
+ # 兼容在Django项目中的使用
21
+ _settings_module = os.environ.get("PY_SETTINGS_MODULE") or os.environ.get("DJANGO_SETTINGS_MODULE")
22
+ try:
23
+ if _settings_module:
24
+ _settings = importlib.import_module(_settings_module)
25
+ except Exception:
26
+ traceback.print_exc()
27
+ print('Please set the correct "PY_SETTINGS_MODULE".')
28
+
29
+ self._settings = _settings
30
+
31
+ # 是否调试模式
32
+ DEBUG = False
33
+
34
+ # 处理原图的大小限制, 单位 MB
35
+ PROCESSOR_MAX_FILE_SIZE = 20
36
+ # 处理图像,原图宽高像素限制
37
+ PROCESSOR_MAX_W_H = 30000
38
+ # width x height总像素3亿,处理前后的值都被此配置限制
39
+ PROCESSOR_MAX_PIXEL = 300000000
40
+ # 图像处理后的默认质量
41
+ PROCESSOR_DEFAULT_QUALITY = 75
42
+ # 默认字体文件; 默认配置了MacOS系统中的字体
43
+ PROCESSOR_TEXT_FONT = "Arial Unicode.ttf"
44
+
45
+ def __getattribute__(self, attr: str) -> typing.Any:
46
+ try:
47
+ if attr in _BLACK_ATTRS:
48
+ # 白名单,内置属性直接返回
49
+ return super(SettingsProxy, self).__getattribute__(attr)
50
+
51
+ if self._settings is not None and hasattr(self._settings, attr):
52
+ value = getattr(self._settings, attr)
53
+ else:
54
+ value = super(SettingsProxy, self).__getattribute__(attr)
55
+ except AttributeError:
56
+ raise AttributeError('settings has no attribute "{}"'.format(attr))
57
+ return value
58
+
59
+ def __setattr__(self, name: str, value: typing.Any) -> None:
60
+ if name in _BLACK_ATTRS and not hasattr(self, name):
61
+ return super(SettingsProxy, self).__setattr__(name, value)
62
+ raise AttributeError("All properties of settings are not allowed to be changed.")
63
+
64
+ def __delattr__(self, name: str) -> None:
65
+ raise AttributeError("All properties of settings are not allowed to be changed.")
66
+
67
+
68
+ settings = SettingsProxy()
@@ -0,0 +1,96 @@
1
+ #!/usr/bin/env python
2
+ # coding=utf-8
3
+ from py_enum import ChoiceEnum
4
+
5
+
6
+ class ImageFormat(ChoiceEnum):
7
+ """图像转换的格式"""
8
+
9
+ JPEG = ("JPEG", "JPEG")
10
+ PNG = ("PNG", "PNG")
11
+ WEBP = ("WebP", "WebP")
12
+
13
+
14
+ class ImageOrientation(ChoiceEnum):
15
+ """
16
+ 图片EXIF中的方向枚举,第0行0列的位置(即图像正常显示右上角的位置)
17
+
18
+ see http://sylvana.net/jpegcrop/exif_orientation.html
19
+ """
20
+
21
+ TOP_LEFT = (1, "0度:正确方向,无需调整")
22
+ TOP_RIGHT = (2, "水平翻转")
23
+ BOTTOM_RIGHT = (3, "180度旋转")
24
+ BOTTOM_LEFT = (4, "水平翻转+180度旋转") # 垂直翻转
25
+ LEFT_TOP = (5, "水平翻转+顺时针270度")
26
+ RIGHT_TOP = (6, "顺时针270度")
27
+ RIGHT_BOTTOM = (7, "水平翻转+顺时针90度")
28
+ LEFT_BOTTOM = (8, "顺时针90°")
29
+
30
+
31
+ class OpAction(ChoiceEnum):
32
+ """支持的操作类型"""
33
+
34
+ # 以下几个比较特殊,在保存文件时使用
35
+ FORMAT = ("format", "格式")
36
+ QUALITY = ("quality", "质量")
37
+ INTERLACE = ("interlace", "渐进显示")
38
+ # 其他
39
+ RESIZE = ("resize", "缩放")
40
+ CROP = ("crop", "裁剪")
41
+ CIRCLE = ("circle", "圆角")
42
+ BLUR = ("blur", "模糊效果")
43
+ ROTATE = ("rotate", "旋转")
44
+ ALPHA = ("alpha", "透明度")
45
+ GRAY = ("gray", "灰度图")
46
+ WATERMARK = ("watermark", "水印")
47
+ # 特殊操作
48
+ MERGE = ("merge", "合并图像")
49
+
50
+
51
+ class ResizeMode(ChoiceEnum):
52
+ """图像缩放的模式"""
53
+
54
+ LFIT = ("lfit", "等比缩放,缩放图限制为指定w与h的矩形内的最大图片") # 类似ImageOps.contain
55
+ MFIT = ("mfit", "等比缩放,缩放图为延伸出指定w与h的矩形框外的最小图片") # 类似ImageOps.cover
56
+ FIT = ("fit", "将原图等比缩放为延伸出指定w与h的矩形框外的最小图片,然后将超出的部分进行居中裁剪") # ImageOps.fit
57
+ PAD = ("pad", "将原图缩放为指定w与h的矩形内的最大图片,然后使用指定颜色居中填充空白部分") # ImageOps.pad
58
+ FIXED = ("fixed", "固定宽高,强制缩放")
59
+
60
+
61
+ class ArgType(ChoiceEnum):
62
+ STRING = ("str", "字符串")
63
+ INTEGER = ("int", "整数")
64
+ FLOAT = ("float", "浮点数")
65
+
66
+
67
+ class Geography(ChoiceEnum):
68
+ """图像中的九宫格位置"""
69
+
70
+ NW = ("nw", "左上")
71
+ NORTH = ("north", "中上")
72
+ NE = ("ne", "右上")
73
+ WEST = ("west", "左中")
74
+ CENTER = ("center", "中部")
75
+ EAST = ("east", "右中")
76
+ SW = ("sw", "左下")
77
+ SOUTH = ("south", "中下")
78
+ SE = ("se", "右下")
79
+
80
+
81
+ class PositionOrder(ChoiceEnum):
82
+ """两个元素的前后顺序"""
83
+
84
+ BEFORE = (0, "第一输入元素在前/在上") # 图片在前
85
+ AFTER = (1, "第一个输入元素在后/在下") # 文字在前
86
+
87
+
88
+ class PositionAlign(ChoiceEnum):
89
+ """两个元素的对齐方式"""
90
+
91
+ TOP = (0, "水平上对齐")
92
+ HORIZONTAL_CENTER = (1, "水平居中对齐")
93
+ BOTTOM = (2, "水平下对齐")
94
+ LEFT = (3, "垂直左对齐")
95
+ VERTIAL_CENTER = (4, "垂直居中对齐")
96
+ RIGHT = (5, "垂直右对齐")
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env python
2
+ # coding=utf-8
3
+
4
+
5
+ class ProcessException(Exception):
6
+ """图像处理异常基类"""
7
+
8
+ pass
9
+
10
+
11
+ class ProcessLimitException(Exception):
12
+ """图像处理限制"""
13
+
14
+ pass
15
+
16
+
17
+ class ParamParseException(ProcessException):
18
+ """解析参数出现错误"""
19
+
20
+ pass
21
+
22
+
23
+ class ParamValidateException(ProcessException):
24
+ """对参数进行校验"""
25
+
26
+ pass
@@ -0,0 +1,106 @@
1
+ #!/usr/bin/env python
2
+ # coding=utf-8
3
+ import typing
4
+ import os
5
+ import sys
6
+ import argparse
7
+ import traceback
8
+
9
+ from imgprocessor import VERSION
10
+ from imgprocessor.processor import process_image_by_path
11
+
12
+
13
+ def main(argv: typing.Optional[list[str]] = None) -> int:
14
+ argv = argv if argv is not None else sys.argv[1:]
15
+ parser = argparse.ArgumentParser(
16
+ prog="img-processor",
17
+ formatter_class=argparse.RawDescriptionHelpFormatter,
18
+ description="图像处理",
19
+ )
20
+
21
+ parser.add_argument("-V", "--version", action="version", version=f"%(prog)s {VERSION}")
22
+ parser.add_argument(
23
+ "-P", "--path", type=str, required=True, help="输入图像的文件路径/目录,若是目录则批量处理目录下所有图像"
24
+ )
25
+ parser.add_argument("--action", type=str, nargs="+", help="操作参数,可对同一个文件多组操作")
26
+ parser.add_argument(
27
+ "-O", "--output", type=str, required=True, help="输出图像路径,多个图像或多个操作时请设置已存在的目录"
28
+ )
29
+ parser.add_argument("--overwrite", action="store_true", help="是否覆盖输出路径中已有文件")
30
+
31
+ args = parser.parse_args(argv)
32
+
33
+ # 输入
34
+ path = args.path
35
+ base_dir = path
36
+ # 初始化输入图像文件列表
37
+ file_paths = []
38
+ if os.path.isdir(path):
39
+ for path, dir_list, file_list in os.walk(path):
40
+ for file_name in file_list:
41
+ p = os.path.join(path, file_name)
42
+ file_paths.append(p)
43
+ else:
44
+ file_paths = [path]
45
+ base_dir = os.path.dirname(path)
46
+
47
+ total = len(file_paths)
48
+ ac_num = len(args.action)
49
+
50
+ # 输出目录
51
+ output = args.output
52
+ if (total > 1 or ac_num > 1) and not os.path.isdir(output):
53
+ print("\033[31m参数output目录不存在,请先创建\033[0m", file=sys.stderr, flush=True)
54
+ return 1
55
+ count = 0
56
+ for file_path in file_paths:
57
+ count += 1
58
+ f_tag = f"{count}/{total}\t处理 {file_path}"
59
+ print(f_tag, flush=True, end="\r")
60
+ # 相对path的相对路径
61
+ if not base_dir or base_dir in [".", "./"]:
62
+ relative_path = file_path
63
+ else:
64
+ relative_path = file_path.split(base_dir, 1)[-1]
65
+ relative_path = relative_path.strip("/")
66
+
67
+ prefix, ext = os.path.splitext(relative_path)
68
+ for idx, param_str in enumerate(args.action):
69
+ # 初始化目标文件路径
70
+ if total == 1 and ac_num == 1 and os.path.splitext(output)[-1]:
71
+ out_path = output
72
+ else:
73
+ if ac_num == 1:
74
+ target_name = relative_path
75
+ else:
76
+ target_name = f"{prefix}-{idx}.{ext}"
77
+ out_path = os.path.join(output, target_name)
78
+
79
+ tag = f"{f_tag}\t action={idx + 1}\t 保存于 {out_path}"
80
+ print(f"{tag}\t ...", flush=True, end="\r")
81
+
82
+ # 判断目标文件是否存在
83
+ if os.path.exists(out_path):
84
+ if not args.overwrite:
85
+ print(f"\033[31m{tag} 目标文件已存在\033[0m", file=sys.stderr, flush=True)
86
+ print("处理中断,可以添加参数 \033[33m--overwrite\033[0m 覆盖现有文件", file=sys.stderr, flush=True)
87
+ return 1
88
+
89
+ tag = f"{tag}\t \033[33moverwrite\033[0m"
90
+
91
+ cur_out_dir = os.path.dirname(out_path)
92
+ if not os.path.exists(cur_out_dir):
93
+ os.makedirs(cur_out_dir)
94
+ try:
95
+ process_image_by_path(file_path, out_path, param_str)
96
+ print(f"{tag}\t 成功", flush=True)
97
+ except Exception as e:
98
+ print(f"{tag}\t \033[31m失败:{e}\033[0m", file=sys.stderr, flush=True)
99
+ print(traceback.format_exc(), file=sys.stderr, flush=True)
100
+ return 1
101
+
102
+ return 0
103
+
104
+
105
+ # if __name__ == "__main__":
106
+ # raise SystemExit(main())