reykit 1.0.0__py3-none-any.whl
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.
- reykit/__init__.py +41 -0
- reykit/rall.py +33 -0
- reykit/rcomm.py +431 -0
- reykit/rdata.py +395 -0
- reykit/rdll/__init__.py +17 -0
- reykit/rdll/rdll_inject.py +41 -0
- reykit/rdll/rdll_inject_core.py +202 -0
- reykit/remail.py +276 -0
- reykit/rexception.py +339 -0
- reykit/rimage.py +261 -0
- reykit/rlog.py +1061 -0
- reykit/rmonkey.py +341 -0
- reykit/rmultitask.py +871 -0
- reykit/rnumber.py +161 -0
- reykit/ros.py +1917 -0
- reykit/rrandom.py +351 -0
- reykit/rregex.py +293 -0
- reykit/rschedule.py +272 -0
- reykit/rstdout.py +356 -0
- reykit/rsystem.py +1180 -0
- reykit/rtable.py +511 -0
- reykit/rtext.py +458 -0
- reykit/rtime.py +678 -0
- reykit/rtype.py +106 -0
- reykit/rwrap.py +613 -0
- reykit/rzip.py +137 -0
- reykit-1.0.0.dist-info/METADATA +29 -0
- reykit-1.0.0.dist-info/RECORD +30 -0
- reykit-1.0.0.dist-info/WHEEL +5 -0
- reykit-1.0.0.dist-info/top_level.txt +1 -0
reykit/rimage.py
ADDED
@@ -0,0 +1,261 @@
|
|
1
|
+
# !/usr/bin/env python
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
"""
|
5
|
+
@Time : 2023-04-22 17:27:47
|
6
|
+
@Author : Rey
|
7
|
+
@Contact : reyxbo@163.com
|
8
|
+
@Explain : Image methods.
|
9
|
+
"""
|
10
|
+
|
11
|
+
|
12
|
+
from typing import Any, Union, Optional
|
13
|
+
from io import BytesIO
|
14
|
+
from qrcode import make as qrcode_make
|
15
|
+
from qrcode.image.pil import PilImage
|
16
|
+
from PIL.Image import open as pil_open, LANCZOS
|
17
|
+
from captcha.image import ImageCaptcha
|
18
|
+
|
19
|
+
from .rexception import catch_exc
|
20
|
+
from .rmonkey import monkey_path_pil_image_get_bytes
|
21
|
+
from .ros import RFile
|
22
|
+
from .rrandom import randchar
|
23
|
+
|
24
|
+
try:
|
25
|
+
from pyzbar.pyzbar import decode as pyzbar_decode
|
26
|
+
except:
|
27
|
+
*_, pyzbar_decode, _ = catch_exc()
|
28
|
+
|
29
|
+
|
30
|
+
__all__ = (
|
31
|
+
'RImage',
|
32
|
+
'encode_qrcode',
|
33
|
+
'decode_qrcode',
|
34
|
+
'compress_image',
|
35
|
+
'to_pimage',
|
36
|
+
'generate_captcha_image'
|
37
|
+
)
|
38
|
+
|
39
|
+
|
40
|
+
# Monkey path.
|
41
|
+
monkey_image_type = monkey_path_pil_image_get_bytes()
|
42
|
+
RImage = monkey_image_type
|
43
|
+
|
44
|
+
|
45
|
+
def encode_qrcode(text: str, path: Optional[str] = None) -> bytes:
|
46
|
+
"""
|
47
|
+
Encoding text to QR code image.
|
48
|
+
|
49
|
+
Parameters
|
50
|
+
----------
|
51
|
+
text : Text.
|
52
|
+
path : File save path.
|
53
|
+
- `None`: Not save.
|
54
|
+
|
55
|
+
Returns
|
56
|
+
-------
|
57
|
+
Image bytes data.
|
58
|
+
"""
|
59
|
+
|
60
|
+
# Encode.
|
61
|
+
image: PilImage = qrcode_make(text)
|
62
|
+
|
63
|
+
# Extract.
|
64
|
+
bytes_io = BytesIO()
|
65
|
+
image.save(bytes_io, 'JPEG')
|
66
|
+
file_bytes = bytes_io.getvalue()
|
67
|
+
|
68
|
+
# Save.
|
69
|
+
if path is not None:
|
70
|
+
rfile = RFile(path)
|
71
|
+
rfile.write(file_bytes)
|
72
|
+
|
73
|
+
return file_bytes
|
74
|
+
|
75
|
+
|
76
|
+
def decode_qrcode(image: Union[str, bytes]) -> list[str]:
|
77
|
+
"""
|
78
|
+
Decoding QR code or bar code image.
|
79
|
+
|
80
|
+
Parameters
|
81
|
+
----------
|
82
|
+
image : Image bytes data or image file path.
|
83
|
+
|
84
|
+
Returns
|
85
|
+
-------
|
86
|
+
QR code or bar code text list.
|
87
|
+
"""
|
88
|
+
|
89
|
+
# Check.
|
90
|
+
if isinstance(pyzbar_decode, BaseException):
|
91
|
+
raise pyzbar_decode
|
92
|
+
|
93
|
+
# Handle parameter.
|
94
|
+
if image.__class__ in (bytes, bytearray):
|
95
|
+
image = BytesIO(image)
|
96
|
+
|
97
|
+
# Decode.
|
98
|
+
image = pil_open(image)
|
99
|
+
qrcodes_data = pyzbar_decode(image)
|
100
|
+
|
101
|
+
# Convert.
|
102
|
+
texts = [
|
103
|
+
data.data.decode()
|
104
|
+
for data in qrcodes_data
|
105
|
+
]
|
106
|
+
|
107
|
+
return texts
|
108
|
+
|
109
|
+
|
110
|
+
def compress_image(
|
111
|
+
input_image: Union[str, bytes],
|
112
|
+
ouput_image: Optional[str] = None,
|
113
|
+
target_size: float = 0.5,
|
114
|
+
rate: int = 5,
|
115
|
+
reduce: bool = False,
|
116
|
+
max_quality: int = 75,
|
117
|
+
min_quality: int = 0
|
118
|
+
) -> Optional[bytes]:
|
119
|
+
"""
|
120
|
+
Compress image file.
|
121
|
+
|
122
|
+
Parameters
|
123
|
+
----------
|
124
|
+
input_image : Input source image data.
|
125
|
+
- `str`: Source image read file path.
|
126
|
+
- `bytes`: Source image bytes data.
|
127
|
+
output_image : Output compressed image data.
|
128
|
+
- `None`: Return compressed image bytes data.
|
129
|
+
- `str`: Compressed image file save path, no return.
|
130
|
+
target_size : Compressed target size.
|
131
|
+
- `value < 1`: Not more than this size ratio.
|
132
|
+
- `value > 1`: Not more than this value, unit is KB.
|
133
|
+
rate : Compressed iteration rate of quality and resolution.
|
134
|
+
reduce : If target size is not completed, whether reduce image resolution for compression.
|
135
|
+
max_quality : Iteration start image quality rate.
|
136
|
+
min_quality : Iteration cutoff image quality rate.
|
137
|
+
|
138
|
+
Returns
|
139
|
+
-------
|
140
|
+
Compressed image bytes data.
|
141
|
+
"""
|
142
|
+
|
143
|
+
# Handle parameter.
|
144
|
+
if input_image.__class__ == str:
|
145
|
+
rfile = RFile(input_image)
|
146
|
+
input_image = rfile.str
|
147
|
+
now_size = len(input_image)
|
148
|
+
if target_size < 1:
|
149
|
+
target_size = now_size * target_size
|
150
|
+
else:
|
151
|
+
target_size *= 1024
|
152
|
+
|
153
|
+
# Read image.
|
154
|
+
bytesio = BytesIO(input_image)
|
155
|
+
image = pil_open(bytesio)
|
156
|
+
image = image.convert('RGB')
|
157
|
+
|
158
|
+
# Step compress.
|
159
|
+
quality = max_quality
|
160
|
+
while now_size > target_size and quality >= min_quality:
|
161
|
+
bytesio = BytesIO()
|
162
|
+
image.save(bytesio, 'JPEG', quality=quality)
|
163
|
+
now_size = len(bytesio.read())
|
164
|
+
quality -= rate
|
165
|
+
|
166
|
+
# Step reduce.
|
167
|
+
if reduce:
|
168
|
+
ratio = 1 - rate / 100
|
169
|
+
while now_size > target_size:
|
170
|
+
bytesio = BytesIO()
|
171
|
+
resize = image.size[0] * ratio, image.size[1] * ratio
|
172
|
+
image.thumbnail(resize, LANCZOS)
|
173
|
+
image.save(bytesio, 'JPEG', quality=min_quality)
|
174
|
+
now_size = len(bytesio.read())
|
175
|
+
ratio -= rate / 100
|
176
|
+
|
177
|
+
# Return.
|
178
|
+
content = bytesio.read()
|
179
|
+
|
180
|
+
## Return file bytes data.
|
181
|
+
if ouput_image is None:
|
182
|
+
return content
|
183
|
+
|
184
|
+
## Save file and return path.
|
185
|
+
else:
|
186
|
+
rfile = RFile(ouput_image)
|
187
|
+
rfile(content)
|
188
|
+
|
189
|
+
|
190
|
+
def to_pimage(image: Union[str, bytes]) -> RImage:
|
191
|
+
"""
|
192
|
+
Get `Image` instance of `PIL` package.
|
193
|
+
|
194
|
+
Parameters
|
195
|
+
----------
|
196
|
+
image : Image source data.
|
197
|
+
- `str`: Image file path.
|
198
|
+
- `bytes`: Image bytes data.
|
199
|
+
|
200
|
+
Returns
|
201
|
+
-------
|
202
|
+
`Image` instance.
|
203
|
+
"""
|
204
|
+
|
205
|
+
# File path.
|
206
|
+
if image.__class__ == str:
|
207
|
+
pil_image = pil_open(image)
|
208
|
+
|
209
|
+
# Bytes data.
|
210
|
+
if image.__class__ in (bytes, bytearray):
|
211
|
+
bytes_io = BytesIO(image)
|
212
|
+
pil_image = pil_open(bytes_io)
|
213
|
+
|
214
|
+
return pil_image
|
215
|
+
|
216
|
+
|
217
|
+
def generate_captcha_image(
|
218
|
+
text: Optional[Union[int, str]] = None,
|
219
|
+
path: Optional[str] = None,
|
220
|
+
**kwargs: Any
|
221
|
+
) -> bytes:
|
222
|
+
"""
|
223
|
+
Generate captcha image, based `captcha` package.
|
224
|
+
|
225
|
+
Parameters
|
226
|
+
----------
|
227
|
+
text : Text, contains digits and Uppercase letters and lowercase letters.
|
228
|
+
- `None`: Random five characters.
|
229
|
+
- `int`: Given length Random characters.
|
230
|
+
- `str`: Given characters.
|
231
|
+
path : File save path.
|
232
|
+
- `None`: Not save.
|
233
|
+
kwargs : `ImageCaptcha` Parameters.
|
234
|
+
|
235
|
+
Returns
|
236
|
+
-------
|
237
|
+
Captcha image bytes data.
|
238
|
+
"""
|
239
|
+
|
240
|
+
# Get parameter.
|
241
|
+
text = text or 5
|
242
|
+
if text.__class__ == int:
|
243
|
+
text = randchar(text, False)
|
244
|
+
|
245
|
+
# Generate.
|
246
|
+
default_kwargs = {
|
247
|
+
'width': 240,
|
248
|
+
'height': 90,
|
249
|
+
'font_sizes': (61, 75, 84)
|
250
|
+
}
|
251
|
+
default_kwargs.update(kwargs)
|
252
|
+
icaptcha = ImageCaptcha(**default_kwargs)
|
253
|
+
image: RImage = icaptcha.generate_image(text)
|
254
|
+
file_bytes = image.get_bytes()
|
255
|
+
|
256
|
+
# Save.
|
257
|
+
if path is not None:
|
258
|
+
rfile = RFile(path)
|
259
|
+
rfile.write(file_bytes)
|
260
|
+
|
261
|
+
return file_bytes
|