py-img-processor 1.0.1__tar.gz → 1.3.2__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.
Files changed (33) hide show
  1. {py_img_processor-1.0.1/py_img_processor.egg-info → py_img_processor-1.3.2}/PKG-INFO +21 -12
  2. {py_img_processor-1.0.1 → py_img_processor-1.3.2}/README.md +19 -10
  3. {py_img_processor-1.0.1 → py_img_processor-1.3.2}/imgprocessor/__init__.py +12 -1
  4. {py_img_processor-1.0.1 → py_img_processor-1.3.2}/imgprocessor/enums.py +4 -6
  5. {py_img_processor-1.0.1 → py_img_processor-1.3.2}/imgprocessor/main.py +2 -2
  6. {py_img_processor-1.0.1 → py_img_processor-1.3.2}/imgprocessor/parsers/__init__.py +24 -14
  7. {py_img_processor-1.0.1 → py_img_processor-1.3.2}/imgprocessor/parsers/alpha.py +4 -4
  8. {py_img_processor-1.0.1 → py_img_processor-1.3.2}/imgprocessor/parsers/base.py +168 -45
  9. {py_img_processor-1.0.1 → py_img_processor-1.3.2}/imgprocessor/parsers/blur.py +4 -4
  10. {py_img_processor-1.0.1 → py_img_processor-1.3.2}/imgprocessor/parsers/circle.py +4 -4
  11. {py_img_processor-1.0.1 → py_img_processor-1.3.2}/imgprocessor/parsers/crop.py +14 -14
  12. {py_img_processor-1.0.1 → py_img_processor-1.3.2}/imgprocessor/parsers/gray.py +3 -3
  13. py_img_processor-1.3.2/imgprocessor/parsers/merge.py +148 -0
  14. {py_img_processor-1.0.1 → py_img_processor-1.3.2}/imgprocessor/parsers/resize.py +36 -31
  15. {py_img_processor-1.0.1 → py_img_processor-1.3.2}/imgprocessor/parsers/rotate.py +4 -4
  16. {py_img_processor-1.0.1 → py_img_processor-1.3.2}/imgprocessor/parsers/watermark.py +51 -32
  17. py_img_processor-1.3.2/imgprocessor/processor.py +143 -0
  18. {py_img_processor-1.0.1 → py_img_processor-1.3.2/py_img_processor.egg-info}/PKG-INFO +21 -12
  19. py_img_processor-1.3.2/py_img_processor.egg-info/requires.txt +2 -0
  20. {py_img_processor-1.0.1 → py_img_processor-1.3.2}/setup.py +1 -1
  21. py_img_processor-1.0.1/imgprocessor/parsers/merge.py +0 -111
  22. py_img_processor-1.0.1/imgprocessor/processor.py +0 -128
  23. py_img_processor-1.0.1/py_img_processor.egg-info/requires.txt +0 -2
  24. {py_img_processor-1.0.1 → py_img_processor-1.3.2}/LICENSE +0 -0
  25. {py_img_processor-1.0.1 → py_img_processor-1.3.2}/MANIFEST.in +0 -0
  26. {py_img_processor-1.0.1 → py_img_processor-1.3.2}/imgprocessor/exceptions.py +0 -0
  27. {py_img_processor-1.0.1 → py_img_processor-1.3.2}/imgprocessor/utils.py +0 -0
  28. {py_img_processor-1.0.1 → py_img_processor-1.3.2}/py_img_processor.egg-info/SOURCES.txt +0 -0
  29. {py_img_processor-1.0.1 → py_img_processor-1.3.2}/py_img_processor.egg-info/dependency_links.txt +0 -0
  30. {py_img_processor-1.0.1 → py_img_processor-1.3.2}/py_img_processor.egg-info/entry_points.txt +0 -0
  31. {py_img_processor-1.0.1 → py_img_processor-1.3.2}/py_img_processor.egg-info/not-zip-safe +0 -0
  32. {py_img_processor-1.0.1 → py_img_processor-1.3.2}/py_img_processor.egg-info/top_level.txt +0 -0
  33. {py_img_processor-1.0.1 → py_img_processor-1.3.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: py-img-processor
3
- Version: 1.0.1
3
+ Version: 1.3.2
4
4
  Summary: Image editor using Python and Pillow.
5
5
  Home-page: https://github.com/SkylerHu/py-img-processor.git
6
6
  Author: SkylerHu
@@ -21,7 +21,7 @@ Classifier: Programming Language :: Python :: Implementation :: CPython
21
21
  Requires-Python: >=3.9
22
22
  Description-Content-Type: text/markdown
23
23
  License-File: LICENSE
24
- Requires-Dist: py-enum>=1.1.1
24
+ Requires-Dist: py-enum>=2.1.1
25
25
  Requires-Dist: Pillow>=8
26
26
 
27
27
  # py-img-processor
@@ -54,7 +54,7 @@ Image editor using Python and Pillow.
54
54
 
55
55
  ## 2. 使用(Usage)
56
56
 
57
- 具体使用说明查看 [readthedocs](https://py-img-processor.readthedocs.io) 。
57
+ 具体使用说明查看 [readthedocs](https://py-img-processor.readthedocs.io/) 。
58
58
 
59
59
  ## 2.1 运行配置
60
60
  可以通过指定环境变量`PY_SETTINGS_MODULE`加载配置文件:
@@ -68,9 +68,12 @@ Image editor using Python and Pillow.
68
68
  | DEBUG | bool | 是否debug开发模式 | False |
69
69
  | PROCESSOR_MAX_FILE_SIZE | int | 处理原图的大小限制, 单位 MB | 20 |
70
70
  | PROCESSOR_MAX_W_H | int | 处理图像,原图宽高像素限制 | 30000 |
71
- | PROCESSOR_MAX_PIXEL | int | width x height总像素3亿,处理前后的值都被此配置限制 | 300000000 |
71
+ | PROCESSOR_MAX_PIXEL | int | width x height总像素3亿,处理前后的值都被此配置限制,会覆盖`Image.MAX_IMAGE_PIXELS`设置 | 300000000 |
72
72
  | PROCESSOR_DEFAULT_QUALITY | int | 图像处理后的默认质量 | 75 |
73
73
  | PROCESSOR_TEXT_FONT | str | 默认字体文件,默认从系统中寻找;也可以直接传递字体文件路径 | Arial Unicode.ttf |
74
+ | PROCESSOR_WORKSPACES | tuple | 限制水印等资源路径 (startswith匹配), 默认无限制 | `()` |
75
+ | PROCESSOR_ALLOW_DOMAINS | tuple | 限制链接地址域名 (endswith匹配),默认无限制 | `()` |
76
+ | PROCESSOR_TEMP_DIR | str | tmpfile使用的临时目录,不设置默认使用系统tmp目录 | `None` |
74
77
 
75
78
  > `注意`:`PROCESSOR_TEXT_FONT` 字体的设置是文字水印必要参数,需保证系统已安装该字体。默认值 `Arial Unicode.ttf` 是MacOS系统存在的字体,建议设置字体文件路径。
76
79
 
@@ -82,13 +85,19 @@ Image editor using Python and Pillow.
82
85
 
83
86
 
84
87
  ### 处理函数
85
- `process_image_by_path(input_path, out_path, params)`
88
+ ```python
89
+ from imgprocessor.processor import process_image, process_image_obj
90
+
91
+ process_image(input_uri, params, out_path=out_path)
92
+ # 或者
93
+ process_image_obj(im, params, out_path=out_path)
94
+ ```
86
95
 
87
96
  参数说明:
88
97
 
89
- - `input_path` str,输入图像文件路径
90
- - `out_path` str, 输出图像保存路径
98
+ - `input_uri` str,输入图像文件路径或者链接地址
91
99
  - `params` str or json,图像处理参数,参数说明详见 [Reference.md](https://github.com/SkylerHu/py-img-processor/blob/master/docs/Reference.md)
100
+ - `out_path` str, 输出图像保存路径, 默认为空,为空时返回二进制内容
92
101
 
93
102
 
94
103
  ### 图像处理参数为字符串
@@ -100,13 +109,13 @@ Image editor using Python and Pillow.
100
109
 
101
110
  ```python
102
111
  from imgprocessor.utils import base64url_encode
103
- from imgprocessor.processor import process_image_by_path
112
+ from imgprocessor.processor import process_image
104
113
 
105
- process_image_by_path(
114
+ process_image(
106
115
  "docs/imgs/lenna-400x225.jpg",
107
- "/tmp/output.png",
108
116
  # 对图片缩放、裁剪、生成圆角、并转成png存储
109
117
  f"resize,s_200/crop,w_200,h_200,g_center/watermark,text_{base64url_encode('Hello 世界')},color_FFF,size_20/circle,r_10/format,png",
118
+ out_path="/tmp/output.png",
110
119
  )
111
120
  ```
112
121
 
@@ -120,9 +129,8 @@ process_image_by_path(
120
129
  - 其他参数都放在 `actions` 数组中;
121
130
 
122
131
  ```python
123
- process_image_by_path(
132
+ process_image(
124
133
  "docs/imgs/lenna-400x225.jpg",
125
- "/tmp/output.png",
126
134
  {
127
135
  "actions": [
128
136
  {"key": "resize", "s": 200},
@@ -133,6 +141,7 @@ process_image_by_path(
133
141
  ],
134
142
  "format": "png",
135
143
  },
144
+ out_path="/tmp/output.png",
136
145
  )
137
146
  ```
138
147
  该操作与上述字符串示例参数等效。
@@ -28,7 +28,7 @@ Image editor using Python and Pillow.
28
28
 
29
29
  ## 2. 使用(Usage)
30
30
 
31
- 具体使用说明查看 [readthedocs](https://py-img-processor.readthedocs.io) 。
31
+ 具体使用说明查看 [readthedocs](https://py-img-processor.readthedocs.io/) 。
32
32
 
33
33
  ## 2.1 运行配置
34
34
  可以通过指定环境变量`PY_SETTINGS_MODULE`加载配置文件:
@@ -42,9 +42,12 @@ Image editor using Python and Pillow.
42
42
  | DEBUG | bool | 是否debug开发模式 | False |
43
43
  | PROCESSOR_MAX_FILE_SIZE | int | 处理原图的大小限制, 单位 MB | 20 |
44
44
  | PROCESSOR_MAX_W_H | int | 处理图像,原图宽高像素限制 | 30000 |
45
- | PROCESSOR_MAX_PIXEL | int | width x height总像素3亿,处理前后的值都被此配置限制 | 300000000 |
45
+ | PROCESSOR_MAX_PIXEL | int | width x height总像素3亿,处理前后的值都被此配置限制,会覆盖`Image.MAX_IMAGE_PIXELS`设置 | 300000000 |
46
46
  | PROCESSOR_DEFAULT_QUALITY | int | 图像处理后的默认质量 | 75 |
47
47
  | PROCESSOR_TEXT_FONT | str | 默认字体文件,默认从系统中寻找;也可以直接传递字体文件路径 | Arial Unicode.ttf |
48
+ | PROCESSOR_WORKSPACES | tuple | 限制水印等资源路径 (startswith匹配), 默认无限制 | `()` |
49
+ | PROCESSOR_ALLOW_DOMAINS | tuple | 限制链接地址域名 (endswith匹配),默认无限制 | `()` |
50
+ | PROCESSOR_TEMP_DIR | str | tmpfile使用的临时目录,不设置默认使用系统tmp目录 | `None` |
48
51
 
49
52
  > `注意`:`PROCESSOR_TEXT_FONT` 字体的设置是文字水印必要参数,需保证系统已安装该字体。默认值 `Arial Unicode.ttf` 是MacOS系统存在的字体,建议设置字体文件路径。
50
53
 
@@ -56,13 +59,19 @@ Image editor using Python and Pillow.
56
59
 
57
60
 
58
61
  ### 处理函数
59
- `process_image_by_path(input_path, out_path, params)`
62
+ ```python
63
+ from imgprocessor.processor import process_image, process_image_obj
64
+
65
+ process_image(input_uri, params, out_path=out_path)
66
+ # 或者
67
+ process_image_obj(im, params, out_path=out_path)
68
+ ```
60
69
 
61
70
  参数说明:
62
71
 
63
- - `input_path` str,输入图像文件路径
64
- - `out_path` str, 输出图像保存路径
72
+ - `input_uri` str,输入图像文件路径或者链接地址
65
73
  - `params` str or json,图像处理参数,参数说明详见 [Reference.md](./docs/Reference.md)
74
+ - `out_path` str, 输出图像保存路径, 默认为空,为空时返回二进制内容
66
75
 
67
76
 
68
77
  ### 图像处理参数为字符串
@@ -74,13 +83,13 @@ Image editor using Python and Pillow.
74
83
 
75
84
  ```python
76
85
  from imgprocessor.utils import base64url_encode
77
- from imgprocessor.processor import process_image_by_path
86
+ from imgprocessor.processor import process_image
78
87
 
79
- process_image_by_path(
88
+ process_image(
80
89
  "docs/imgs/lenna-400x225.jpg",
81
- "/tmp/output.png",
82
90
  # 对图片缩放、裁剪、生成圆角、并转成png存储
83
91
  f"resize,s_200/crop,w_200,h_200,g_center/watermark,text_{base64url_encode('Hello 世界')},color_FFF,size_20/circle,r_10/format,png",
92
+ out_path="/tmp/output.png",
84
93
  )
85
94
  ```
86
95
 
@@ -94,9 +103,8 @@ process_image_by_path(
94
103
  - 其他参数都放在 `actions` 数组中;
95
104
 
96
105
  ```python
97
- process_image_by_path(
106
+ process_image(
98
107
  "docs/imgs/lenna-400x225.jpg",
99
- "/tmp/output.png",
100
108
  {
101
109
  "actions": [
102
110
  {"key": "resize", "s": 200},
@@ -107,6 +115,7 @@ process_image_by_path(
107
115
  ],
108
116
  "format": "png",
109
117
  },
118
+ out_path="/tmp/output.png",
110
119
  )
111
120
  ```
112
121
  该操作与上述字符串示例参数等效。
@@ -3,9 +3,11 @@ import os
3
3
  import traceback
4
4
  import importlib
5
5
 
6
+ from PIL import Image
7
+
6
8
 
7
9
  __all__ = ["settings", "VERSION"]
8
- __version__ = "1.0.1"
10
+ __version__ = "1.3.2"
9
11
 
10
12
 
11
13
  VERSION = __version__
@@ -41,6 +43,12 @@ class SettingsProxy(object):
41
43
  PROCESSOR_DEFAULT_QUALITY = 75
42
44
  # 默认字体文件; 默认配置了MacOS系统中的字体
43
45
  PROCESSOR_TEXT_FONT = "Arial Unicode.ttf"
46
+ # 工作目录列表:例如水印文件必须限制在设定的目录下,避免恶意访问文件
47
+ PROCESSOR_WORKSPACES = ()
48
+ # 当资源文件uri使用链接地址时,限制地址域名来源
49
+ PROCESSOR_ALLOW_DOMAINS = ()
50
+ # 临时文件目录
51
+ PROCESSOR_TEMP_DIR = None
44
52
 
45
53
  def __getattribute__(self, attr: str) -> typing.Any:
46
54
  try:
@@ -66,3 +74,6 @@ class SettingsProxy(object):
66
74
 
67
75
 
68
76
  settings = SettingsProxy()
77
+
78
+
79
+ Image.MAX_IMAGE_PIXELS = settings.PROCESSOR_MAX_PIXEL
@@ -31,10 +31,6 @@ class ImageOrientation(ChoiceEnum):
31
31
  class OpAction(ChoiceEnum):
32
32
  """支持的操作类型"""
33
33
 
34
- # 以下几个比较特殊,在保存文件时使用
35
- FORMAT = ("format", "格式")
36
- QUALITY = ("quality", "质量")
37
- INTERLACE = ("interlace", "渐进显示")
38
34
  # 其他
39
35
  RESIZE = ("resize", "缩放")
40
36
  CROP = ("crop", "裁剪")
@@ -51,8 +47,8 @@ class OpAction(ChoiceEnum):
51
47
  class ResizeMode(ChoiceEnum):
52
48
  """图像缩放的模式"""
53
49
 
54
- LFIT = ("lfit", "等比缩放,缩放图限制为指定w与h的矩形内的最大图片") # 类似ImageOps.contain
55
- MFIT = ("mfit", "等比缩放,缩放图为延伸出指定w与h的矩形框外的最小图片") # 类似ImageOps.cover
50
+ LFIT = ("lfit", "等比缩放,缩放图限制为指定w与h的矩形内的最大图片") # 类似 ImageOps.contain
51
+ MFIT = ("mfit", "等比缩放,缩放图为延伸出指定w与h的矩形框外的最小图片") # 类似 ImageOps.cover
56
52
  FIT = ("fit", "将原图等比缩放为延伸出指定w与h的矩形框外的最小图片,然后将超出的部分进行居中裁剪") # ImageOps.fit
57
53
  PAD = ("pad", "将原图缩放为指定w与h的矩形内的最大图片,然后使用指定颜色居中填充空白部分") # ImageOps.pad
58
54
  FIXED = ("fixed", "固定宽高,强制缩放")
@@ -62,6 +58,8 @@ class ArgType(ChoiceEnum):
62
58
  STRING = ("str", "字符串")
63
59
  INTEGER = ("int", "整数")
64
60
  FLOAT = ("float", "浮点数")
61
+ URI = ("uri", "资源路径/链接")
62
+ ACTION = ("action", "对图像的操作")
65
63
 
66
64
 
67
65
  class Geography(ChoiceEnum):
@@ -7,7 +7,7 @@ import argparse
7
7
  import traceback
8
8
 
9
9
  from imgprocessor import VERSION
10
- from imgprocessor.processor import ProcessParams, process_image_by_path
10
+ from imgprocessor.processor import ProcessParams, process_image
11
11
 
12
12
 
13
13
  def main(argv: typing.Optional[list[str]] = None) -> int:
@@ -95,7 +95,7 @@ def main(argv: typing.Optional[list[str]] = None) -> int:
95
95
  if not os.path.exists(cur_out_dir):
96
96
  os.makedirs(cur_out_dir)
97
97
  try:
98
- process_image_by_path(file_path, out_path, param_str)
98
+ process_image(file_path, param_str, out_path=out_path)
99
99
  print(f"{tag}\t 成功", flush=True)
100
100
  except Exception as e:
101
101
  print(f"{tag}\t \033[31m失败:{e}\033[0m", file=sys.stderr, flush=True)
@@ -4,7 +4,8 @@ import typing
4
4
 
5
5
  from imgprocessor import enums
6
6
  from imgprocessor.exceptions import ParamParseException
7
- from .base import BaseParser, ImgSaveParser # noqa: F401
7
+
8
+ from .base import BaseParser, ImgSaveParser
8
9
  from .resize import ResizeParser
9
10
  from .crop import CropParser
10
11
  from .circle import CircleParser
@@ -16,31 +17,39 @@ from .watermark import WatermarkParser
16
17
  from .merge import MergeParser
17
18
 
18
19
 
19
- _ACTION_PARASER_MAP: dict[str, BaseParser] = {
20
- enums.OpAction.RESIZE: ResizeParser, # type: ignore
21
- enums.OpAction.CROP: CropParser, # type: ignore
22
- enums.OpAction.CIRCLE: CircleParser, # type: ignore
23
- enums.OpAction.BLUR: BlurParser, # type: ignore
24
- enums.OpAction.ROTATE: RotateParser, # type: ignore
25
- enums.OpAction.ALPHA: AlphaParser, # type: ignore
26
- enums.OpAction.GRAY: GrayParser, # type: ignore
27
- enums.OpAction.WATERMARK: WatermarkParser, # type: ignore
28
- enums.OpAction.MERGE: MergeParser, # type: ignore
20
+ _ACTION_PARASER_MAP: dict[str, typing.Any] = {
21
+ enums.OpAction.RESIZE.value: ResizeParser,
22
+ enums.OpAction.CROP.value: CropParser,
23
+ enums.OpAction.CIRCLE.value: CircleParser,
24
+ enums.OpAction.BLUR.value: BlurParser,
25
+ enums.OpAction.ROTATE.value: RotateParser,
26
+ enums.OpAction.ALPHA.value: AlphaParser,
27
+ enums.OpAction.GRAY.value: GrayParser,
28
+ enums.OpAction.WATERMARK.value: WatermarkParser,
29
+ enums.OpAction.MERGE.value: MergeParser,
29
30
  }
30
31
 
31
32
 
32
33
  class ProcessParams(object):
33
34
  """图像处理输入参数"""
34
35
 
36
+ @classmethod
37
+ def init(cls, params: typing.Union["ProcessParams", dict, str]) -> "ProcessParams":
38
+ if isinstance(params, ProcessParams):
39
+ return params
40
+ if isinstance(params, dict):
41
+ return cls(**params)
42
+ return cls.parse_str(params)
43
+
35
44
  def __init__(
36
45
  self,
37
46
  enable_base64: bool = False,
38
47
  actions: typing.Optional[list] = None,
39
48
  **kwargs: typing.Any,
40
49
  ) -> None:
41
- self.save_parser: ImgSaveParser = ImgSaveParser.init(kwargs, enable_base64=enable_base64)
50
+ self.save_parser: ImgSaveParser = ImgSaveParser.init(kwargs, enable_base64=enable_base64) # type: ignore
42
51
 
43
- _actions = []
52
+ _actions: list[BaseParser] = []
44
53
  for i in actions or []:
45
54
  key = i.get("key")
46
55
  cls = _ACTION_PARASER_MAP.get(key)
@@ -65,6 +74,7 @@ class ProcessParams(object):
65
74
 
66
75
  save_args = [""] # 加空字符串,是为了保证解析出key
67
76
 
77
+ save_keys = list(ImgSaveParser.ARGS.keys())
68
78
  for item in value.split("/"):
69
79
  if not item:
70
80
  continue
@@ -76,7 +86,7 @@ class ProcessParams(object):
76
86
  key, param_str = info
77
87
  if not key:
78
88
  raise ParamParseException(f"参数必须指定操作类型 [{item}]不符合参数要求")
79
- if key in [enums.OpAction.FORMAT, enums.OpAction.QUALITY, enums.OpAction.INTERLACE]:
89
+ if key in save_keys:
80
90
  save_args.append(f"{key}_{param_str}")
81
91
  else:
82
92
  action_cls = _ACTION_PARASER_MAP.get(key)
@@ -2,7 +2,7 @@
2
2
  # coding=utf-8
3
3
  import typing
4
4
 
5
- from PIL import Image
5
+ from PIL import ImageFile
6
6
 
7
7
  from imgprocessor import enums
8
8
  from .base import BaseParser, pre_processing
@@ -10,10 +10,10 @@ from .base import BaseParser, pre_processing
10
10
 
11
11
  class AlphaParser(BaseParser):
12
12
 
13
- KEY = enums.OpAction.ALPHA
13
+ KEY = enums.OpAction.ALPHA.value
14
14
  ARGS = {
15
15
  # 不透明度, 为100时,完全不透明,即原图; 为0时,完全透明
16
- "value": {"type": enums.ArgType.INTEGER, "default": 100, "min": 0, "max": 100},
16
+ "value": {"type": enums.ArgType.INTEGER.value, "default": 100, "min": 0, "max": 100},
17
17
  }
18
18
 
19
19
  def __init__(
@@ -23,7 +23,7 @@ class AlphaParser(BaseParser):
23
23
  ) -> None:
24
24
  self.value = value
25
25
 
26
- def do_action(self, im: Image) -> Image:
26
+ def do_action(self, im: ImageFile.ImageFile) -> ImageFile.ImageFile:
27
27
  im = pre_processing(im, use_alpha=True)
28
28
  if self.value < 100:
29
29
  _, _, _, alpha_channel = im.split()